From 17c909ec8338870c93a4c2e6c3f4b6d601768ba7 Mon Sep 17 00:00:00 2001 From: Dean Troyer Date: Wed, 30 May 2018 16:17:12 -0700 Subject: [PATCH] StarlingX open source release updates Signed-off-by: Dean Troyer --- CONTRIBUTORS.wrs | 8 + LICENSE | 202 + README.rst | 5 + mwa-solon.map | 5 + service-mgmt-api/centos/build_srpm.data | 4 + service-mgmt-api/centos/sm-api.spec | 81 + service-mgmt-api/sm-api/LICENSE | 202 + service-mgmt-api/sm-api/scripts/sm-api | 114 + service-mgmt-api/sm-api/scripts/sm-api.conf | 14 + .../sm-api/scripts/sm-api.service | 15 + service-mgmt-api/sm-api/scripts/sm_api.ini | 10 + service-mgmt-api/sm-api/setup.py | 31 + service-mgmt-api/sm-api/sm_api/__init__.py | 10 + .../sm-api/sm_api/api/__init__.py | 27 + service-mgmt-api/sm-api/sm_api/api/acl.py | 76 + service-mgmt-api/sm-api/sm_api/api/api.ini | 5 + service-mgmt-api/sm-api/sm_api/api/api.py | 67 + service-mgmt-api/sm-api/sm_api/api/app.py | 109 + service-mgmt-api/sm-api/sm_api/api/config.py | 17 + .../sm-api/sm_api/api/controllers/__init__.py | 5 + .../sm-api/sm_api/api/controllers/root.py | 65 + .../sm_api/api/controllers/v1/__init__.py | 101 + .../sm-api/sm_api/api/controllers/v1/base.py | 55 + .../sm_api/api/controllers/v1/collection.py | 55 + .../sm-api/sm_api/api/controllers/v1/link.py | 30 + .../sm-api/sm_api/api/controllers/v1/nodes.py | 144 + .../api/controllers/v1/service_groups.py | 164 + .../sm_api/api/controllers/v1/servicenode.py | 447 +++ .../sm_api/api/controllers/v1/services.py | 144 + .../sm_api/api/controllers/v1/sm_sda.py | 162 + .../sm_api/api/controllers/v1/smc_api.py | 160 + .../sm-api/sm_api/api/controllers/v1/utils.py | 98 + service-mgmt-api/sm-api/sm_api/api/hooks.py | 98 + .../sm-api/sm_api/api/middleware/__init__.py | 19 + .../sm_api/api/middleware/auth_token.py | 34 + .../sm_api/api/middleware/parsable_error.py | 95 + .../sm-api/sm_api/cmd/__init__.py | 30 + service-mgmt-api/sm-api/sm_api/cmd/api.py | 82 + .../sm-api/sm_api/common/__init__.py | 5 + .../sm-api/sm_api/common/config.py | 34 + .../sm-api/sm_api/common/context.py | 45 + .../sm-api/sm_api/common/exception.py | 401 ++ service-mgmt-api/sm-api/sm_api/common/log.py | 77 + .../sm-api/sm_api/common/policy.py | 135 + .../sm-api/sm_api/common/safe_utils.py | 59 + .../sm-api/sm_api/common/service.py | 70 + .../sm-api/sm_api/common/utils.py | 678 ++++ service-mgmt-api/sm-api/sm_api/db/__init__.py | 10 + service-mgmt-api/sm-api/sm_api/db/api.py | 175 + .../sm-api/sm_api/db/migration.py | 49 + .../sm-api/sm_api/db/sqlalchemy/__init__.py | 0 .../sm-api/sm_api/db/sqlalchemy/api.py | 267 ++ .../db/sqlalchemy/migrate_repo/__init__.py | 0 .../db/sqlalchemy/migrate_repo/manage.py | 26 + .../db/sqlalchemy/migrate_repo/migrate.cfg | 20 + .../migrate_repo/versions/001_init.py | 74 + .../migrate_repo/versions/__init__.py | 0 .../sm-api/sm_api/db/sqlalchemy/migration.py | 116 + .../sm-api/sm_api/db/sqlalchemy/models.py | 154 + .../sm-api/sm_api/objects/__init__.py | 56 + .../sm-api/sm_api/objects/base.py | 504 +++ .../sm-api/sm_api/objects/smo_node.py | 72 + .../sm-api/sm_api/objects/smo_sda.py | 81 + .../sm-api/sm_api/objects/smo_sdm.py | 72 + .../sm-api/sm_api/objects/smo_service.py | 77 + .../sm-api/sm_api/objects/smo_servicegroup.py | 80 + .../sm-api/sm_api/objects/utils.py | 129 + .../sm-api/sm_api/openstack/__init__.py | 0 .../sm_api/openstack/common/__init__.py | 0 .../sm_api/openstack/common/cliutils.py | 67 + .../openstack/common/config/generator.py | 258 ++ .../sm-api/sm_api/openstack/common/context.py | 86 + .../sm_api/openstack/common/db/__init__.py | 20 + .../sm-api/sm_api/openstack/common/db/api.py | 110 + .../sm_api/openstack/common/db/exception.py | 58 + .../common/db/sqlalchemy/__init__.py | 20 + .../openstack/common/db/sqlalchemy/models.py | 109 + .../openstack/common/db/sqlalchemy/session.py | 700 ++++ .../openstack/common/db/sqlalchemy/utils.py | 150 + .../openstack/common/eventlet_backdoor.py | 93 + .../sm_api/openstack/common/excutils.py | 55 + .../sm_api/openstack/common/fileutils.py | 114 + .../openstack/common/fixture/__init__.py | 0 .../openstack/common/fixture/mockpatch.py | 55 + .../openstack/common/fixture/moxstubout.py | 41 + .../sm_api/openstack/common/gettextutils.py | 54 + .../sm_api/openstack/common/importutils.py | 71 + .../sm_api/openstack/common/jsonutils.py | 173 + .../sm-api/sm_api/openstack/common/local.py | 52 + .../sm_api/openstack/common/lockutils.py | 282 ++ .../sm-api/sm_api/openstack/common/log.py | 562 +++ .../sm_api/openstack/common/log_handler.py | 35 + .../sm_api/openstack/common/loopingcall.py | 151 + .../sm_api/openstack/common/network_utils.py | 73 + .../openstack/common/notifier/__init__.py | 18 + .../sm_api/openstack/common/notifier/api.py | 186 + .../openstack/common/notifier/log_notifier.py | 39 + .../common/notifier/no_op_notifier.py | 23 + .../openstack/common/notifier/rpc_notifier.py | 50 + .../common/notifier/rpc_notifier2.py | 56 + .../common/notifier/test_notifier.py | 26 + .../sm_api/openstack/common/periodic_task.py | 185 + .../sm-api/sm_api/openstack/common/policy.py | 784 ++++ .../sm_api/openstack/common/processutils.py | 251 ++ .../openstack/common/rootwrap/__init__.py | 20 + .../sm_api/openstack/common/rootwrap/cmd.py | 134 + .../openstack/common/rootwrap/filters.py | 232 ++ .../openstack/common/rootwrap/wrapper.py | 153 + .../sm_api/openstack/common/rpc/__init__.py | 311 ++ .../sm_api/openstack/common/rpc/amqp.py | 682 ++++ .../sm_api/openstack/common/rpc/common.py | 518 +++ .../sm_api/openstack/common/rpc/dispatcher.py | 182 + .../sm_api/openstack/common/rpc/impl_fake.py | 199 + .../sm_api/openstack/common/rpc/impl_kombu.py | 843 ++++ .../sm_api/openstack/common/rpc/impl_qpid.py | 654 ++++ .../sm_api/openstack/common/rpc/impl_zmq.py | 860 +++++ .../sm_api/openstack/common/rpc/matchmaker.py | 352 ++ .../openstack/common/rpc/matchmaker_redis.py | 153 + .../openstack/common/rpc/matchmaker_ring.py | 118 + .../sm_api/openstack/common/rpc/proxy.py | 227 ++ .../sm_api/openstack/common/rpc/serializer.py | 56 + .../sm_api/openstack/common/rpc/service.py | 81 + .../openstack/common/rpc/zmq_receiver.py | 45 + .../sm-api/sm_api/openstack/common/service.py | 465 +++ .../sm-api/sm_api/openstack/common/setup.py | 371 ++ .../sm_api/openstack/common/strutils.py | 222 ++ .../sm_api/openstack/common/threadgroup.py | 125 + .../sm_api/openstack/common/timeutils.py | 190 + .../sm_api/openstack/common/uuidutils.py | 43 + .../sm-api/sm_api/openstack/common/version.py | 98 + service-mgmt-client/LICENSE | 202 + service-mgmt-client/centos/build_srpm.data | 4 + service-mgmt-client/centos/sm-client.spec | 55 + service-mgmt-client/sm-client/LICENSE | 176 + service-mgmt-client/sm-client/README.rst | 5 + .../sm-client/doc/source/conf.py | 76 + .../sm-client/requirements.txt | 7 + service-mgmt-client/sm-client/setup.cfg | 34 + service-mgmt-client/sm-client/setup.py | 23 + .../sm-client/sm_client/__init__.py | 21 + .../sm-client/sm_client/client.py | 111 + .../sm-client/sm_client/common/__init__.py | 0 .../sm-client/sm_client/common/base.py | 146 + .../sm-client/sm_client/common/http.py | 302 ++ .../sm-client/sm_client/common/utils.py | 231 ++ .../sm-client/sm_client/exc.py | 166 + .../sm-client/sm_client/openstack/__init__.py | 18 + .../sm_client/openstack/common/__init__.py | 18 + .../openstack/common/config/generator.py | 258 ++ .../openstack/common/gettextutils.py | 54 + .../sm_client/openstack/common/importutils.py | 71 + .../openstack/common/rootwrap/__init__.py | 20 + .../openstack/common/rootwrap/cmd.py | 123 + .../openstack/common/rootwrap/filters.py | 232 ++ .../openstack/common/rootwrap/wrapper.py | 155 + .../sm-client/sm_client/shell.py | 277 ++ .../sm-client/sm_client/v1/__init__.py | 21 + .../sm-client/sm_client/v1/client.py | 45 + .../sm-client/sm_client/v1/iservice.py | 63 + .../sm-client/sm_client/v1/iservice_shell.py | 116 + .../sm-client/sm_client/v1/iservicegroup.py | 62 + .../sm_client/v1/iservicegroup_shell.py | 105 + .../sm-client/sm_client/v1/shell.py | 35 + .../sm-client/sm_client/v1/sm_nodes.py | 62 + .../sm-client/sm_client/v1/sm_nodes_shell.py | 51 + .../sm-client/sm_client/v1/sm_sda.py | 62 + .../sm-client/sm_client/v1/sm_sda_shell.py | 54 + .../sm-client/sm_client/v1/smservicenode.py | 62 + .../sm_client/v1/smservicenode_shell.py | 56 + .../sm-client/tools_junk/__init__.py | 0 .../tools_junk/install_venv_common.py | 216 ++ .../sm-client/tools_junk/with_venv.sh | 13 + service-mgmt-tools/centos/build_srpm.data | 4 + service-mgmt-tools/centos/sm-tools.spec | 56 + service-mgmt-tools/sm-tools/LICENSE | 202 + service-mgmt-tools/sm-tools/setup.py | 29 + .../sm-tools/sm_tools/__init__.py | 5 + .../sm-tools/sm_tools/sm_action.py | 88 + .../sm-tools/sm_tools/sm_api_msg_utils.py | 68 + .../sm-tools/sm_tools/sm_configure.py | 223 ++ .../sm-tools/sm_tools/sm_dump.py | 193 + .../sm-tools/sm_tools/sm_patch.py | 59 + .../sm-tools/sm_tools/sm_provision.py | 160 + .../sm-tools/sm_tools/sm_query.py | 61 + service-mgmt/LICENSE | 202 + service-mgmt/sm-1.0.0/LICENSE | 202 + service-mgmt/sm-1.0.0/Makefile | 14 + service-mgmt/sm-1.0.0/centos/build_srpm.data | 5 + service-mgmt/sm-1.0.0/centos/sm.spec | 98 + service-mgmt/sm-1.0.0/scripts/Makefile | 15 + service-mgmt/sm-1.0.0/scripts/sm | 155 + .../sm-1.0.0/scripts/sm-shutdown.service | 13 + service-mgmt/sm-1.0.0/scripts/sm.conf | 16 + service-mgmt/sm-1.0.0/scripts/sm.logrotate | 61 + service-mgmt/sm-1.0.0/scripts/sm.notification | 104 + service-mgmt/sm-1.0.0/scripts/sm.notify | 40 + service-mgmt/sm-1.0.0/scripts/sm.service | 16 + service-mgmt/sm-1.0.0/scripts/sm.shutdown | 40 + service-mgmt/sm-1.0.0/scripts/sm.troubleshoot | 166 + service-mgmt/sm-1.0.0/src/Makefile | 130 + service-mgmt/sm-1.0.0/src/fm_api_wrapper.c | 159 + service-mgmt/sm-1.0.0/src/fm_api_wrapper.h | 40 + service-mgmt/sm-1.0.0/src/main.c | 65 + service-mgmt/sm-1.0.0/src/service_status | 114 + service-mgmt/sm-1.0.0/src/sm_alarm.c | 770 ++++ service-mgmt/sm-1.0.0/src/sm_alarm.h | 127 + service-mgmt/sm-1.0.0/src/sm_alarm_defs.h | 132 + service-mgmt/sm-1.0.0/src/sm_alarm_thread.c | 1819 +++++++++ service-mgmt/sm-1.0.0/src/sm_alarm_thread.h | 84 + service-mgmt/sm-1.0.0/src/sm_api.c | 631 +++ service-mgmt/sm-1.0.0/src/sm_api.h | 85 + .../sm-1.0.0/src/sm_configuration_table.c | 93 + .../sm-1.0.0/src/sm_configuration_table.h | 41 + service-mgmt/sm-1.0.0/src/sm_failover.c | 1541 ++++++++ service-mgmt/sm-1.0.0/src/sm_failover.h | 143 + .../sm-1.0.0/src/sm_failover_thread.c | 244 ++ .../sm-1.0.0/src/sm_failover_thread.h | 33 + service-mgmt/sm-1.0.0/src/sm_heartbeat.c | 137 + service-mgmt/sm-1.0.0/src/sm_heartbeat.h | 82 + service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.c | 1333 +++++++ service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.h | 90 + .../sm-1.0.0/src/sm_heartbeat_thread.c | 1363 +++++++ .../sm-1.0.0/src/sm_heartbeat_thread.h | 91 + service-mgmt/sm-1.0.0/src/sm_log.c | 517 +++ service-mgmt/sm-1.0.0/src/sm_log.h | 96 + service-mgmt/sm-1.0.0/src/sm_log_defs.h | 65 + service-mgmt/sm-1.0.0/src/sm_log_thread.c | 933 +++++ service-mgmt/sm-1.0.0/src/sm_log_thread.h | 85 + .../sm-1.0.0/src/sm_main_event_handler.c | 480 +++ .../sm-1.0.0/src/sm_main_event_handler.h | 37 + service-mgmt/sm-1.0.0/src/sm_msg.c | 3387 +++++++++++++++++ service-mgmt/sm-1.0.0/src/sm_msg.h | 264 ++ service-mgmt/sm-1.0.0/src/sm_node_api.cpp | 1108 ++++++ service-mgmt/sm-1.0.0/src/sm_node_api.h | 90 + .../sm-1.0.0/src/sm_node_disabled_state.c | 131 + .../sm-1.0.0/src/sm_node_disabled_state.h | 59 + .../sm-1.0.0/src/sm_node_enabled_state.c | 134 + .../sm-1.0.0/src/sm_node_enabled_state.h | 59 + service-mgmt/sm-1.0.0/src/sm_node_fsm.c | 515 +++ service-mgmt/sm-1.0.0/src/sm_node_fsm.h | 60 + .../sm-1.0.0/src/sm_node_swact_monitor.cpp | 58 + .../sm-1.0.0/src/sm_node_swact_monitor.h | 22 + .../sm-1.0.0/src/sm_node_unknown_state.c | 144 + .../sm-1.0.0/src/sm_node_unknown_state.h | 59 + service-mgmt/sm-1.0.0/src/sm_notify_api.c | 270 ++ service-mgmt/sm-1.0.0/src/sm_notify_api.h | 61 + service-mgmt/sm-1.0.0/src/sm_process.c | 854 +++++ service-mgmt/sm-1.0.0/src/sm_process.h | 27 + service-mgmt/sm-1.0.0/src/sm_process_death.c | 425 +++ service-mgmt/sm-1.0.0/src/sm_process_death.h | 65 + service-mgmt/sm-1.0.0/src/sm_service_action.c | 909 +++++ service-mgmt/sm-1.0.0/src/sm_service_action.h | 79 + .../src/sm_service_action_result_table.c | 195 + .../src/sm_service_action_result_table.h | 60 + .../sm-1.0.0/src/sm_service_action_table.c | 255 ++ .../sm-1.0.0/src/sm_service_action_table.h | 81 + service-mgmt/sm-1.0.0/src/sm_service_api.c | 481 +++ service-mgmt/sm-1.0.0/src/sm_service_api.h | 90 + service-mgmt/sm-1.0.0/src/sm_service_audit.c | 594 +++ service-mgmt/sm-1.0.0/src/sm_service_audit.h | 96 + .../sm-1.0.0/src/sm_service_dependency.c | 510 +++ .../sm-1.0.0/src/sm_service_dependency.h | 88 + .../src/sm_service_dependency_table.c | 262 ++ .../src/sm_service_dependency_table.h | 78 + .../sm-1.0.0/src/sm_service_disable.c | 471 +++ .../sm-1.0.0/src/sm_service_disable.h | 52 + .../sm-1.0.0/src/sm_service_disabled_state.c | 338 ++ .../sm-1.0.0/src/sm_service_disabled_state.h | 59 + .../sm-1.0.0/src/sm_service_disabling_state.c | 303 ++ .../sm-1.0.0/src/sm_service_disabling_state.h | 59 + .../sm-1.0.0/src/sm_service_domain_api.c | 322 ++ .../sm-1.0.0/src/sm_service_domain_api.h | 53 + .../src/sm_service_domain_assignment_table.c | 642 ++++ .../src/sm_service_domain_assignment_table.h | 188 + .../src/sm_service_domain_backup_state.c | 218 ++ .../src/sm_service_domain_backup_state.h | 60 + .../sm-1.0.0/src/sm_service_domain_filter.c | 1011 +++++ .../sm-1.0.0/src/sm_service_domain_filter.h | 60 + .../sm-1.0.0/src/sm_service_domain_fsm.c | 754 ++++ .../sm-1.0.0/src/sm_service_domain_fsm.h | 52 + .../src/sm_service_domain_initial_state.c | 225 ++ .../src/sm_service_domain_initial_state.h | 60 + .../src/sm_service_domain_interface_api.c | 412 ++ .../src/sm_service_domain_interface_api.h | 49 + ..._service_domain_interface_disabled_state.c | 164 + ..._service_domain_interface_disabled_state.h | 61 + ...m_service_domain_interface_enabled_state.c | 286 ++ ...m_service_domain_interface_enabled_state.h | 61 + .../src/sm_service_domain_interface_fsm.c | 691 ++++ .../src/sm_service_domain_interface_fsm.h | 65 + ...ervice_domain_interface_not_in_use_state.c | 97 + ...ervice_domain_interface_not_in_use_state.h | 61 + .../src/sm_service_domain_interface_table.c | 325 ++ .../src/sm_service_domain_interface_table.h | 104 + ...m_service_domain_interface_unknown_state.c | 227 ++ ...m_service_domain_interface_unknown_state.h | 61 + .../src/sm_service_domain_leader_state.c | 218 ++ .../src/sm_service_domain_leader_state.h | 61 + .../src/sm_service_domain_member_table.c | 308 ++ .../src/sm_service_domain_member_table.h | 100 + .../sm_service_domain_neighbor_down_state.c | 128 + .../sm_service_domain_neighbor_down_state.h | 62 + ...ice_domain_neighbor_exchange_start_state.c | 344 ++ ...ice_domain_neighbor_exchange_start_state.h | 63 + ...m_service_domain_neighbor_exchange_state.c | 559 +++ ...m_service_domain_neighbor_exchange_state.h | 62 + .../src/sm_service_domain_neighbor_fsm.c | 1135 ++++++ .../src/sm_service_domain_neighbor_fsm.h | 93 + .../sm_service_domain_neighbor_full_state.c | 166 + .../sm_service_domain_neighbor_full_state.h | 62 + .../src/sm_service_domain_neighbor_table.c | 373 ++ .../src/sm_service_domain_neighbor_table.h | 105 + .../src/sm_service_domain_other_state.c | 127 + .../src/sm_service_domain_other_state.h | 60 + .../src/sm_service_domain_scheduler.c | 1993 ++++++++++ .../src/sm_service_domain_scheduler.h | 51 + .../sm-1.0.0/src/sm_service_domain_table.c | 266 ++ .../sm-1.0.0/src/sm_service_domain_table.h | 89 + .../sm-1.0.0/src/sm_service_domain_utils.c | 1079 ++++++ .../sm-1.0.0/src/sm_service_domain_utils.h | 162 + .../src/sm_service_domain_waiting_state.c | 316 ++ .../src/sm_service_domain_waiting_state.h | 60 + .../sm-1.0.0/src/sm_service_domain_weight.c | 225 ++ .../sm-1.0.0/src/sm_service_domain_weight.h | 38 + service-mgmt/sm-1.0.0/src/sm_service_enable.c | 731 ++++ service-mgmt/sm-1.0.0/src/sm_service_enable.h | 68 + .../src/sm_service_enabled_active_state.c | 398 ++ .../src/sm_service_enabled_active_state.h | 59 + .../src/sm_service_enabled_go_active_state.c | 275 ++ .../src/sm_service_enabled_go_active_state.h | 61 + .../src/sm_service_enabled_go_standby_state.c | 350 ++ .../src/sm_service_enabled_go_standby_state.h | 61 + .../src/sm_service_enabled_standby_state.c | 396 ++ .../src/sm_service_enabled_standby_state.h | 59 + .../sm-1.0.0/src/sm_service_enabling_state.c | 290 ++ .../sm-1.0.0/src/sm_service_enabling_state.h | 59 + .../src/sm_service_enabling_throttle_state.c | 247 ++ .../src/sm_service_enabling_throttle_state.h | 59 + service-mgmt/sm-1.0.0/src/sm_service_engine.c | 532 +++ service-mgmt/sm-1.0.0/src/sm_service_engine.h | 38 + service-mgmt/sm-1.0.0/src/sm_service_fsm.c | 2014 ++++++++++ service-mgmt/sm-1.0.0/src/sm_service_fsm.h | 104 + .../sm-1.0.0/src/sm_service_go_active.c | 465 +++ .../sm-1.0.0/src/sm_service_go_active.h | 52 + .../sm-1.0.0/src/sm_service_go_standby.c | 463 +++ .../sm-1.0.0/src/sm_service_go_standby.h | 52 + .../src/sm_service_group_active_state.c | 181 + .../src/sm_service_group_active_state.h | 62 + .../sm-1.0.0/src/sm_service_group_api.c | 331 ++ .../sm-1.0.0/src/sm_service_group_api.h | 75 + .../sm-1.0.0/src/sm_service_group_audit.c | 498 +++ .../sm-1.0.0/src/sm_service_group_audit.h | 41 + .../sm-1.0.0/src/sm_service_group_disable.c | 123 + .../sm-1.0.0/src/sm_service_group_disable.h | 45 + .../src/sm_service_group_disabled_state.c | 181 + .../src/sm_service_group_disabled_state.h | 62 + .../src/sm_service_group_disabling_state.c | 197 + .../src/sm_service_group_disabling_state.h | 62 + .../sm-1.0.0/src/sm_service_group_enable.c | 120 + .../sm-1.0.0/src/sm_service_group_enable.h | 45 + .../sm-1.0.0/src/sm_service_group_engine.c | 299 ++ .../sm-1.0.0/src/sm_service_group_engine.h | 39 + .../sm-1.0.0/src/sm_service_group_fsm.c | 1290 +++++++ .../sm-1.0.0/src/sm_service_group_fsm.h | 78 + .../sm-1.0.0/src/sm_service_group_go_active.c | 123 + .../sm-1.0.0/src/sm_service_group_go_active.h | 45 + .../src/sm_service_group_go_active_state.c | 198 + .../src/sm_service_group_go_active_state.h | 62 + .../src/sm_service_group_go_standby.c | 127 + .../src/sm_service_group_go_standby.h | 45 + .../src/sm_service_group_go_standby_state.c | 198 + .../src/sm_service_group_go_standby_state.h | 62 + .../sm-1.0.0/src/sm_service_group_health.c | 28 + .../sm-1.0.0/src/sm_service_group_health.h | 26 + .../src/sm_service_group_initial_state.c | 121 + .../src/sm_service_group_initial_state.h | 62 + .../src/sm_service_group_member_table.c | 300 ++ .../src/sm_service_group_member_table.h | 98 + .../src/sm_service_group_notification.c | 817 ++++ .../src/sm_service_group_notification.h | 47 + .../src/sm_service_group_shutdown_state.c | 102 + .../src/sm_service_group_shutdown_state.h | 62 + .../src/sm_service_group_standby_state.c | 182 + .../src/sm_service_group_standby_state.h | 62 + .../sm-1.0.0/src/sm_service_group_table.c | 280 ++ .../sm-1.0.0/src/sm_service_group_table.h | 101 + .../sm-1.0.0/src/sm_service_heartbeat.c | 570 +++ .../sm-1.0.0/src/sm_service_heartbeat.h | 31 + .../sm-1.0.0/src/sm_service_heartbeat_api.c | 488 +++ .../sm-1.0.0/src/sm_service_heartbeat_api.h | 100 + .../src/sm_service_heartbeat_thread.c | 290 ++ .../src/sm_service_heartbeat_thread.h | 33 + .../sm-1.0.0/src/sm_service_initial_state.c | 105 + .../sm-1.0.0/src/sm_service_initial_state.h | 59 + .../sm-1.0.0/src/sm_service_shutdown_state.c | 77 + .../sm-1.0.0/src/sm_service_shutdown_state.h | 59 + service-mgmt/sm-1.0.0/src/sm_service_table.c | 406 ++ service-mgmt/sm-1.0.0/src/sm_service_table.h | 123 + .../sm-1.0.0/src/sm_service_unknown_state.c | 218 ++ .../sm-1.0.0/src/sm_service_unknown_state.h | 59 + service-mgmt/sm-1.0.0/src/sm_swact_state.c | 28 + service-mgmt/sm-1.0.0/src/sm_swact_state.h | 35 + .../sm-1.0.0/src/sm_task_affining_thread.c | 232 ++ .../sm-1.0.0/src/sm_task_affining_thread.h | 31 + service-mgmt/sm-1.0.0/src/sm_troubleshoot.c | 153 + service-mgmt/sm-1.0.0/src/sm_troubleshoot.h | 26 + service-mgmt/sm-common-1.0.0/LICENSE | 202 + service-mgmt/sm-common-1.0.0/Makefile | 14 + .../sm-common-1.0.0/centos/build_srpm.data | 2 + .../sm-common-1.0.0/centos/sm-common.spec | 168 + service-mgmt/sm-common-1.0.0/scripts/Makefile | 8 + service-mgmt/sm-common-1.0.0/scripts/sm-eru | 131 + .../sm-common-1.0.0/scripts/sm-eru.conf | 15 + .../sm-common-1.0.0/scripts/sm-eru.service | 15 + .../sm-common-1.0.0/scripts/sm-watchdog | 131 + .../sm-common-1.0.0/scripts/sm-watchdog.conf | 15 + .../scripts/sm-watchdog.service | 15 + service-mgmt/sm-common-1.0.0/src/Makefile | 83 + service-mgmt/sm-common-1.0.0/src/sm_debug.c | 409 ++ service-mgmt/sm-common-1.0.0/src/sm_debug.h | 131 + .../sm-common-1.0.0/src/sm_debug_thread.c | 340 ++ .../sm-common-1.0.0/src/sm_debug_thread.h | 59 + service-mgmt/sm-common-1.0.0/src/sm_eru_db.c | 618 +++ service-mgmt/sm-common-1.0.0/src/sm_eru_db.h | 101 + .../sm-common-1.0.0/src/sm_eru_dump.c | 321 ++ .../sm-common-1.0.0/src/sm_eru_main.c | 49 + .../sm-common-1.0.0/src/sm_eru_process.c | 570 +++ .../sm-common-1.0.0/src/sm_eru_process.h | 25 + service-mgmt/sm-common-1.0.0/src/sm_hw.c | 822 ++++ service-mgmt/sm-common-1.0.0/src/sm_hw.h | 133 + service-mgmt/sm-common-1.0.0/src/sm_limits.h | 181 + service-mgmt/sm-common-1.0.0/src/sm_list.h | 147 + service-mgmt/sm-common-1.0.0/src/sm_netlink.c | 436 +++ service-mgmt/sm-common-1.0.0/src/sm_netlink.h | 77 + .../sm-common-1.0.0/src/sm_node_stats.c | 445 +++ .../sm-common-1.0.0/src/sm_node_stats.h | 180 + .../sm-common-1.0.0/src/sm_node_utils.c | 545 +++ .../sm-common-1.0.0/src/sm_node_utils.h | 111 + service-mgmt/sm-common-1.0.0/src/sm_selobj.c | 325 ++ service-mgmt/sm-common-1.0.0/src/sm_selobj.h | 56 + service-mgmt/sm-common-1.0.0/src/sm_sha512.c | 289 ++ service-mgmt/sm-common-1.0.0/src/sm_sha512.h | 67 + .../sm-common-1.0.0/src/sm_thread_health.c | 230 ++ .../sm-common-1.0.0/src/sm_thread_health.h | 58 + service-mgmt/sm-common-1.0.0/src/sm_time.c | 110 + service-mgmt/sm-common-1.0.0/src/sm_time.h | 62 + service-mgmt/sm-common-1.0.0/src/sm_timer.c | 646 ++++ service-mgmt/sm-common-1.0.0/src/sm_timer.h | 74 + service-mgmt/sm-common-1.0.0/src/sm_trap.c | 332 ++ service-mgmt/sm-common-1.0.0/src/sm_trap.h | 37 + .../sm-common-1.0.0/src/sm_trap_thread.c | 848 +++++ .../sm-common-1.0.0/src/sm_trap_thread.h | 58 + service-mgmt/sm-common-1.0.0/src/sm_types.c | 1824 +++++++++ service-mgmt/sm-common-1.0.0/src/sm_types.h | 1252 ++++++ .../sm-common-1.0.0/src/sm_util_types.c | 27 + .../sm-common-1.0.0/src/sm_util_types.h | 20 + service-mgmt/sm-common-1.0.0/src/sm_utils.c | 203 + service-mgmt/sm-common-1.0.0/src/sm_utils.h | 69 + service-mgmt/sm-common-1.0.0/src/sm_uuid.c | 43 + service-mgmt/sm-common-1.0.0/src/sm_uuid.h | 42 + .../sm-common-1.0.0/src/sm_watchdog_main.c | 49 + .../sm-common-1.0.0/src/sm_watchdog_module.c | 247 ++ .../sm-common-1.0.0/src/sm_watchdog_module.h | 31 + .../sm-common-1.0.0/src/sm_watchdog_nfs.c | 608 +++ .../sm-common-1.0.0/src/sm_watchdog_nfs.h | 37 + .../sm-common-1.0.0/src/sm_watchdog_process.c | 241 ++ .../sm-common-1.0.0/src/sm_watchdog_process.h | 25 + service-mgmt/sm-db-1.0.0/LICENSE | 202 + service-mgmt/sm-db-1.0.0/Makefile | 14 + .../sm-db-1.0.0/centos/build_srpm.data | 5 + service-mgmt/sm-db-1.0.0/centos/sm-db.spec | 95 + service-mgmt/sm-db-1.0.0/database/Makefile | 7 + service-mgmt/sm-db-1.0.0/database/README | 11 + .../sm-db-1.0.0/database/create_sm_db.sql | 971 +++++ .../sm-db-1.0.0/database/create_sm_hb_db.sql | 4 + .../sm-db-1.0.0/database/sm-patch.sql | 1 + .../sm-db-1.0.0/database/sm_database.xlsb | Bin 0 -> 122233 bytes .../patches/sm_db_ceph_install.patch | 31 + .../patches/sm_db_cinder_lvm_install.patch | 60 + .../patches/sm_db_pxeboot_install.patch | 17 + .../sm-db-1.0.0/scripts/sm-db-populate.script | 47 + service-mgmt/sm-db-1.0.0/src/Makefile | 62 + service-mgmt/sm-db-1.0.0/src/sm_db.c | 1131 ++++++ service-mgmt/sm-db-1.0.0/src/sm_db.h | 112 + service-mgmt/sm-db-1.0.0/src/sm_db_build.c | 75 + .../sm-db-1.0.0/src/sm_db_configuration.c | 68 + .../sm-db-1.0.0/src/sm_db_configuration.h | 53 + service-mgmt/sm-db-1.0.0/src/sm_db_foreach.c | 79 + service-mgmt/sm-db-1.0.0/src/sm_db_foreach.h | 34 + service-mgmt/sm-db-1.0.0/src/sm_db_iterator.c | 192 + service-mgmt/sm-db-1.0.0/src/sm_db_iterator.h | 67 + .../sm-db-1.0.0/src/sm_db_node_history.c | 328 ++ .../sm-db-1.0.0/src/sm_db_node_history.h | 104 + service-mgmt/sm-db-1.0.0/src/sm_db_nodes.c | 437 +++ service-mgmt/sm-db-1.0.0/src/sm_db_nodes.h | 116 + .../src/sm_db_service_action_results.c | 408 ++ .../src/sm_db_service_action_results.h | 106 + .../sm-db-1.0.0/src/sm_db_service_actions.c | 476 +++ .../sm-db-1.0.0/src/sm_db_service_actions.h | 110 + .../src/sm_db_service_dependency.c | 380 ++ .../src/sm_db_service_dependency.h | 100 + .../src/sm_db_service_domain_assignments.c | 644 ++++ .../src/sm_db_service_domain_assignments.h | 150 + .../src/sm_db_service_domain_interfaces.c | 663 ++++ .../src/sm_db_service_domain_interfaces.h | 149 + .../src/sm_db_service_domain_members.c | 494 +++ .../src/sm_db_service_domain_members.h | 122 + .../src/sm_db_service_domain_neighbors.c | 563 +++ .../src/sm_db_service_domain_neighbors.h | 138 + .../sm-db-1.0.0/src/sm_db_service_domains.c | 623 +++ .../sm-db-1.0.0/src/sm_db_service_domains.h | 140 + .../src/sm_db_service_group_members.c | 405 ++ .../src/sm_db_service_group_members.h | 115 + .../sm-db-1.0.0/src/sm_db_service_groups.c | 494 +++ .../sm-db-1.0.0/src/sm_db_service_groups.h | 117 + .../sm-db-1.0.0/src/sm_db_service_heartbeat.c | 642 ++++ .../sm-db-1.0.0/src/sm_db_service_heartbeat.h | 145 + .../sm-db-1.0.0/src/sm_db_service_instances.c | 318 ++ .../sm-db-1.0.0/src/sm_db_service_instances.h | 96 + service-mgmt/sm-db-1.0.0/src/sm_db_services.c | 556 +++ service-mgmt/sm-db-1.0.0/src/sm_db_services.h | 136 + service-mgmt/sm-db-1.0.0/upgrades/README | 31 + service-mgmt/sm-db-1.0.0/upgrades/new-service | 33 + .../sm-db-1.0.0/upgrades/sm_db_upgrade.patch | 62 + 524 files changed, 107907 insertions(+) create mode 100644 CONTRIBUTORS.wrs create mode 100644 LICENSE create mode 100644 README.rst create mode 100644 mwa-solon.map create mode 100644 service-mgmt-api/centos/build_srpm.data create mode 100644 service-mgmt-api/centos/sm-api.spec create mode 100644 service-mgmt-api/sm-api/LICENSE create mode 100755 service-mgmt-api/sm-api/scripts/sm-api create mode 100644 service-mgmt-api/sm-api/scripts/sm-api.conf create mode 100644 service-mgmt-api/sm-api/scripts/sm-api.service create mode 100644 service-mgmt-api/sm-api/scripts/sm_api.ini create mode 100644 service-mgmt-api/sm-api/setup.py create mode 100644 service-mgmt-api/sm-api/sm_api/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/acl.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/api.ini create mode 100644 service-mgmt-api/sm-api/sm_api/api/api.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/app.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/config.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/root.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/v1/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/v1/base.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/v1/collection.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/v1/link.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/v1/nodes.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/v1/service_groups.py create mode 100755 service-mgmt-api/sm-api/sm_api/api/controllers/v1/servicenode.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/v1/services.py create mode 100755 service-mgmt-api/sm-api/sm_api/api/controllers/v1/sm_sda.py create mode 100755 service-mgmt-api/sm-api/sm_api/api/controllers/v1/smc_api.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/controllers/v1/utils.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/hooks.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/middleware/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/middleware/auth_token.py create mode 100644 service-mgmt-api/sm-api/sm_api/api/middleware/parsable_error.py create mode 100644 service-mgmt-api/sm-api/sm_api/cmd/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/cmd/api.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/config.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/context.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/exception.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/log.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/policy.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/safe_utils.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/service.py create mode 100644 service-mgmt-api/sm-api/sm_api/common/utils.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/api.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/migration.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/__init__.py create mode 100755 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/api.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/manage.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/migrate.cfg create mode 100644 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/versions/001_init.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/versions/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migration.py create mode 100755 service-mgmt-api/sm-api/sm_api/db/sqlalchemy/models.py create mode 100644 service-mgmt-api/sm-api/sm_api/objects/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/objects/base.py create mode 100644 service-mgmt-api/sm-api/sm_api/objects/smo_node.py create mode 100755 service-mgmt-api/sm-api/sm_api/objects/smo_sda.py create mode 100644 service-mgmt-api/sm-api/sm_api/objects/smo_sdm.py create mode 100644 service-mgmt-api/sm-api/sm_api/objects/smo_service.py create mode 100644 service-mgmt-api/sm-api/sm_api/objects/smo_servicegroup.py create mode 100644 service-mgmt-api/sm-api/sm_api/objects/utils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/cliutils.py create mode 100755 service-mgmt-api/sm-api/sm_api/openstack/common/config/generator.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/context.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/db/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/db/api.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/db/exception.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/models.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/session.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/utils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/eventlet_backdoor.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/excutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/fileutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/fixture/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/fixture/mockpatch.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/fixture/moxstubout.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/gettextutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/importutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/jsonutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/local.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/lockutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/log.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/log_handler.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/loopingcall.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/network_utils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/notifier/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/notifier/api.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/notifier/log_notifier.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/notifier/no_op_notifier.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/notifier/rpc_notifier.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/notifier/rpc_notifier2.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/notifier/test_notifier.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/periodic_task.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/policy.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/processutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/__init__.py create mode 100755 service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/cmd.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/filters.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/wrapper.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/__init__.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/amqp.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/common.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/dispatcher.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_fake.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_kombu.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_qpid.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_zmq.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker_redis.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker_ring.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/proxy.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/serializer.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/service.py create mode 100755 service-mgmt-api/sm-api/sm_api/openstack/common/rpc/zmq_receiver.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/service.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/setup.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/strutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/threadgroup.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/timeutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/uuidutils.py create mode 100644 service-mgmt-api/sm-api/sm_api/openstack/common/version.py create mode 100644 service-mgmt-client/LICENSE create mode 100644 service-mgmt-client/centos/build_srpm.data create mode 100644 service-mgmt-client/centos/sm-client.spec create mode 100644 service-mgmt-client/sm-client/LICENSE create mode 100644 service-mgmt-client/sm-client/README.rst create mode 100644 service-mgmt-client/sm-client/doc/source/conf.py create mode 100644 service-mgmt-client/sm-client/requirements.txt create mode 100644 service-mgmt-client/sm-client/setup.cfg create mode 100644 service-mgmt-client/sm-client/setup.py create mode 100644 service-mgmt-client/sm-client/sm_client/__init__.py create mode 100644 service-mgmt-client/sm-client/sm_client/client.py create mode 100644 service-mgmt-client/sm-client/sm_client/common/__init__.py create mode 100644 service-mgmt-client/sm-client/sm_client/common/base.py create mode 100644 service-mgmt-client/sm-client/sm_client/common/http.py create mode 100644 service-mgmt-client/sm-client/sm_client/common/utils.py create mode 100644 service-mgmt-client/sm-client/sm_client/exc.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/__init__.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/common/__init__.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/common/config/generator.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/common/gettextutils.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/common/importutils.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/__init__.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/cmd.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/filters.py create mode 100644 service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/wrapper.py create mode 100644 service-mgmt-client/sm-client/sm_client/shell.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/__init__.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/client.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/iservice.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/iservice_shell.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/iservicegroup.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/iservicegroup_shell.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/shell.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/sm_nodes.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/sm_nodes_shell.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/sm_sda.py create mode 100755 service-mgmt-client/sm-client/sm_client/v1/sm_sda_shell.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/smservicenode.py create mode 100644 service-mgmt-client/sm-client/sm_client/v1/smservicenode_shell.py create mode 100644 service-mgmt-client/sm-client/tools_junk/__init__.py create mode 100644 service-mgmt-client/sm-client/tools_junk/install_venv_common.py create mode 100755 service-mgmt-client/sm-client/tools_junk/with_venv.sh create mode 100644 service-mgmt-tools/centos/build_srpm.data create mode 100644 service-mgmt-tools/centos/sm-tools.spec create mode 100644 service-mgmt-tools/sm-tools/LICENSE create mode 100755 service-mgmt-tools/sm-tools/setup.py create mode 100644 service-mgmt-tools/sm-tools/sm_tools/__init__.py create mode 100644 service-mgmt-tools/sm-tools/sm_tools/sm_action.py create mode 100644 service-mgmt-tools/sm-tools/sm_tools/sm_api_msg_utils.py create mode 100644 service-mgmt-tools/sm-tools/sm_tools/sm_configure.py create mode 100755 service-mgmt-tools/sm-tools/sm_tools/sm_dump.py create mode 100644 service-mgmt-tools/sm-tools/sm_tools/sm_patch.py create mode 100755 service-mgmt-tools/sm-tools/sm_tools/sm_provision.py create mode 100644 service-mgmt-tools/sm-tools/sm_tools/sm_query.py create mode 100644 service-mgmt/LICENSE create mode 100644 service-mgmt/sm-1.0.0/LICENSE create mode 100644 service-mgmt/sm-1.0.0/Makefile create mode 100644 service-mgmt/sm-1.0.0/centos/build_srpm.data create mode 100644 service-mgmt/sm-1.0.0/centos/sm.spec create mode 100644 service-mgmt/sm-1.0.0/scripts/Makefile create mode 100755 service-mgmt/sm-1.0.0/scripts/sm create mode 100644 service-mgmt/sm-1.0.0/scripts/sm-shutdown.service create mode 100644 service-mgmt/sm-1.0.0/scripts/sm.conf create mode 100644 service-mgmt/sm-1.0.0/scripts/sm.logrotate create mode 100644 service-mgmt/sm-1.0.0/scripts/sm.notification create mode 100644 service-mgmt/sm-1.0.0/scripts/sm.notify create mode 100644 service-mgmt/sm-1.0.0/scripts/sm.service create mode 100644 service-mgmt/sm-1.0.0/scripts/sm.shutdown create mode 100644 service-mgmt/sm-1.0.0/scripts/sm.troubleshoot create mode 100644 service-mgmt/sm-1.0.0/src/Makefile create mode 100644 service-mgmt/sm-1.0.0/src/fm_api_wrapper.c create mode 100644 service-mgmt/sm-1.0.0/src/fm_api_wrapper.h create mode 100644 service-mgmt/sm-1.0.0/src/main.c create mode 100644 service-mgmt/sm-1.0.0/src/service_status create mode 100644 service-mgmt/sm-1.0.0/src/sm_alarm.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_alarm.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_alarm_defs.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_alarm_thread.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_alarm_thread.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_api.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_api.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_configuration_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_configuration_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_failover.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_failover.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_failover_thread.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_failover_thread.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_heartbeat.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_heartbeat.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_heartbeat_thread.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_heartbeat_thread.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_log.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_log.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_log_defs.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_log_thread.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_log_thread.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_main_event_handler.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_main_event_handler.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_msg.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_msg.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_api.cpp create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_api.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_disabled_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_disabled_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_enabled_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_enabled_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_fsm.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_fsm.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_swact_monitor.cpp create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_swact_monitor.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_unknown_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_node_unknown_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_notify_api.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_notify_api.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_process.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_process.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_process_death.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_process_death.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_action.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_action.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_action_result_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_action_result_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_action_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_action_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_api.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_api.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_audit.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_audit.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_dependency.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_dependency.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_dependency_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_dependency_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_disable.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_disable.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_disabled_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_disabled_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_disabling_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_disabling_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_api.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_api.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_assignment_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_assignment_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_backup_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_backup_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_filter.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_filter.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_fsm.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_fsm.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_initial_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_initial_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_api.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_api.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_disabled_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_disabled_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_enabled_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_enabled_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_fsm.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_fsm.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_not_in_use_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_not_in_use_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_unknown_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_interface_unknown_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_leader_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_leader_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_member_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_member_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_down_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_down_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_start_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_start_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_fsm.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_fsm.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_full_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_full_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_other_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_other_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_scheduler.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_scheduler.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_utils.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_utils.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_waiting_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_waiting_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_weight.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_domain_weight.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enable.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enable.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabled_active_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabled_active_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabled_go_active_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabled_go_active_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabled_go_standby_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabled_go_standby_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabled_standby_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabled_standby_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabling_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabling_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabling_throttle_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_enabling_throttle_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_engine.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_engine.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_fsm.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_fsm.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_go_active.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_go_active.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_go_standby.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_go_standby.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_active_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_active_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_api.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_api.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_audit.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_audit.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_disable.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_disable.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_disabled_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_disabled_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_disabling_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_disabling_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_enable.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_enable.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_engine.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_engine.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_fsm.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_fsm.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_go_active.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_go_active.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_go_active_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_go_active_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_go_standby.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_go_standby.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_go_standby_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_go_standby_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_health.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_health.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_initial_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_initial_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_member_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_member_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_notification.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_notification.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_shutdown_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_shutdown_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_standby_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_standby_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_group_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_heartbeat.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_heartbeat.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_heartbeat_api.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_heartbeat_api.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_heartbeat_thread.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_heartbeat_thread.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_initial_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_initial_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_shutdown_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_shutdown_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_table.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_table.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_unknown_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_service_unknown_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_swact_state.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_swact_state.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_task_affining_thread.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_task_affining_thread.h create mode 100644 service-mgmt/sm-1.0.0/src/sm_troubleshoot.c create mode 100644 service-mgmt/sm-1.0.0/src/sm_troubleshoot.h create mode 100644 service-mgmt/sm-common-1.0.0/LICENSE create mode 100644 service-mgmt/sm-common-1.0.0/Makefile create mode 100644 service-mgmt/sm-common-1.0.0/centos/build_srpm.data create mode 100644 service-mgmt/sm-common-1.0.0/centos/sm-common.spec create mode 100644 service-mgmt/sm-common-1.0.0/scripts/Makefile create mode 100755 service-mgmt/sm-common-1.0.0/scripts/sm-eru create mode 100644 service-mgmt/sm-common-1.0.0/scripts/sm-eru.conf create mode 100644 service-mgmt/sm-common-1.0.0/scripts/sm-eru.service create mode 100755 service-mgmt/sm-common-1.0.0/scripts/sm-watchdog create mode 100644 service-mgmt/sm-common-1.0.0/scripts/sm-watchdog.conf create mode 100644 service-mgmt/sm-common-1.0.0/scripts/sm-watchdog.service create mode 100644 service-mgmt/sm-common-1.0.0/src/Makefile create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_debug.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_debug.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_debug_thread.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_debug_thread.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_eru_db.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_eru_db.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_eru_dump.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_eru_main.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_eru_process.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_eru_process.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_hw.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_hw.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_limits.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_list.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_netlink.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_netlink.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_node_stats.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_node_stats.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_node_utils.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_node_utils.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_selobj.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_selobj.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_sha512.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_sha512.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_thread_health.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_thread_health.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_time.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_time.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_timer.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_timer.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_trap.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_trap.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_trap_thread.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_trap_thread.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_types.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_types.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_util_types.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_util_types.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_utils.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_utils.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_uuid.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_uuid.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_watchdog_main.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_watchdog_module.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_watchdog_module.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_watchdog_nfs.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_watchdog_nfs.h create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_watchdog_process.c create mode 100644 service-mgmt/sm-common-1.0.0/src/sm_watchdog_process.h create mode 100644 service-mgmt/sm-db-1.0.0/LICENSE create mode 100644 service-mgmt/sm-db-1.0.0/Makefile create mode 100644 service-mgmt/sm-db-1.0.0/centos/build_srpm.data create mode 100644 service-mgmt/sm-db-1.0.0/centos/sm-db.spec create mode 100644 service-mgmt/sm-db-1.0.0/database/Makefile create mode 100644 service-mgmt/sm-db-1.0.0/database/README create mode 100644 service-mgmt/sm-db-1.0.0/database/create_sm_db.sql create mode 100644 service-mgmt/sm-db-1.0.0/database/create_sm_hb_db.sql create mode 100644 service-mgmt/sm-db-1.0.0/database/sm-patch.sql create mode 100644 service-mgmt/sm-db-1.0.0/database/sm_database.xlsb create mode 100644 service-mgmt/sm-db-1.0.0/patches/sm_db_ceph_install.patch create mode 100644 service-mgmt/sm-db-1.0.0/patches/sm_db_cinder_lvm_install.patch create mode 100644 service-mgmt/sm-db-1.0.0/patches/sm_db_pxeboot_install.patch create mode 100755 service-mgmt/sm-db-1.0.0/scripts/sm-db-populate.script create mode 100644 service-mgmt/sm-db-1.0.0/src/Makefile create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_build.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_configuration.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_configuration.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_foreach.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_foreach.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_iterator.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_iterator.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_node_history.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_node_history.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_nodes.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_nodes.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_action_results.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_action_results.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_actions.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_actions.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_dependency.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_dependency.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_assignments.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_assignments.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_interfaces.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_interfaces.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_members.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_members.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_neighbors.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_neighbors.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domains.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_domains.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_group_members.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_group_members.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_groups.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_groups.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_heartbeat.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_heartbeat.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_instances.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_service_instances.h create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_services.c create mode 100644 service-mgmt/sm-db-1.0.0/src/sm_db_services.h create mode 100644 service-mgmt/sm-db-1.0.0/upgrades/README create mode 100644 service-mgmt/sm-db-1.0.0/upgrades/new-service create mode 100644 service-mgmt/sm-db-1.0.0/upgrades/sm_db_upgrade.patch diff --git a/CONTRIBUTORS.wrs b/CONTRIBUTORS.wrs new file mode 100644 index 00000000..fba3ceaa --- /dev/null +++ b/CONTRIBUTORS.wrs @@ -0,0 +1,8 @@ +The following contributors from Wind River have developed the seed code in this +repository. We look forward to community collaboration and contributions for +additional features, enhancements and refactoring. + +Contributors: +============= +Bin Qian +Eric Macdonald diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..d872abf7 --- /dev/null +++ b/README.rst @@ -0,0 +1,5 @@ +====== +stx-ha +====== + +SterlingX Service Management diff --git a/mwa-solon.map b/mwa-solon.map new file mode 100644 index 00000000..28090cf1 --- /dev/null +++ b/mwa-solon.map @@ -0,0 +1,5 @@ +cgcs/recipes-svcmgmt/service-mgmt-api|service-mgmt-api +cgcs/recipes-svcmgmt/service-mgmt-client|service-mgmt-client +cgcs/recipes-svcmgmt/service-mgmt-tools|service-mgmt-tools +cgcs/recipes-svcmgmt/service-mgmt|service-mgmt +cgcs/middleware/mtce/recipes-common/cgts-mtce-common/cgts-mtce-common-1.0/pmon|pmon diff --git a/service-mgmt-api/centos/build_srpm.data b/service-mgmt-api/centos/build_srpm.data new file mode 100644 index 00000000..896b6864 --- /dev/null +++ b/service-mgmt-api/centos/build_srpm.data @@ -0,0 +1,4 @@ +SRC_DIR=sm-api +TAR_NAME=sm-api +VERSION=1.0 +TIS_PATCH_VER=2 diff --git a/service-mgmt-api/centos/sm-api.spec b/service-mgmt-api/centos/sm-api.spec new file mode 100644 index 00000000..a6970787 --- /dev/null +++ b/service-mgmt-api/centos/sm-api.spec @@ -0,0 +1,81 @@ +Summary: Service Management API +Name: sm-api +Version: 1.0 +Release: %{tis_patch_ver}%{?_tis_dist} +License: Apache-2.0 +Group: base +Packager: Wind River +URL: unknown +Source0: %{name}-%{version}.tar.gz + +%define debug_package %{nil} + +BuildRequires: python +BuildRequires: python-setuptools +BuildRequires: util-linux +# BuildRequires systemd is to get %_unitdir I think +BuildRequires: systemd +BuildRequires: systemd-devel +Requires: python-libs + +# Needed for /etc/init.d, can be removed when we go fully systemd +Requires: chkconfig +# Needed for /etc/pmon.d +Requires: cgts-mtce-common-pmon + + +%prep +%setup -q + +%build +%{__python2} setup.py build + +%install +%global _buildsubdir %{_builddir}/%{name}-%{version} +%{__python2} setup.py install -O1 --skip-build --root %{buildroot} +install -d %{buildroot}/etc/sm +install -d %{buildroot}/etc/init.d +install -d %{buildroot}/etc/pmon.d +install -d %{buildroot}%{_unitdir} +install -m 644 %{_buildsubdir}/scripts/sm_api.ini %{buildroot}/etc/sm +install -m 755 %{_buildsubdir}/scripts/sm-api %{buildroot}/etc/init.d +install -m 644 %{_buildsubdir}/scripts/sm-api.service %{buildroot}%{_unitdir} +install -m 644 %{_buildsubdir}/scripts/sm-api.conf %{buildroot}/etc/pmon.d + +%description +Service Management API + +#%package -n sm-api-py-src-tar +#Summary: Service Management API +#Group: base + +#%description -n sm-api-py-src-tar +#Service Management API + + +#%post -n sm-api-py-src-tar +## sm-api-py-src-tar - postinst +# if [ -f $D/usr/src/sm-api-1.0.tar.bz2 ] ; then +# ( cd $D/ && tar -xf $D/usr/src/sm-api-1.0.tar.bz2 ) +# fi + +%post +/usr/bin/systemctl enable sm-api.service >/dev/null 2>&1 + +%files +%defattr(-,root,root,-) +%dir "/usr/lib/python2.7/site-packages/sm_api" +/usr/lib/python2.7/site-packages/sm_api/* +%dir "/usr/lib/python2.7/site-packages/sm_api-1.0.0-py2.7.egg-info" +/usr/lib/python2.7/site-packages/sm_api-1.0.0-py2.7.egg-info/* +"/usr/bin/sm-api" +%dir "/etc/sm" +"/etc/init.d/sm-api" +"/etc/pmon.d/sm-api.conf" +"/etc/sm/sm_api.ini" +%{_unitdir}/* + +#%files -n sm-api-py-src-tar +#%defattr(-,-,-,-) +#"/usr/src/sm-api-1.0.tar.bz2" + diff --git a/service-mgmt-api/sm-api/LICENSE b/service-mgmt-api/sm-api/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/service-mgmt-api/sm-api/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/service-mgmt-api/sm-api/scripts/sm-api b/service-mgmt-api/sm-api/scripts/sm-api new file mode 100755 index 00000000..54e93ac6 --- /dev/null +++ b/service-mgmt-api/sm-api/scripts/sm-api @@ -0,0 +1,114 @@ +#! /bin/sh +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# chkconfig: - 60 60 +# processname: sm-api +# description: Service Management API +# +### BEGIN INIT INFO +# Description: sm-api... +# +# Short-Description: Service Management API. +# Provides: sm-api +# Required-Start: $network +# Should-Start: $syslog +# Required-Stop: $network +# Default-Start: 3 5 +# Default-Stop: 0 6 +### END INIT INFO + +. /etc/init.d/functions + +# Linux Standard Base (LSB) Error Codes +RETVAL=0 +LSB_GENERIC_ERROR=1 +LSB_INVALID_ARGS=2 +LSB_UNSUPPORTED_FEATURE=3 +LSB_NOT_INSTALLED=5 +LSB_NOT_RUNNING=7 + +SM_API_NAME="sm-api" +SM_API="/usr/bin/${SM_API_NAME}" + +daemon_pidfile="/var/run/${SM_API_NAME}.pid" + + +if [ ! -e "${SM_API}" ] ; then + logger "${SM_API} is missing" + exit ${LSB_NOT_INSTALLED} +fi + +PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin +export PATH + +case "$1" in + start) + echo -n "Starting ${SM_API_NAME}: " + if [ -n "`pidof ${SM_API_NAME}`" ] ; then + echo -n "is already running " + RETVAL=0 + else + /bin/sh -c "${SM_API} --debug --verbose --use-syslog --syslog-log-facility local1"' >> /dev/null 2>&1 & echo $!' > ${daemon_pidfile} + RETVAL=$? + fi + if [ ${RETVAL} -eq 0 ] ; then + pid=`pidof ${SM_API_NAME}` + echo "OK" + logger "${SM_API} (${pid})" + else + echo "FAIL" + RETVAL=${LSB_GENERIC_ERROR} + fi + ;; + + stop) + echo " " + echo -n "Stopping ${SM_API_NAME}: " + + if [ -e ${daemon_pidfile} ] ; then + pid=`cat ${daemon_pidfile}` + kill -TERM $pid + rm -f ${daemon_pidfile} + rm -f /var/lock/subsys/${SM_API_NAME} + echo "OK" + else + echo "FAIL" + fi + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + status) + if [ -e ${daemon_pidfile} ] ; then + pid=`cat ${daemon_pidfile}` + ps -p $pid | grep -v "PID TTY" >> /dev/null 2>&1 + if [ $? -eq 0 ] ; then + echo "${SM_API_NAME} is running" + RETVAL=0 + else + echo "${SM_API_NAME} is NOT running" + RETVAL=1 + fi + else + echo "${SM_API_NAME} is running; no pidfile" + RETVAL=1 + fi + ;; + + condrestart) + [ -f /var/lock/subsys/${SM_API_NAME} ] && $0 restart + ;; + + *) + echo "usage: $0 { start | stop | status | restart | condrestart | status }" + ;; +esac + +exit ${RETVAL} diff --git a/service-mgmt-api/sm-api/scripts/sm-api.conf b/service-mgmt-api/sm-api/scripts/sm-api.conf new file mode 100644 index 00000000..08dd8674 --- /dev/null +++ b/service-mgmt-api/sm-api/scripts/sm-api.conf @@ -0,0 +1,14 @@ +; +; Copyright (c) 2014 Wind River Systems, Inc. +; +; SPDX-License-Identifier: Apache-2.0 +; +[process] +process = sm-api +pidfile = /var/run/sm-api.pid +script = /etc/init.d/sm-api +style = lsb ; ocf or lsb +severity = major ; minor, major, critical +restarts = 3 ; restarts before error assertion +interval = 5 ; number of seconds to wait between restarts +debounce = 20 ; number of seconds to wait before degrade clear diff --git a/service-mgmt-api/sm-api/scripts/sm-api.service b/service-mgmt-api/sm-api/scripts/sm-api.service new file mode 100644 index 00000000..11a35104 --- /dev/null +++ b/service-mgmt-api/sm-api/scripts/sm-api.service @@ -0,0 +1,15 @@ +[Unit] +Description=Service Management API Unit +After=network-online.target syslog-ng.service config.service sm.service +Before=sm-eru.service pmon.service + +[Service] +Type=forking +RemainAfterExit=yes +User=root +ExecStart=/etc/init.d/sm-api start +ExecStop=/etc/init.d/sm-api stop +PIDFile=/var/run/sm-api.pid + +[Install] +WantedBy=multi-user.target diff --git a/service-mgmt-api/sm-api/scripts/sm_api.ini b/service-mgmt-api/sm-api/scripts/sm_api.ini new file mode 100644 index 00000000..198fd009 --- /dev/null +++ b/service-mgmt-api/sm-api/scripts/sm_api.ini @@ -0,0 +1,10 @@ +; +; Copyright (c) 2014 Wind River Systems, Inc. +; +; SPDX-License-Identifier: Apache-2.0 +; +[logging] +use_syslog= + +[database] +database=/etc/sm/sm.database.v1 diff --git a/service-mgmt-api/sm-api/setup.py b/service-mgmt-api/sm-api/setup.py new file mode 100644 index 00000000..650e56d0 --- /dev/null +++ b/service-mgmt-api/sm-api/setup.py @@ -0,0 +1,31 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +import setuptools + +setuptools.setup( + name='sm_api', + description='Service Management API', + version='1.0.0', + license='Apache-2.0', + packages=['sm_api', 'sm_api.common', 'sm_api.db', 'sm_api.objects', + 'sm_api.api', 'sm_api.api.controllers', 'sm_api.api.middleware', + 'sm_api.api.controllers.v1', 'sm_api.cmd', + 'sm_api.db.sqlalchemy', + 'sm_api.db.sqlalchemy.migrate_repo', + 'sm_api.db.sqlalchemy.migrate_repo.versions', + 'sm_api.openstack', 'sm_api.openstack.common', + 'sm_api.openstack.common.db', + 'sm_api.openstack.common.db.sqlalchemy', + 'sm_api.openstack.common.rootwrap', + 'sm_api.openstack.common.rpc', + 'sm_api.openstack.common.notifier', + 'sm_api.openstack.common.config', + 'sm_api.openstack.common.fixture'], + entry_points={ + 'console_scripts': [ + 'sm-api = sm_api.cmd.api:main' + ]} +) diff --git a/service-mgmt-api/sm-api/sm_api/__init__.py b/service-mgmt-api/sm-api/sm_api/__init__.py new file mode 100644 index 00000000..42b3bf66 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/__init__.py @@ -0,0 +1,10 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# All Rights Reserved. +# diff --git a/service-mgmt-api/sm-api/sm_api/api/__init__.py b/service-mgmt-api/sm-api/sm_api/api/__init__.py new file mode 100644 index 00000000..37856032 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/__init__.py @@ -0,0 +1,27 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +from oslo_config import cfg + +API_SERVICE_OPTS = [ + cfg.StrOpt('sm_api_bind_ip', + default='0.0.0.0', + help='IP for the Service Management API server to bind to', + ), + cfg.IntOpt('sm_api_port', + default=7777, + help='The port for the Service Management API server', + ), + cfg.IntOpt('api_limit_max', + default=1000, + help='the maximum number of items returned in a single ' + 'response from a collection resource'), + ] + +CONF = cfg.CONF +opt_group = cfg.OptGroup(name='api', + title='Options for the sm-api service') +CONF.register_group(opt_group) +CONF.register_opts(API_SERVICE_OPTS) diff --git a/service-mgmt-api/sm-api/sm_api/api/acl.py b/service-mgmt-api/sm-api/sm_api/api/acl.py new file mode 100644 index 00000000..3b4360f5 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/acl.py @@ -0,0 +1,76 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2012 New Dream Network, LLC (DreamHost) +# +# Author: Doug Hellmann +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Access Control Lists (ACL's) control access the API server.""" + +from keystonemiddleware import auth_token as keystone_auth_token +from oslo_config import cfg +from pecan import hooks +from webob import exc + +from sm_api.api.middleware import auth_token +from sm_api.common import policy + + +OPT_GROUP_NAME = 'keystone_authtoken' + + +def register_opts(conf): + """Register keystoneclient middleware options + + :param conf: SmApi settings. + """ + #conf.register_opts(keystone_auth_token._OPTS, group=OPT_GROUP_NAME) + keystone_auth_token.CONF = conf + + +register_opts(cfg.CONF) + + +def install(app, conf, public_routes): + """Install ACL check on application. + + :param app: A WSGI applicatin. + :param conf: Settings. Must include OPT_GROUP_NAME section. + :param public_routes: The list of the routes which will be allowed to + access without authentication. + :return: The same WSGI application with ACL installed. + + """ + keystone_config = dict(conf.get(OPT_GROUP_NAME)) + return auth_token.AuthTokenMiddleware(app, + conf=keystone_config, + public_api_routes=public_routes) + + +class AdminAuthHook(hooks.PecanHook): + """Verify that the user has admin rights. + + Checks whether the request context is an admin context and + rejects the request otherwise. + + """ + def before(self, state): + ctx = state.request.context + + if not policy.check_is_admin(ctx) and not ctx.is_public_api: + raise exc.HTTPForbidden() diff --git a/service-mgmt-api/sm-api/sm_api/api/api.ini b/service-mgmt-api/sm-api/sm_api/api/api.ini new file mode 100644 index 00000000..55975a19 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/api.ini @@ -0,0 +1,5 @@ +[logging] +use_syslog= + +[database] +database=/tmp/sm.database.v1 diff --git a/service-mgmt-api/sm-api/sm_api/api/api.py b/service-mgmt-api/sm-api/sm_api/api/api.py new file mode 100644 index 00000000..52a6cd17 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/api.py @@ -0,0 +1,67 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +import os +import sys +import argparse +import ConfigParser +import eventlet +from wsgiref import simple_server + +from sm_api.common import config +from sm_api.common import log +from sm_api import app + +os.environ['EVENTLET_NO_GREENDNS'] = 'yes' +eventlet.monkey_patch(os=False) + + +def get_handler_cls(): + cls = simple_server.WSGIRequestHandler + + # old-style class doesn't support super + class MyHandler(cls, object): + def address_string(self): + # In the future, we could provide a config option to allow reverse DNS lookup + return self.client_address[0] + + return MyHandler + + +def main(): + try: + parser = argparse.ArgumentParser() + parser.add_argument('-c', '--config', required=True, + help='configuration file') + args = parser.parse_args() + + config.load(args.config) + + if not config.CONF: + print "Error: configuration not available." + sys.exit(-1) + + log.configure(config.CONF) + + wsgi = simple_server.make_server('0.0.0.0', 7777, app.Application(), + handler_class=get_handler_cls()) + wsgi.serve_forever() + + except ConfigParser.NoOptionError as e: + print e + sys.exit(-2) + + except ConfigParser.NoSectionError as e: + print e + sys.exit(-3) + + except KeyboardInterrupt: + sys.exit() + + except Exception as e: + print e + sys.exit(-4) + +main() diff --git a/service-mgmt-api/sm-api/sm_api/api/app.py b/service-mgmt-api/sm-api/sm_api/api/app.py new file mode 100644 index 00000000..1f134738 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/app.py @@ -0,0 +1,109 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +""" +Application +""" + +from oslo_config import cfg +import pecan + +from sm_api.api import config +from sm_api.api import hooks + +from sm_api.api import acl +from sm_api.api import middleware + + +auth_opts = [ + cfg.StrOpt('auth_strategy', + default='noauth', + help='Method to use for auth: noauth or keystone.'), + ] + +CONF = cfg.CONF +CONF.register_opts(auth_opts) + + +def get_pecan_config(): + filename = config.__file__.replace('.pyc', '.py') + return pecan.configuration.conf_from_file(filename) + + +def create_app(): + pecan_conf = get_pecan_config() + app_hooks = [hooks.ConfigHook(), + hooks.DatabaseHook()] + + pecan.configuration.set_config(dict(pecan_conf), overwrite=True) + + app = pecan.make_app( + pecan_conf.app.root, + static_root=pecan_conf.app.static_root, + debug=False, + force_canonical=getattr(pecan_conf.app, 'force_canonical', True), + hooks=app_hooks + ) + + return app + + +def setup_app(pecan_config=None, extra_hooks=None): + app_hooks = [hooks.ConfigHook(), + hooks.DatabaseHook(), + hooks.ContextHook(pecan_config.app.acl_public_routes), + ] + # hooks.RPCHook() + if extra_hooks: + app_hooks.extend(extra_hooks) + + if not pecan_config: + pecan_config = get_pecan_config() + + if pecan_config.app.enable_acl: + app_hooks.append(acl.AdminAuthHook()) + + pecan.configuration.set_config(dict(pecan_config), overwrite=True) + + app = pecan.make_app( + pecan_config.app.root, + static_root=pecan_config.app.static_root, + debug=CONF.debug, + force_canonical=getattr(pecan_config.app, 'force_canonical', True), + hooks=app_hooks, + wrap_app=middleware.ParsableErrorMiddleware, + ) + + if pecan_config.app.enable_acl: + return acl.install(app, cfg.CONF, pecan_config.app.acl_public_routes) + + return app + + +class Application(object): + def __init__(self): + self.v1 = create_app() + + @classmethod + def unsupported_version(cls, start_response): + start_response('404 Not Found', []) + return [] + + def __call__(self, environ, start_response): + if environ['PATH_INFO'].startswith("/v1/"): + return self.v1(environ, start_response) + + return Application.unsupported_version(start_response) + + +class VersionSelectorApplication(object): + def __init__(self): + pc = get_pecan_config() + pc.app.enable_acl = (CONF.auth_strategy == 'keystone') + self.v1 = setup_app(pecan_config=pc) + + def __call__(self, environ, start_response): + return self.v1(environ, start_response) diff --git a/service-mgmt-api/sm-api/sm_api/api/config.py b/service-mgmt-api/sm-api/sm_api/api/config.py new file mode 100644 index 00000000..fb5113d4 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/config.py @@ -0,0 +1,17 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Server Configuration +server = {'host': '0.0.0.0', 'port': '7777'} + +# Pecan Application Configurations +app = {'root': 'sm_api.api.controllers.root.RootController', + 'modules': ['sm_api'], + 'static_root': '', + 'debug': False, + 'enable_acl': False, + 'acl_public_routes': ['/', '/v1'] + } diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/__init__.py b/service-mgmt-api/sm-api/sm_api/api/controllers/__init__.py new file mode 100644 index 00000000..147b74f9 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/__init__.py @@ -0,0 +1,5 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/root.py b/service-mgmt-api/sm-api/sm_api/api/controllers/root.py new file mode 100644 index 00000000..419f6d3c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/root.py @@ -0,0 +1,65 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import pecan +from pecan import rest +from wsme import types as wsme_types +from wsmeext import pecan as wsme_pecan + +from sm_api.api.controllers import v1 +from sm_api.api.controllers.v1 import base +from sm_api.api.controllers.v1 import link + + +class Version(base.APIBase): + """An API version representation.""" + + id = wsme_types.text + "The ID of the version, also acts as the release number" + + links = [link.Link] + "A Link that point to a specific version of the API" + + @classmethod + def convert(cls, id): + version = Version() + version.id = id + version.links = [link.Link.make_link('self', pecan.request.host_url, + id, '', bookmark=True)] + return version + + +class Root(base.APIBase): + + name = wsme_types.text + "The name of the API" + + description = wsme_types.text + "Some information about this API" + + version = [Version] + "Links to all the versions available in this API" + + default_version = Version + "A link to the default version of the API" + + @classmethod + def convert(cls): + root = Root() + root.name = "System Management API" + root.description = "System Management API from Wind River" + root.version = [Version.convert("v1")] + root.default_version = Version.convert("v1") + return root + + +class RootController(rest.RestController): + + v1 = v1.Controller() + + @wsme_pecan.wsexpose(Root) + def get(self): + return Root.convert() diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/__init__.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/__init__.py new file mode 100644 index 00000000..109021da --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/__init__.py @@ -0,0 +1,101 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import pecan +from pecan import rest + +from wsme import types as wsme_types +import wsmeext.pecan as wsme_pecan + +from sm_api.api.controllers.v1 import link +from sm_api.api.controllers.v1 import service_groups +from sm_api.api.controllers.v1 import services +from sm_api.api.controllers.v1 import servicenode +from sm_api.api.controllers.v1 import sm_sda +from sm_api.api.controllers.v1 import nodes + + +class Version1(wsme_types.Base): + """ Version-1 of the API. + """ + + id = wsme_types.text + "The ID of the version, also acts as the release number" + + links = [link.Link] + "Links that point to a specific URL for this version and documentation" + + service_group = [link.Link] + "Links to the SM service-group resource" + + servicenode = [link.Link] + "Links to the SM service node resource" + + sm_sda = [link.Link] + "Links to the SM service domain assignments resource " + + @classmethod + def convert(cls): + v1 = Version1() + v1.id = "v1" + v1.links = [link.Link.make_link('self', pecan.request.host_url, + 'v1', '', bookmark=True)] + v1.service_groups = [link.Link.make_link('self', + pecan.request.host_url, + 'service_groups', ''), + link.Link.make_link('bookmark', + pecan.request.host_url, + 'service_groups', '', + bookmark=True)] + v1.services = [link.Link.make_link('self', + pecan.request.host_url, + 'services', ''), + link.Link.make_link('bookmark', + pecan.request.host_url, + 'services', '', + bookmark=True)] + + v1.servicenode = [link.Link.make_link('self', + pecan.request.host_url, + 'servicenode', ''), + link.Link.make_link('bookmark', + pecan.request.host_url, + 'servicenode', '', + bookmark=True)] + + v1.sm_sda = [link.Link.make_link('self', + pecan.request.host_url, + 'sm_sda', ''), + link.Link.make_link('bookmark', + pecan.request.host_url, + 'sm_sda', '', + bookmark=True)] + + v1.nodes = [link.Link.make_link('self', + pecan.request.host_url, + 'nodes', ''), + link.Link.make_link('bookmark', + pecan.request.host_url, + 'nodes', '', + bookmark=True)] + + return v1 + + +class Controller(rest.RestController): + """Version 1 API controller root.""" + + service_groups = service_groups.ServiceGroupController() + services = services.ServicesController() + servicenode = servicenode.ServiceNodeController() + sm_sda = sm_sda.SmSdaController() + nodes = nodes.NodesController() + + @wsme_pecan.wsexpose(Version1) + def get(self): + return Version1.convert() + +__all__ = Controller diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/base.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/base.py new file mode 100644 index 00000000..49f5dbff --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/base.py @@ -0,0 +1,55 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# All Rights Reserved. +# + +import datetime + +import wsme +from wsme import types as wsme_types + + +class APIBase(wsme_types.Base): + + # created_at = datetime.datetime + # "The time in UTC at which the object is created" + + # updated_at = datetime.datetime + # "The time in UTC at which the object is updated" + + def as_dict(self): + """Render this object as a dict of its fields.""" + return dict((k, getattr(self, k)) + for k in self.fields + if hasattr(self, k) and + getattr(self, k) != wsme.Unset) + + def unset_fields_except(self, except_list=None): + """Unset fields so they don't appear in the message body. + + :param except_list: A list of fields that won't be touched. + + """ + if except_list is None: + except_list = [] + + for k in self.as_dict(): + if k not in except_list: + setattr(self, k, wsme.Unset) + + @classmethod + def from_rpc_object(cls, m, fields=None): + """Convert a RPC object to an API object.""" + obj_dict = m.as_dict() + # Unset non-required fields so they do not appear + # in the message body + obj_dict.update(dict((k, wsme.Unset) + for k in obj_dict.keys() + if fields and k not in fields)) + return cls(**obj_dict) diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/collection.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/collection.py new file mode 100644 index 00000000..35f6b5db --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/collection.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import pecan +from wsme import types as wtypes + +from sm_api.api.controllers.v1 import base +from sm_api.api.controllers.v1 import link + + +class Collection(base.APIBase): + + next = wtypes.text + "A link to retrieve the next subset of the collection" + + @property + def collection(self): + return getattr(self, self._type) + + def has_next(self, limit): + """Return whether collection has more items.""" + return len(self.collection) and len(self.collection) == limit + + def get_next(self, limit, url=None, **kwargs): + """Return a link to the next subset of the collection.""" + if not self.has_next(limit): + return wtypes.Unset + + resource_url = url or self._type + q_args = ''.join(['%s=%s&' % (key, kwargs[key]) for key in kwargs]) + next_args = '?%(args)slimit=%(limit)d&marker=%(marker)s' % { + 'args': q_args, 'limit': limit, + 'marker': self.collection[-1].uuid} + + return link.Link.make_link('next', pecan.request.host_url, + resource_url, next_args).href diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/link.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/link.py new file mode 100644 index 00000000..3c39d12c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/link.py @@ -0,0 +1,30 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from wsme import types as wsme_types + + +class Link(wsme_types.Base): + """ Representation of a link. + """ + + href = wsme_types.text + "The url of a link." + + rel = wsme_types.text + "The name of a link." + + type = wsme_types.text + "The type of document or link." + + @classmethod + def make_link(cls, rel_name, url, resource, resource_args, + bookmark=False, type=wsme_types.Unset): + template = '%s/%s' if bookmark else '%s/v1/%s' + template += '%s' if resource_args.startswith('?') else '/%s' + + return Link(href=template % (url, resource, resource_args), + rel=rel_name, type=type) diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/nodes.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/nodes.py new file mode 100644 index 00000000..54345da5 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/nodes.py @@ -0,0 +1,144 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import json +import wsme +from wsme import types as wsme_types +import wsmeext.pecan as wsme_pecan +import pecan +from pecan import rest + +from sm_api.api.controllers.v1 import base +from sm_api.api.controllers.v1 import collection +from sm_api.api.controllers.v1 import link +from sm_api.api.controllers.v1 import utils + +from sm_api.common import log +from sm_api import objects + + +LOG = log.get_logger(__name__) + + +class NodesCommand(wsme_types.Base): + path = wsme_types.text + value = wsme_types.text + op = wsme_types.text + + +class NodesCommandResult(wsme_types.Base): + # Host Information + hostname = wsme_types.text + state = wsme_types.text + # Command + path = wsme_types.text + value = wsme_types.text + op = wsme_types.text + # Result + error_code = wsme_types.text + error_details = wsme_types.text + + +class Nodes(base.APIBase): + id = int + name = wsme_types.text + administrative_state = wsme_types.text + operational_state = wsme_types.text + availability_status = wsme_types.text + ready_state = wsme_types.text + + links = [link.Link] + "A list containing a self link and associated nodes links" + + def __init__(self, **kwargs): + self.fields = objects.sm_node.fields.keys() + for k in self.fields: + setattr(self, k, kwargs.get(k)) + + @classmethod + def convert_with_links(cls, rpc_nodes, expand=True): + minimum_fields = ['id', 'name', 'administrative_state', + 'operational_state', 'availability_status', + 'ready_state'] + fields = minimum_fields if not expand else None + nodes = Nodes.from_rpc_object( + rpc_nodes, fields) + + return nodes + + +class NodesCollection(collection.Collection): + """API representation of a collection of nodes.""" + + nodes = [Nodes] + "A list containing nodes objects" + + def __init__(self, **kwargs): + self._type = 'nodes' + + @classmethod + def convert_with_links(cls, nodes, limit, url=None, + expand=False, **kwargs): + collection = NodesCollection() + collection.nodes = [ + Nodes.convert_with_links(ch, expand) + for ch in nodes] + url = url or None + collection.next = collection.get_next(limit, url=url, **kwargs) + return collection + + +# class Nodess(wsme_types.Base): +# nodes = wsme_types.text +class NodesController(rest.RestController): + + def _get_nodes(self, marker, limit, sort_key, sort_dir): + + limit = utils.validate_limit(limit) + sort_dir = utils.validate_sort_dir(sort_dir) + marker_obj = None + if marker: + marker_obj = objects.sm_node.get_by_uuid( + pecan.request.context, marker) + + nodes = pecan.request.dbapi.sm_node_get_list(limit, + marker_obj, + sort_key=sort_key, + sort_dir=sort_dir) + return nodes + + @wsme_pecan.wsexpose(Nodes, unicode) + def get_one(self, uuid): + rpc_sg = objects.sm_node.get_by_uuid(pecan.request.context, uuid) + + return Nodes.convert_with_links(rpc_sg) + + @wsme_pecan.wsexpose(NodesCollection, unicode, int, + unicode, unicode) + def get_all(self, marker=None, limit=None, + sort_key='name', sort_dir='asc'): + """Retrieve list of nodes.""" + + nodes = self._get_nodes(marker, + limit, + sort_key, + sort_dir) + + return NodesCollection.convert_with_links(nodes, limit, + sort_key=sort_key, + sort_dir=sort_dir) + + @wsme_pecan.wsexpose(NodesCommandResult, unicode, + body=NodesCommand) + def put(self, hostname, command): + + raise NotImplementedError() + + @wsme_pecan.wsexpose(NodesCommandResult, unicode, + body=NodesCommand) + def patch(self, hostname, command): + + raise NotImplementedError() diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/service_groups.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/service_groups.py new file mode 100644 index 00000000..8cb8edab --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/service_groups.py @@ -0,0 +1,164 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import json +import wsme +from wsme import types as wsme_types +import wsmeext.pecan as wsme_pecan +import pecan +from pecan import rest + +from sm_api.api.controllers.v1 import base +from sm_api.api.controllers.v1 import collection +from sm_api.api.controllers.v1 import link +from sm_api.api.controllers.v1 import utils + +from sm_api.common import log +from sm_api import objects + + +LOG = log.get_logger(__name__) + + +class ServiceGroupCommand(wsme_types.Base): + path = wsme_types.text + value = wsme_types.text + op = wsme_types.text + + +class ServiceGroupCommandResult(wsme_types.Base): + # Host Information + hostname = wsme_types.text + state = wsme_types.text + # Command + path = wsme_types.text + value = wsme_types.text + op = wsme_types.text + # Result + error_code = wsme_types.text + error_details = wsme_types.text + + +class ServiceGroup(base.APIBase): + name = wsme_types.text + state = wsme_types.text + status = wsme_types.text + + # JKUNG new + uuid = wsme_types.text + "The UUID of the service_groups" + + id = int + + links = [link.Link] + "A list containing a self link and associated service_groups links" + + def __init__(self, **kwargs): + self.fields = objects.service_groups.fields.keys() + for k in self.fields: + setattr(self, k, kwargs.get(k)) + + @classmethod + def convert_with_links(cls, rpc_service_groups, expand=True): + minimum_fields = ['id', 'name', 'state', 'status'] + fields = minimum_fields if not expand else None + service_groups = ServiceGroup.from_rpc_object( + rpc_service_groups, fields) + + return service_groups + + +class ServiceGroupCollection(collection.Collection): + """API representation of a collection of service_groups.""" + + service_groups = [ServiceGroup] + "A list containing service_groups objects" + + def __init__(self, **kwargs): + self._type = 'service_groups' + + @classmethod + def convert_with_links(cls, service_groups, limit, url=None, + expand=False, **kwargs): + collection = ServiceGroupCollection() + collection.service_groups = [ + ServiceGroup.convert_with_links(ch, expand) + for ch in service_groups] + url = url or None + collection.next = collection.get_next(limit, url=url, **kwargs) + return collection + + +class ServiceGroups(wsme_types.Base): + service_groups = wsme_types.text + + +class ServiceGroupController(rest.RestController): + + def _get_service_groups(self, marker, limit, sort_key, sort_dir): + + limit = utils.validate_limit(limit) + sort_dir = utils.validate_sort_dir(sort_dir) + marker_obj = None + if marker: + marker_obj = objects.service_groups.get_by_uuid( + pecan.request.context, marker) + + service_groups = pecan.request.dbapi.iservicegroup_get_list(limit, + marker_obj, + sort_key=sort_key, + sort_dir=sort_dir) + return service_groups + + @wsme_pecan.wsexpose(ServiceGroup, unicode) + def get_one(self, uuid): + rpc_sg = objects.service_groups.get_by_uuid(pecan.request.context, uuid) + + return ServiceGroup.convert_with_links(rpc_sg) + + @wsme_pecan.wsexpose(ServiceGroupCollection, unicode, int, + unicode, unicode) + def get_all(self, marker=None, limit=None, + sort_key='name', sort_dir='asc'): + """Retrieve list of servicegroups.""" + + service_groups = self._get_service_groups(marker, + limit, + sort_key, + sort_dir) + + return ServiceGroupCollection.convert_with_links(service_groups, limit, + sort_key=sort_key, + sort_dir=sort_dir) + + # cursor = pecan.request.database.cursor() + + # cursor.execute("SELECT name, state from service_groups") + + # data = cursor.fetchall() + + # if data is not None: + # service_groups = [] + + # for row in data: + # service_groups.append({'name': row[0], 'state': row[1]}) + + # return ServiceGroups(service_groups=json.dumps(service_groups)) + + #return wsme.api.Response(ServiceGroups(service_groups=json.dumps([])), + # status_code=404) + + @wsme_pecan.wsexpose(ServiceGroupCommandResult, unicode, + body=ServiceGroupCommand) + def put(self, hostname, command): + + raise NotImplementedError() + + @wsme_pecan.wsexpose(ServiceGroupCommandResult, unicode, + body=ServiceGroupCommand) + def patch(self, hostname, command): + + raise NotImplementedError() diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/servicenode.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/servicenode.py new file mode 100755 index 00000000..67ccaa48 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/servicenode.py @@ -0,0 +1,447 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import pecan +from pecan import rest +import wsme +from wsme import types as wtypes +import wsmeext.pecan as wsme_pecan + +from sm_api.api.controllers.v1 import base +from sm_api.api.controllers.v1 import smc_api +from sm_api.openstack.common import log + +LOG = log.getLogger(__name__) + +ERR_CODE_SUCCESS = "0" +ERR_CODE_HOST_NOT_FOUND = "-1000" +ERR_CODE_ACTION_FAILED = "-1001" +ERR_CODE_NO_HOST_TO_SWACT_TO = "-1002" + +SM_NODE_STATE_UNKNOWN = "unknown" +SM_NODE_ADMIN_LOCKED = "locked" +SM_NODE_ADMIN_UNLOCKED = "unlocked" +SM_NODE_OPER_ENABLED = "enabled" +SM_NODE_OPER_DISABLED = "disabled" +SM_NODE_AVAIL_AVAILABLE = "available" +SM_NODE_AVAIL_DEGRADED = "degraded" +SM_NODE_AVAIL_FAILED = "failed" + +# sm_types.c +SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_NIL = "nil" +SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_UNKNOWN = "unknown" +SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_NONE = "none" +SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N = "N" +SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_PLUS_M = "N + M" +SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_TO_1 = "N to 1" +SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_TO_N = "N to N" + +# sm_types.c +SM_SERVICE_GROUP_STATE_NIL = "nil" +SM_SERVICE_GROUP_STATE_NA = "not-applicable" +SM_SERVICE_GROUP_STATE_INITIAL = "initial" +SM_SERVICE_GROUP_STATE_UNKNOWN = "unknown" +SM_SERVICE_GROUP_STATE_STANDBY = "standby" +SM_SERVICE_GROUP_STATE_GO_STANDBY = "go-standby" +SM_SERVICE_GROUP_STATE_GO_ACTIVE = "go-active" +SM_SERVICE_GROUP_STATE_ACTIVE = "active" +SM_SERVICE_GROUP_STATE_DISABLING = "disabling" +SM_SERVICE_GROUP_STATE_DISABLED = "disabled" +SM_SERVICE_GROUP_STATE_SHUTDOWN = "shutdown" + +# sm_types.c +SM_SERVICE_GROUP_STATUS_NIL = "nil" +SM_SERVICE_GROUP_STATUS_NONE = "" +SM_SERVICE_GROUP_STATUS_WARN = "warn" +SM_SERVICE_GROUP_STATUS_DEGRADED = "degraded" +SM_SERVICE_GROUP_STATUS_FAILED = "failed" + +# sm_types.c +SM_SERVICE_GROUP_CONDITION_NIL = "nil" +SM_SERVICE_GROUP_CONDITION_NONE = "" +SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT = "data-inconsistent" +SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED = "data-outdated" +SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT = "data-consistent" +SM_SERVICE_GROUP_CONDITION_DATA_SYNC = "data-syncing" +SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE = "data-standalone" +SM_SERVICE_GROUP_CONDITION_RECOVERY_FAILURE = "recovery-failure" +SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE = "action-failure" +SM_SERVICE_GROUP_CONDITION_FATAL_FAILURE = "fatal-failure" + + +class ServiceNodeCommand(base.APIBase): + origin = wtypes.text + action = wtypes.text # swact | swact-force | unlock | lock | event + admin = wtypes.text # locked | unlocked + oper = wtypes.text # enabled | disabled + avail = wtypes.text # none | ... + + +class ServiceNodeCommandResult(base.APIBase): + # Origin and Host Information + origin = wtypes.text # e.g. "mtce" or "sm" + hostname = wtypes.text + # Command + action = wtypes.text + admin = wtypes.text + oper = wtypes.text + avail = wtypes.text + # Result + error_code = wtypes.text + error_details = wtypes.text + + +class ServiceNode(base.APIBase): + origin = wtypes.text + hostname = wtypes.text + admin = wtypes.text + oper = wtypes.text + avail = wtypes.text + active_services = wtypes.text + swactable_services = wtypes.text + + +class ServiceNodeController(rest.RestController): + + def __init__(self, from_isystem=False): + self._seqno = 0 + + def _seqno_incr_get(self): + self._seqno += 1 + return self._seqno + + def _seqno_get(self): + return self._seqno + + def _get_current_sm_sdas(self): + sm_sdas = pecan.request.dbapi.sm_sda_get_list() + for sm in sm_sdas: + LOG.debug("sm-api sm_sdas= %s" % sm.as_dict()) + + return sm_sdas + + def _sm_sdm_get(self, server, service_group_name): + return pecan.request.dbapi.sm_sdm_get(server, service_group_name) + + def _smc_node_exists(self, hostname): + # check whether hostname exists in nodes table + node_exists = False + sm_nodes = pecan.request.dbapi.sm_node_get_by_name(hostname) + for sm_node in sm_nodes: + node_exists = True + + return node_exists + + def _get_sm_node_state(self, hostname): + sm_nodes = pecan.request.dbapi.sm_node_get_by_name(hostname) + + # default values + node_state = {'hostname': hostname, + 'admin': SM_NODE_STATE_UNKNOWN, + 'oper': SM_NODE_STATE_UNKNOWN, + 'avail': SM_NODE_STATE_UNKNOWN} + + for sm_node in sm_nodes: + node_state = {'hostname': hostname, + 'admin': sm_node.administrative_state, + 'oper': sm_node.operational_state, + 'avail': sm_node.availability_status} + break + + LOG.debug("sm-api get_sm_node_state hostname: %s" % (node_state)) + return node_state + + def _have_active_sm_services(self, hostname, sm_sdas): + # check db service_domain_assignments for any "active" + # in either state or desired state: + active_sm_services = False + + # active: current or transition state + active_attr_list = [SM_SERVICE_GROUP_STATE_ACTIVE, + SM_SERVICE_GROUP_STATE_GO_ACTIVE, + SM_SERVICE_GROUP_STATE_GO_STANDBY, + SM_SERVICE_GROUP_STATE_DISABLING, + SM_SERVICE_GROUP_STATE_UNKNOWN] + + for sm_sda in sm_sdas: + if sm_sda.node_name == hostname: + for aa in active_attr_list: + if sm_sda.state == aa or sm_sda.desired_state == aa: + active_sm_services = True + LOG.debug("sm-api have_active_sm_services True") + return active_sm_services + + LOG.debug("sm-api have_active_sm_services: False") + return active_sm_services + + def _have_swactable_sm_services(self, hostname, sm_sdas): + # check db service_domain_assignments for any "active" + # in either state or desired state: + swactable_sm_services = False + + # active: current or transition state + active_attr_list = [SM_SERVICE_GROUP_STATE_ACTIVE, + SM_SERVICE_GROUP_STATE_GO_ACTIVE, + SM_SERVICE_GROUP_STATE_GO_STANDBY, + SM_SERVICE_GROUP_STATE_DISABLING, + SM_SERVICE_GROUP_STATE_UNKNOWN] + + for sm_sda in sm_sdas: + if sm_sda.node_name == hostname: + for aa in active_attr_list: + if sm_sda.state == aa or sm_sda.desired_state == aa: + sdm = self._sm_sdm_get(sm_sda.name, + sm_sda.service_group_name) + if sdm.redundancy_model == \ + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_PLUS_M: + swactable_sm_services = True + LOG.debug("sm-api have_swactable_sm_services True") + return swactable_sm_services + + LOG.debug("sm-api have_active_sm_services: False") + return swactable_sm_services + + def _swact_pre_check(self, hostname): + # run pre-swact checks, verify that services are in the right state + # to accept service + have_destination = False + check_result = None + + sm_sdas = pecan.request.dbapi.sm_sda_get_list(None, None, + sort_key='name', + sort_dir='asc') + + origin_state = self._collect_svc_state(sm_sdas, hostname) + + for sm_sda in sm_sdas: + if sm_sda.node_name != hostname: + have_destination = True + + # Verify that target host state is unlocked-enabled + node_state = self._get_sm_node_state(sm_sda.node_name) + if SM_NODE_ADMIN_LOCKED == node_state['admin']: + check_result = ("%s is not ready to take service, " + "%s is locked" + % (sm_sda.node_name, sm_sda.node_name)) + break + + if SM_NODE_OPER_DISABLED == node_state['oper']: + check_result = ("%s is not ready to take service, " + "%s is disabled" + % (sm_sda.node_name, sm_sda.node_name)) + break + + # Verify that + # all the services are in the standby or active + # state on the other host + # or service only provisioned in the other host + # or service state are the same on both hosts + if SM_SERVICE_GROUP_STATE_ACTIVE != sm_sda.state \ + and SM_SERVICE_GROUP_STATE_STANDBY != sm_sda.state \ + and origin_state.has_key(sm_sda.service_group_name) \ + and origin_state[sm_sda.service_group_name] != sm_sda.state: + check_result = ( + "%s on %s is not ready to take service, " + "service not in the active or standby " + "state" % (sm_sda.service_group_name, + sm_sda.node_name)) + break + + # Verify that all the services are in the desired state on + # the other host + if sm_sda.desired_state != sm_sda.state: + check_result = ("%s on %s is not ready to take service, " + "services transitioning state" + % (sm_sda.service_group_name, + sm_sda.node_name)) + break + + # Verify that all the services are ready to accept service + # i.e. not failed or syncing data + if SM_SERVICE_GROUP_STATUS_FAILED == sm_sda.status: + check_result = ("%s on %s is not ready to take service, " + "service is failed" + % (sm_sda.service_group_name, + sm_sda.node_name)) + break + + elif SM_SERVICE_GROUP_STATUS_DEGRADED == sm_sda.status: + degraded_conditions \ + = [SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT, + SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED, + SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT, + SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE] + + if sm_sda.condition == SM_SERVICE_GROUP_CONDITION_DATA_SYNC: + check_result = ("%s on %s is not ready to take " + "service, service is syncing data" + % (sm_sda.service_group_name, + sm_sda.node_name)) + break + + elif sm_sda.condition in degraded_conditions: + check_result = ("%s on %s is not ready to take " + "service, service is degraded, %s" + % (sm_sda.service_group_name, + sm_sda.node_name, sm_sda.condition)) + break + else: + check_result = ("%s on %s is not ready to take " + "service, service is degraded" + % (sm_sda.service_group_name, + sm_sda.node_name)) + break + + if check_result is None and not have_destination: + check_result = "no peer available" + + if check_result is not None: + LOG.info("swact pre-check failed host %s, reason=%s." + % (hostname, check_result)) + + return check_result + + @staticmethod + def _collect_svc_state(sm_sdas, hostname): + sm_state_ht = {} + for sm_sda in sm_sdas: + if sm_sda.node_name == hostname: + sm_state_ht[sm_sda.service_group_name] = sm_sda.state + LOG.info("%s" % sm_state_ht) + return sm_state_ht + + def _do_modify_command(self, hostname, command): + + if command.action == smc_api.SM_NODE_ACTION_SWACT_PRE_CHECK or \ + command.action == smc_api.SM_NODE_ACTION_SWACT: + check_result = self._swact_pre_check(hostname) + if check_result is not None: + result = ServiceNodeCommandResult( + origin="sm", hostname=hostname, action=command.action, + admin=command.admin, oper=command.oper, + avail=command.avail, error_code=ERR_CODE_ACTION_FAILED, + error_details=check_result) + + if command.action == smc_api.SM_NODE_ACTION_SWACT_PRE_CHECK: + return wsme.api.Response(result, status_code=200) + return wsme.api.Response(result, status_code=400) + + elif command.action == smc_api.SM_NODE_ACTION_SWACT_PRE_CHECK: + result = ServiceNodeCommandResult( + origin="sm", hostname=hostname, action=command.action, + admin=command.admin, oper=command.oper, + avail=command.avail, error_code=ERR_CODE_SUCCESS, + error_details=check_result) + return wsme.api.Response(result, status_code=200) + + if command.action == smc_api.SM_NODE_ACTION_UNLOCK or \ + command.action == smc_api.SM_NODE_ACTION_LOCK or \ + command.action == smc_api.SM_NODE_ACTION_SWACT or \ + command.action == smc_api.SM_NODE_ACTION_SWACT_FORCE or \ + command.action == smc_api.SM_NODE_ACTION_EVENT: + + sm_ack_dict = smc_api.sm_api_set_node_state(command.origin, + hostname, + command.action, + command.admin, + command.avail, + command.oper, + self._seqno_incr_get()) + + ack_admin = sm_ack_dict['SM_API_MSG_NODE_ADMIN'].lower() + ack_oper = sm_ack_dict['SM_API_MSG_NODE_OPER'].lower() + ack_avail = sm_ack_dict['SM_API_MSG_NODE_AVAIL'].lower() + + LOG.debug("sm-api _do_modify_command sm_ack_dict: %s ACK admin: " + "%s oper: %s avail: %s." % (sm_ack_dict, ack_admin, + ack_oper, ack_avail)) + + # loose check on admin and oper only + if (command.admin == ack_admin) and (command.oper == ack_oper): + return ServiceNodeCommandResult( + origin=sm_ack_dict['SM_API_MSG_ORIGIN'], + hostname=sm_ack_dict['SM_API_MSG_NODE_NAME'], + action=sm_ack_dict['SM_API_MSG_NODE_ACTION'], + admin=ack_admin, + oper=ack_oper, + avail=ack_avail, + error_code=ERR_CODE_SUCCESS, + error_msg="success") + else: + result = ServiceNodeCommandResult( + origin="sm", + hostname=hostname, + action=sm_ack_dict['SM_API_MSG_NODE_ACTION'], + admin=ack_admin, + oper=ack_oper, + avail=ack_avail, + error_code=ERR_CODE_ACTION_FAILED, + error_details="action failed") + + return wsme.api.Response(result, status_code=500) + else: + raise wsme.exc.InvalidInput('action', command.action, "unknown") + + @wsme_pecan.wsexpose(ServiceNode, unicode) + def get_one(self, hostname): + + try: + data = self._get_sm_node_state(hostname) + except: + LOG.exception("No entry in database for %s:" % hostname) + return ServiceNode(origin="sm", + hostname=hostname, + admin=SM_NODE_STATE_UNKNOWN, + oper=SM_NODE_STATE_UNKNOWN, + avail=SM_NODE_STATE_UNKNOWN, + active_services="unknown", + swactable_services="unknown") + + sm_sdas = self._get_current_sm_sdas() + + if self._have_active_sm_services(hostname, sm_sdas): + active_services = "yes" + else: + active_services = "no" + + if self._have_swactable_sm_services(hostname, sm_sdas): + swactable_services = "yes" + else: + swactable_services = "no" + + return ServiceNode(origin="sm", + hostname=data['hostname'], + admin=data['admin'], + oper=data['oper'], + avail=data['avail'], + active_services=active_services, + swactable_services=swactable_services) + + @wsme_pecan.wsexpose(ServiceNodeCommandResult, unicode, + body=ServiceNodeCommand) + def patch(self, hostname, command): + + if command.origin != "mtce" and command.origin != "sysinv": + LOG.warn("sm-api unexpected origin: %s. Continuing." + % command.origin) + + return self._do_modify_command(hostname, command) diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/services.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/services.py new file mode 100644 index 00000000..e38393cc --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/services.py @@ -0,0 +1,144 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import json +import wsme +from wsme import types as wsme_types +import wsmeext.pecan as wsme_pecan +import pecan +from pecan import rest + +from sm_api.api.controllers.v1 import base +from sm_api.api.controllers.v1 import collection +from sm_api.api.controllers.v1 import link +from sm_api.api.controllers.v1 import utils + +from sm_api.common import log +from sm_api import objects + + +LOG = log.get_logger(__name__) + + +class ServicesCommand(wsme_types.Base): + path = wsme_types.text + value = wsme_types.text + op = wsme_types.text + + +class ServicesCommandResult(wsme_types.Base): + # Host Information + hostname = wsme_types.text + state = wsme_types.text + # Command + path = wsme_types.text + value = wsme_types.text + op = wsme_types.text + # Result + error_code = wsme_types.text + error_details = wsme_types.text + + +class Services(base.APIBase): + id = int + name = wsme_types.text + desired_state = wsme_types.text + state = wsme_types.text + status = wsme_types.text + + # online_uuid = wsme_types.text + # "The UUID of the services" + + links = [link.Link] + "A list containing a self link and associated services links" + + def __init__(self, **kwargs): + self.fields = objects.service.fields.keys() + for k in self.fields: + setattr(self, k, kwargs.get(k)) + + @classmethod + def convert_with_links(cls, rpc_services, expand=True): + minimum_fields = ['id', 'name', 'desired_state', 'state', 'status'] + fields = minimum_fields if not expand else None + services = Services.from_rpc_object( + rpc_services, fields) + + return services + + +class ServicesCollection(collection.Collection): + """API representation of a collection of services.""" + + services = [Services] + "A list containing services objects" + + def __init__(self, **kwargs): + self._type = 'services' + + @classmethod + def convert_with_links(cls, services, limit, url=None, + expand=False, **kwargs): + collection = ServicesCollection() + collection.services = [ + Services.convert_with_links(ch, expand) + for ch in services] + url = url or None + collection.next = collection.get_next(limit, url=url, **kwargs) + return collection + + +# class Servicess(wsme_types.Base): +# services = wsme_types.text +class ServicesController(rest.RestController): + + def _get_services(self, marker, limit, sort_key, sort_dir): + + limit = utils.validate_limit(limit) + sort_dir = utils.validate_sort_dir(sort_dir) + marker_obj = None + if marker: + marker_obj = objects.service.get_by_uuid( + pecan.request.context, marker) + + services = pecan.request.dbapi.sm_service_get_list(limit, + marker_obj, + sort_key=sort_key, + sort_dir=sort_dir) + return services + + @wsme_pecan.wsexpose(Services, unicode) + def get_one(self, uuid): + rpc_sg = objects.service.get_by_uuid(pecan.request.context, uuid) + + return Services.convert_with_links(rpc_sg) + + @wsme_pecan.wsexpose(ServicesCollection, unicode, int, + unicode, unicode) + def get_all(self, marker=None, limit=None, + sort_key='name', sort_dir='asc'): + """Retrieve list of services.""" + + services = self._get_services(marker, + limit, + sort_key, + sort_dir) + + return ServicesCollection.convert_with_links(services, limit, + sort_key=sort_key, + sort_dir=sort_dir) + + @wsme_pecan.wsexpose(ServicesCommandResult, unicode, + body=ServicesCommand) + def put(self, hostname, command): + + raise NotImplementedError() + + @wsme_pecan.wsexpose(ServicesCommandResult, unicode, + body=ServicesCommand) + def patch(self, hostname, command): + + raise NotImplementedError() diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/sm_sda.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/sm_sda.py new file mode 100755 index 00000000..42707213 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/sm_sda.py @@ -0,0 +1,162 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import json +import wsme +from wsme import types as wsme_types +import wsmeext.pecan as wsme_pecan +import pecan +from pecan import rest + +from sm_api.api.controllers.v1 import base +from sm_api.api.controllers.v1 import collection +from sm_api.api.controllers.v1 import link +from sm_api.api.controllers.v1 import utils + +from sm_api.common import log +from sm_api import objects + + +LOG = log.get_logger(__name__) + + +class SmSdaCommand(wsme_types.Base): + path = wsme_types.text + value = wsme_types.text + op = wsme_types.text + + +class SmSdaCommandResult(wsme_types.Base): + # Host Information + hostname = wsme_types.text + state = wsme_types.text + # Command + path = wsme_types.text + value = wsme_types.text + op = wsme_types.text + # Result + error_code = wsme_types.text + error_details = wsme_types.text + + +class SmSda(base.APIBase): + id = int + uuid = wsme_types.text + "The UUID of the sm_sda" + + name = wsme_types.text + node_name = wsme_types.text + service_group_name = wsme_types.text + state = wsme_types.text + desired_state = wsme_types.text + status = wsme_types.text + condition = wsme_types.text + + links = [link.Link] + "A list containing a self link and associated sm_sda links" + + def __init__(self, **kwargs): + self.fields = objects.sm_sda.fields.keys() + for k in self.fields: + setattr(self, k, kwargs.get(k)) + + @classmethod + def convert_with_links(cls, rpc_sm_sda, expand=True): + minimum_fields = ['id', 'uuid', 'name', 'node_name', + 'service_group_name', 'desired_state', + 'state', 'status', 'condition'] + fields = minimum_fields if not expand else None + sm_sda = SmSda.from_rpc_object( + rpc_sm_sda, fields) + + return sm_sda + + +class SmSdaCollection(collection.Collection): + """API representation of a collection of sm_sda.""" + + sm_sda = [SmSda] + "A list containing sm_sda objects" + + def __init__(self, **kwargs): + self._type = 'sm_sda' + + @classmethod + def convert_with_links(cls, sm_sda, limit, url=None, + expand=False, **kwargs): + collection = SmSdaCollection() + collection.sm_sda = [ + SmSda.convert_with_links(ch, expand) + for ch in sm_sda] + url = url or None + collection.next = collection.get_next(limit, url=url, **kwargs) + return collection + + +class SmSdas(wsme_types.Base): + sm_sda = wsme_types.text + + +class SmSdaController(rest.RestController): + + def _get_sm_sda(self, marker, limit, sort_key, sort_dir): + + limit = utils.validate_limit(limit) + sort_dir = utils.validate_sort_dir(sort_dir) + marker_obj = None + if marker: + marker_obj = objects.sm_sda.get_by_uuid(pecan.request.context, + marker) + + sm_sdas = pecan.request.dbapi.sm_sda_get_list(limit, + marker_obj, + sort_key=sort_key, + sort_dir=sort_dir) + + # Remap OpenStack_Services to Cloud_Services + for sm_sda in sm_sdas: + if sm_sda.service_group_name.lower() == "openstack_services": + sm_sda.service_group_name = "Cloud_Services" + + return sm_sdas + + @wsme_pecan.wsexpose(SmSda, unicode) + def get_one(self, uuid): + + rpc_sda = objects.sm_sda.get_by_uuid(pecan.request.context, uuid) + + # temp: remap OpenStack_Services to Cloud_Services + if rpc_sda.service_group_name.lower() == "openstack_services": + rpc_sda.service_group_name = "Cloud_Services" + + return SmSda.convert_with_links(rpc_sda) + + @wsme_pecan.wsexpose(SmSdaCollection, unicode, int, + unicode, unicode) + def get_all(self, marker=None, limit=None, + sort_key='name', sort_dir='asc'): + """Retrieve list of sm_sdas.""" + + sm_sda = self._get_sm_sda(marker, + limit, + sort_key, + sort_dir) + + return SmSdaCollection.convert_with_links(sm_sda, limit, + sort_key=sort_key, + sort_dir=sort_dir) + + @wsme_pecan.wsexpose(SmSdaCommandResult, unicode, + body=SmSdaCommand) + def put(self, hostname, command): + + raise NotImplementedError() + + @wsme_pecan.wsexpose(SmSdaCommandResult, unicode, + body=SmSdaCommand) + def patch(self, hostname, command): + + raise NotImplementedError() diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/smc_api.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/smc_api.py new file mode 100755 index 00000000..42853085 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/smc_api.py @@ -0,0 +1,160 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import os +import socket + +from sm_api.openstack.common import log + + +LOG = log.getLogger(__name__) + +SM_API_SERVER_ADDR = "/tmp/.sm_server_api" +SM_API_CLIENT_ADDR = "/tmp/.sm_client_api" + +SM_API_MSG_VERSION = "1" +SM_API_MSG_REVISION = "1" +SM_API_MSG_TYPE_SET_NODE = "SET_NODE" +SM_API_MSG_TYPE_SET_NODE_ACK = "SET_NODE_ACK" + +SM_API_MSG_NODE_ADMINSTATE_LOCK = "LOCK" +SM_API_MSG_NODE_ADMINSTATE_UNLOCK = "UNLOCK" + +# offsets +SM_API_MSG_VERSION_FIELD = 0 +SM_API_MSG_REVISION_FIELD = 1 +SM_API_MSG_SEQNO_FIELD = 2 +SM_API_MSG_TYPE_FIELD = 3 +SM_API_MSG_ORIGIN_FIELD = 4 +SM_API_MSG_NODE_NAME_FIELD = 5 +SM_API_MSG_NODE_ACTION_FIELD = 6 +SM_API_MSG_NODE_ADMIN_FIELD = 7 +SM_API_MSG_NODE_OPER_FIELD = 8 +SM_API_MSG_NODE_AVAIL_FIELD = 9 +SM_API_MAX_MSG_SIZE = 2048 + +SM_NODE_ACTION_UNLOCK = "unlock" +SM_NODE_ACTION_LOCK = "lock" +SM_NODE_ACTION_SWACT_PRE_CHECK = "swact-pre-check" +SM_NODE_ACTION_SWACT = "swact" +SM_NODE_ACTION_SWACT_FORCE = "swact-force" +SM_NODE_ACTION_EVENT = "event" + + +def sm_api_notify(sm_dict): + + sm_ack_dict = {} + + sm_buf_dict = {'SM_API_MSG_VERSION': SM_API_MSG_VERSION, + 'SM_API_MSG_REVISION': SM_API_MSG_REVISION} + + sm_buf_dict.update(sm_dict) + sm_buf = ("%s,%s,%i,%s,%s,%s,%s,%s,%s,%s" % ( + sm_buf_dict['SM_API_MSG_VERSION'], + sm_buf_dict['SM_API_MSG_REVISION'], + sm_buf_dict['SM_API_MSG_SEQNO'], + sm_buf_dict['SM_API_MSG_TYPE'], + sm_buf_dict['SM_API_MSG_ORIGIN'], + sm_buf_dict['SM_API_MSG_NODE_NAME'], + sm_buf_dict['SM_API_MSG_NODE_ACTION'], + sm_buf_dict['SM_API_MSG_NODE_ADMIN'], + sm_buf_dict['SM_API_MSG_NODE_OPER'], + sm_buf_dict['SM_API_MSG_NODE_AVAIL'])) + + LOG.debug("sm-api buffer to SM API: %s" % sm_buf) + + # notify SM + s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + try: + if os.path.exists(SM_API_CLIENT_ADDR): + os.unlink(SM_API_CLIENT_ADDR) + + s.setblocking(1) # blocking, timeout must be specified + s.settimeout(6) # give sm a few secs to respond + s.bind(SM_API_CLIENT_ADDR) + s.sendto(sm_buf, SM_API_SERVER_ADDR) + + count = 0 + while count < 5: + count += 1 + sm_ack = s.recv(1024) + + try: + sm_ack_list = sm_ack.split(",") + if sm_ack_list[SM_API_MSG_SEQNO_FIELD] == \ + str(sm_buf_dict['SM_API_MSG_SEQNO']): + break + else: + LOG.debug(_("sm-api mismatch seqno tx message: %s rx message: %s " % (sm_buf, sm_ack))) + except: + LOG.exception(_("sm-api bad rx message: %s" % sm_ack)) + + except socket.error, e: + LOG.exception(_("sm-api socket error: %s on %s") % (e, sm_buf)) + sm_ack_dict = { + 'SM_API_MSG_TYPE': "unknown_set_node", + 'SM_API_MSG_NODE_ACTION': sm_dict['SM_API_MSG_NODE_ACTION'], + 'SM_API_MSG_ORIGIN': "sm", + 'SM_API_MSG_NODE_NAME': sm_dict['SM_API_MSG_NODE_NAME'], + 'SM_API_MSG_NODE_ADMIN': "unknown", + 'SM_API_MSG_NODE_OPER': "unknown", + 'SM_API_MSG_NODE_AVAIL': "unknown"} + + return sm_ack_dict + + finally: + s.close() + if os.path.exists(SM_API_CLIENT_ADDR): + os.unlink(SM_API_CLIENT_ADDR) + + LOG.debug("sm-api set node state sm_ack %s " % sm_ack) + try: + sm_ack_list = sm_ack.split(",") + sm_ack_dict = { + 'SM_API_MSG_VERSION': sm_ack_list[SM_API_MSG_VERSION_FIELD], + 'SM_API_MSG_REVISION': sm_ack_list[SM_API_MSG_REVISION_FIELD], + 'SM_API_MSG_SEQNO': sm_ack_list[SM_API_MSG_SEQNO_FIELD], + 'SM_API_MSG_TYPE': sm_ack_list[SM_API_MSG_TYPE_FIELD], + 'SM_API_MSG_NODE_ACTION': sm_ack_list[SM_API_MSG_NODE_ACTION_FIELD], + + 'SM_API_MSG_ORIGIN': sm_ack_list[SM_API_MSG_ORIGIN_FIELD], + 'SM_API_MSG_NODE_NAME': sm_ack_list[SM_API_MSG_NODE_NAME_FIELD], + 'SM_API_MSG_NODE_ADMIN': sm_ack_list[SM_API_MSG_NODE_ADMIN_FIELD], + 'SM_API_MSG_NODE_OPER': sm_ack_list[SM_API_MSG_NODE_OPER_FIELD], + 'SM_API_MSG_NODE_AVAIL': sm_ack_list[SM_API_MSG_NODE_AVAIL_FIELD] + } + except: + LOG.exception(_("sm-api ack message error: %s" % sm_ack)) + sm_ack_dict = { + 'SM_API_MSG_TYPE': "unknown_set_node", + + 'SM_API_MSG_ORIGIN': "sm", + 'SM_API_MSG_NODE_NAME': sm_dict['SM_API_MSG_NODE_NAME'], + 'SM_API_MSG_NODE_ADMIN': "unknown", + 'SM_API_MSG_NODE_OPEsR': "unknown", + 'SM_API_MSG_NODE_AVAIL': "unknown" + } + + return sm_ack_dict + + +def sm_api_set_node_state(origin, hostname, action, admin, avail, oper, seqno): + sm_ack_dict = {} + sm_dict = {'SM_API_MSG_TYPE': SM_API_MSG_TYPE_SET_NODE, + + 'SM_API_MSG_ORIGIN': origin, + 'SM_API_MSG_NODE_NAME': hostname, + + 'SM_API_MSG_NODE_ACTION': action, + 'SM_API_MSG_NODE_ADMIN': admin, + 'SM_API_MSG_NODE_OPER': oper, + 'SM_API_MSG_NODE_AVAIL': avail, + 'SM_API_MSG_SEQNO': seqno, + } + + sm_ack_dict = sm_api_notify(sm_dict) + + return sm_ack_dict diff --git a/service-mgmt-api/sm-api/sm_api/api/controllers/v1/utils.py b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/utils.py new file mode 100644 index 00000000..32606f30 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/controllers/v1/utils.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import jsonpatch +import re +import wsme + +from oslo_config import cfg + +CONF = cfg.CONF + + +JSONPATCH_EXCEPTIONS = (jsonpatch.JsonPatchException, + jsonpatch.JsonPointerException, + KeyError) + + +def validate_limit(limit): + if limit and limit < 0: + raise wsme.exc.ClientSideError(_("Limit must be positive")) + + return min(CONF.api_limit_max, limit) or CONF.api_limit_max + + +def validate_sort_dir(sort_dir): + if sort_dir not in ['asc', 'desc']: + raise wsme.exc.ClientSideError(_("Invalid sort direction: %s. " + "Acceptable values are " + "'asc' or 'desc'") % sort_dir) + return sort_dir + + +def validate_patch(patch): + """Performs a basic validation on patch.""" + + if not isinstance(patch, list): + patch = [patch] + + for p in patch: + path_pattern = re.compile("^/[a-zA-Z0-9-_]+(/[a-zA-Z0-9-_]+)*$") + + if not isinstance(p, dict) or \ + any(key for key in ["path", "op"] if key not in p): + raise wsme.exc.ClientSideError(_("Invalid patch format: %s") + % str(p)) + + path = p["path"] + op = p["op"] + + if op not in ["add", "replace", "remove"]: + raise wsme.exc.ClientSideError(_("Operation not supported: %s") + % op) + + if not path_pattern.match(path): + raise wsme.exc.ClientSideError(_("Invalid path: %s") % path) + + if op == "add": + if path.count('/') == 1: + raise wsme.exc.ClientSideError(_("Adding an additional " + "attribute (%s) to the " + "resource is not allowed") + % path) + + +class ValidTypes(wsme.types.UserType): + """User type for validate that value has one of a few types.""" + + def __init__(self, *types): + self.types = types + + def validate(self, value): + for t in self.types: + if t is wsme.types.text and isinstance(value, wsme.types.bytes): + value = value.decode() + if isinstance(value, t): + return value + else: + raise ValueError("Wrong type. Expected '%s', got '%s'" % ( + self.types, type(value))) diff --git a/service-mgmt-api/sm-api/sm_api/api/hooks.py b/service-mgmt-api/sm-api/sm_api/api/hooks.py new file mode 100644 index 00000000..17490aad --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/hooks.py @@ -0,0 +1,98 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +""" +Hooks +""" + +import sqlite3 +from pecan import hooks + +from sm_api.common import context +from sm_api.common import utils + +from sm_api.common import config +from sm_api.db import api as dbapi +from sm_api.openstack.common import policy + + + + +class ConfigHook(hooks.PecanHook): + def __init__(self): + super(ConfigHook, self).__init__() + + def before(self, state): + state.request.config = config.CONF + + +class DatabaseHook(hooks.PecanHook): + # JKUNG def __init__(self): + # super(DatabaseHook, self).__init__() + # self.database = sqlite3.connect(config.CONF['database']['database']) + + def before(self, state): + # state.request.database = self.database + state.request.dbapi = dbapi.get_instance() + + # def __del__(self): + # self.database.close() + + +class ContextHook(hooks.PecanHook): + """Configures a request context and attaches it to the request. + + The following HTTP request headers are used: + + X-User-Id or X-User: + Used for context.user_id. + + X-Tenant-Id or X-Tenant: + Used for context.tenant. + + X-Auth-Token: + Used for context.auth_token. + + X-Roles: + Used for setting context.is_admin flag to either True or False. + The flag is set to True, if X-Roles contains either an administrator + or admin substring. Otherwise it is set to False. + + """ + def __init__(self, public_api_routes): + self.public_api_routes = public_api_routes + super(ContextHook, self).__init__() + + def before(self, state): + user_id = state.request.headers.get('X-User-Id') + user_id = state.request.headers.get('X-User', user_id) + tenant = state.request.headers.get('X-Tenant-Id') + tenant = state.request.headers.get('X-Tenant', tenant) + domain_id = state.request.headers.get('X-User-Domain-Id') + domain_name = state.request.headers.get('X-User-Domain-Name') + auth_token = state.request.headers.get('X-Auth-Token', None) + creds = {'roles': state.request.headers.get('X-Roles', '').split(',')} + + is_admin = policy.check('is_admin', state.request.headers, creds) + + path = utils.safe_rstrip(state.request.path, '/') + is_public_api = path in self.public_api_routes + + state.request.context = context.RequestContext( + auth_token=auth_token, + user=user_id, + tenant=tenant, + domain_id=domain_id, + domain_name=domain_name, + is_admin=is_admin, + is_public_api=is_public_api) + + +class RPCHook(hooks.PecanHook): + """Attach the rpcapi object to the request so controllers can get to it.""" + + def before(self, state): + state.request.rpcapi = rpcapi.ConductorAPI() diff --git a/service-mgmt-api/sm-api/sm_api/api/middleware/__init__.py b/service-mgmt-api/sm-api/sm_api/api/middleware/__init__.py new file mode 100644 index 00000000..470b5601 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/middleware/__init__.py @@ -0,0 +1,19 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# -*- encoding: utf-8 -*- +# + +from sm_api.api.middleware import auth_token +from sm_api.api.middleware import parsable_error + + +ParsableErrorMiddleware = parsable_error.ParsableErrorMiddleware +AuthTokenMiddleware = auth_token.AuthTokenMiddleware + +__all__ = (ParsableErrorMiddleware, + AuthTokenMiddleware) diff --git a/service-mgmt-api/sm-api/sm_api/api/middleware/auth_token.py b/service-mgmt-api/sm-api/sm_api/api/middleware/auth_token.py new file mode 100644 index 00000000..0229a833 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/middleware/auth_token.py @@ -0,0 +1,34 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# -*- encoding: utf-8 -*- +# + +from keystonemiddleware import auth_token + +from sm_api.common import utils + + +class AuthTokenMiddleware(auth_token.AuthProtocol): + """A wrapper on Keystone auth_token middleware. + + Does not perform verification of authentication tokens + for public routes in the API. + + """ + def __init__(self, app, conf, public_api_routes=[]): + self.public_api_routes = set(public_api_routes) + + super(AuthTokenMiddleware, self).__init__(app, conf) + + def __call__(self, env, start_response): + path = utils.safe_rstrip(env.get('PATH_INFO'), '/') + + if path in self.public_api_routes: + return self.app(env, start_response) + + return super(AuthTokenMiddleware, self).__call__(env, start_response) diff --git a/service-mgmt-api/sm-api/sm_api/api/middleware/parsable_error.py b/service-mgmt-api/sm-api/sm_api/api/middleware/parsable_error.py new file mode 100644 index 00000000..1ee34519 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/api/middleware/parsable_error.py @@ -0,0 +1,95 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2012 New Dream Network, LLC (DreamHost) +# +# Author: Doug Hellmann +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +""" +Middleware to replace the plain text message body of an error +response with one formatted so the client can parse it. + +Based on pecan.middleware.errordocument +""" + +import json +import webob +from xml import etree as et + +from sm_api.openstack.common import log + +LOG = log.getLogger(__name__) + + +class ParsableErrorMiddleware(object): + """Replace error body with something the client can parse. + """ + def __init__(self, app): + self.app = app + + def __call__(self, environ, start_response): + # Request for this state, modified by replace_start_response() + # and used when an error is being reported. + state = {} + + def replacement_start_response(status, headers, exc_info=None): + """Overrides the default response to make errors parsable. + """ + try: + status_code = int(status.split(' ')[0]) + state['status_code'] = status_code + except (ValueError, TypeError): # pragma: nocover + raise Exception(( + 'ErrorDocumentMiddleware received an invalid ' + 'status %s' % status + )) + else: + if (state['status_code'] / 100) not in (2, 3): + # Remove some headers so we can replace them later + # when we have the full error message and can + # compute the length. + headers = [(h, v) + for (h, v) in headers + if h not in ('Content-Length', 'Content-Type') + ] + # Save the headers in case we need to modify them. + state['headers'] = headers + return start_response(status, headers, exc_info) + + app_iter = self.app(environ, replacement_start_response) + if (state['status_code'] / 100) not in (2, 3): + req = webob.Request(environ) + if (req.accept.best_match(['application/json', 'application/xml']) + == 'application/xml'): + try: + # simple check xml is valid + body = [et.ElementTree.tostring( + et.ElementTree.fromstring('' + + '\n'.join(app_iter) + + ''))] + except et.ElementTree.ParseError as err: + LOG.error('Error parsing HTTP response: %s' % err) + body = ['%s' % state['status_code'] + + ''] + state['headers'].append(('Content-Type', 'application/xml')) + else: + body = [json.dumps({'error_message': '\n'.join(app_iter)})] + state['headers'].append(('Content-Type', 'application/json')) + state['headers'].append(('Content-Length', len(body[0]))) + else: + body = app_iter + return body diff --git a/service-mgmt-api/sm-api/sm_api/cmd/__init__.py b/service-mgmt-api/sm-api/sm_api/cmd/__init__.py new file mode 100644 index 00000000..88837031 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/cmd/__init__.py @@ -0,0 +1,30 @@ +# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +# TODO(deva): move eventlet imports to sm_api.__init__ once we move to PBR +import os + +os.environ['EVENTLET_NO_GREENDNS'] = 'yes' + +import eventlet + +eventlet.monkey_patch(os=False) + +from sm_api.openstack.common import gettextutils +gettextutils.install('sm_api') diff --git a/service-mgmt-api/sm-api/sm_api/cmd/api.py b/service-mgmt-api/sm-api/sm_api/cmd/api.py new file mode 100644 index 00000000..bac1b924 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/cmd/api.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""The Service Management API.""" + +import logging +import os.path +import sys +import time + + +from oslo_config import cfg +from wsgiref import simple_server + +from sm_api.api import app +from sm_api.common import service as sm_api_service +from sm_api.openstack.common import log + +CONF = cfg.CONF + + +def get_handler_cls(): + cls = simple_server.WSGIRequestHandler + + # old-style class doesn't support super + class MyHandler(cls, object): + def address_string(self): + # In the future, we could provide a config option to allow reverse DNS lookup + return self.client_address[0] + + return MyHandler + + +def main(): + # Parse config file and command line options, then start logging + + # Periodically check every minute for want_sm_config + while os.path.exists("/etc/sm/.not_want_sm_config"): + time.sleep(60) + + sm_api_service.prepare_service(sys.argv) + + # Build and start the WSGI app + # host = CONF.sm_api_api_bind_ip + # port = CONF.sm_api_api_port + host = 'localhost' + port = 7777 + wsgi = simple_server.make_server(host, port, + app.VersionSelectorApplication(), + handler_class=get_handler_cls()) + + LOG = log.getLogger(__name__) + LOG.info(_("Serving on http://%(host)s:%(port)s") % + {'host': host, 'port': port}) + LOG.info(_("Configuration:")) + CONF.log_opt_values(LOG, logging.INFO) + + try: + wsgi.serve_forever() + except KeyboardInterrupt: + pass diff --git a/service-mgmt-api/sm-api/sm_api/common/__init__.py b/service-mgmt-api/sm-api/sm_api/common/__init__.py new file mode 100644 index 00000000..147b74f9 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/__init__.py @@ -0,0 +1,5 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# diff --git a/service-mgmt-api/sm-api/sm_api/common/config.py b/service-mgmt-api/sm-api/sm_api/common/config.py new file mode 100644 index 00000000..0ee0273b --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/config.py @@ -0,0 +1,34 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +""" +Configuration +""" + +import ConfigParser + +CONF = None + + +class Config(ConfigParser.ConfigParser): + def as_dict(self): + d = dict(self._sections) + for key in d: + d[key] = dict(self._defaults, **d[key]) + d[key].pop('__name__', None) + return d + + +def load(config_file): + """ Load the power management configuration + + Parameters: configuration file + """ + global CONF + + config = Config() + config.read(config_file) + CONF = config.as_dict() diff --git a/service-mgmt-api/sm-api/sm_api/common/context.py b/service-mgmt-api/sm-api/sm_api/common/context.py new file mode 100644 index 00000000..a70fd86b --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/context.py @@ -0,0 +1,45 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# -*- encoding: utf-8 -*- +# + +from sm_api.openstack.common import context + + +class RequestContext(context.RequestContext): + """Extends security contexts from the OpenStack common library.""" + + def __init__(self, auth_token=None, domain_id=None, domain_name=None, + user=None, tenant=None, is_admin=False, is_public_api=False, + read_only=False, show_deleted=False, request_id=None): + """Stores several additional request parameters: + + :param domain_id: The ID of the domain. + :param domain_name: The name of the domain. + :param is_public_api: Specifies whether the request should be processed + without authentication. + + """ + self.is_public_api = is_public_api + self.domain_id = domain_id + self.domain_name = domain_name + + super(RequestContext, self).__init__(auth_token=auth_token, + user=user, tenant=tenant, + is_admin=is_admin, + read_only=read_only, + show_deleted=show_deleted, + request_id=request_id) + + def to_dict(self): + result = {'domain_id': self.domain_id, + 'domain_name': self.domain_name, + 'is_public_api': self.is_public_api} + + result.update(super(RequestContext, self).to_dict()) + + return result diff --git a/service-mgmt-api/sm-api/sm_api/common/exception.py b/service-mgmt-api/sm-api/sm_api/common/exception.py new file mode 100644 index 00000000..269305d0 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/exception.py @@ -0,0 +1,401 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""SmApi base exception handling. + +Includes decorator for re-raising SmApi-type exceptions. + +SHOULD include dedicated exception logging. + +""" + +import functools + +from oslo_config import cfg + +from sm_api.common import safe_utils +from sm_api.openstack.common import excutils +from sm_api.openstack.common import log as logging + + +LOG = logging.getLogger(__name__) + +exc_log_opts = [ + cfg.BoolOpt('fatal_exception_format_errors', + default=False, + help='make exception message format errors fatal'), +] + +CONF = cfg.CONF +CONF.register_opts(exc_log_opts) + + +class ProcessExecutionError(IOError): + def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, + description=None): + self.exit_code = exit_code + self.stderr = stderr + self.stdout = stdout + self.cmd = cmd + self.description = description + + if description is None: + description = _('Unexpected error while running command.') + if exit_code is None: + exit_code = '-' + message = (_('%(description)s\nCommand: %(cmd)s\n' + 'Exit code: %(exit_code)s\nStdout: %(stdout)r\n' + 'Stderr: %(stderr)r') % + {'description': description, 'cmd': cmd, + 'exit_code': exit_code, 'stdout': stdout, + 'stderr': stderr}) + IOError.__init__(self, message) + + +def _cleanse_dict(original): + """Strip all admin_password, new_pass, rescue_pass keys from a dict.""" + return dict((k, v) for k, v in original.iteritems() if not "_pass" in k) + + +def wrap_exception(notifier=None, publisher_id=None, event_type=None, + level=None): + """This decorator wraps a method to catch any exceptions that may + get thrown. It logs the exception as well as optionally sending + it to the notification system. + """ + def inner(f): + def wrapped(self, context, *args, **kw): + # Don't store self or context in the payload, it now seems to + # contain confidential information. + try: + return f(self, context, *args, **kw) + except Exception as e: + with excutils.save_and_reraise_exception(): + if notifier: + payload = dict(exception=e) + call_dict = safe_utils.getcallargs(f, *args, **kw) + cleansed = _cleanse_dict(call_dict) + payload.update({'args': cleansed}) + + # Use a temp vars so we don't shadow + # our outer definitions. + temp_level = level + if not temp_level: + temp_level = notifier.ERROR + + temp_type = event_type + if not temp_type: + # If f has multiple decorators, they must use + # functools.wraps to ensure the name is + # propagated. + temp_type = f.__name__ + + notifier.notify(context, publisher_id, temp_type, + temp_level, payload) + + return functools.wraps(f)(wrapped) + return inner + + +class SmApiException(Exception): + """Base SmApi Exception + + To correctly use this class, inherit from it and define + a 'message' property. That message will get printf'd + with the keyword arguments provided to the constructor. + + """ + message = _("An unknown exception occurred.") + code = 500 + headers = {} + safe = False + + def __init__(self, message=None, **kwargs): + self.kwargs = kwargs + + if 'code' not in self.kwargs: + try: + self.kwargs['code'] = self.code + except AttributeError: + pass + + if not message: + try: + message = self.message % kwargs + + except Exception as e: + # kwargs doesn't match a variable in the message + # log the issue and the kwargs + LOG.exception(_('Exception in string format operation')) + for name, value in kwargs.iteritems(): + LOG.error("%s: %s" % (name, value)) + + if CONF.fatal_exception_format_errors: + raise e + else: + # at least get the core message out if something happened + message = self.message + + super(SmApiException, self).__init__(message) + + def format_message(self): + if self.__class__.__name__.endswith('_Remote'): + return self.args[0] + else: + return unicode(self) + + +class NotAuthorized(SmApiException): + message = _("Not authorized.") + code = 403 + + +class AdminRequired(NotAuthorized): + message = _("User does not have admin privileges") + + +class PolicyNotAuthorized(NotAuthorized): + message = _("Policy doesn't allow %(action)s to be performed.") + + +class OperationNotPermitted(NotAuthorized): + message = _("Operation not permitted.") + + +class Invalid(SmApiException): + message = _("Unacceptable parameters.") + code = 400 + + +class Conflict(SmApiException): + message = _('Conflict.') + code = 409 + + +class InvalidCPUInfo(Invalid): + message = _("Unacceptable CPU info") + ": %(reason)s" + + +class InvalidIpAddressError(Invalid): + message = _("%(address)s is not a valid IP v4/6 address.") + + +class InvalidDiskFormat(Invalid): + message = _("Disk format %(disk_format)s is not acceptable") + + +class InvalidUUID(Invalid): + message = _("Expected a uuid but received %(uuid)s.") + + +class InvalidIdentity(Invalid): + message = _("Expected an uuid or int but received %(identity)s.") + + +class PatchError(Invalid): + message = _("Couldn't apply patch '%(patch)s'. Reason: %(reason)s") + + +class InvalidMAC(Invalid): + message = _("Expected a MAC address but received %(mac)s.") + + +class MACAlreadyExists(Conflict): + message = _("A Port with MAC address %(mac)s already exists.") + + +class InstanceDeployFailure(Invalid): + message = _("Failed to deploy instance: %(reason)s") + + +class ImageUnacceptable(Invalid): + message = _("Image %(image_id)s is unacceptable: %(reason)s") + + +class ImageConvertFailed(Invalid): + message = _("Image %(image_id)s is unacceptable: %(reason)s") + + +# Cannot be templated as the error syntax varies. +# msg needs to be constructed when raised. +class InvalidParameterValue(Invalid): + message = _("%(err)s") + + +class NotFound(SmApiException): + message = _("Resource could not be found.") + code = 404 + + +class DiskNotFound(NotFound): + message = _("No disk at %(location)s") + + +class DriverNotFound(NotFound): + message = _("Failed to load driver %(driver_name)s.") + + +class ImageNotFound(NotFound): + message = _("Image %(image_id)s could not be found.") + + +class HostNotFound(NotFound): + message = _("Host %(host)s could not be found.") + + +class HostLocked(SmApiException): + message = _("Unable to complete the action %(action)s because " + "Host %(host)s is in administrative state = unlocked.") + + +class ConsoleNotFound(NotFound): + message = _("Console %(console_id)s could not be found.") + + +class FileNotFound(NotFound): + message = _("File %(file_path)s could not be found.") + + +class NoValidHost(NotFound): + message = _("No valid host was found. %(reason)s") + + +class InstanceNotFound(NotFound): + message = _("Instance %(instance)s could not be found.") + + +class NodeNotFound(NotFound): + message = _("Node %(node)s could not be found.") + + +class NodeLocked(NotFound): + message = _("Node %(node)s is locked by another process.") + + +class PortNotFound(NotFound): + message = _("Port %(port)s could not be found.") + + +class ChassisNotFound(NotFound): + message = _("Chassis %(chassis)s could not be found.") + + +class ServerNotFound(NotFound): + message = _("Server %(server)s could not be found.") + + +class PowerStateFailure(SmApiException): + message = _("Failed to set node power state to %(pstate)s.") + + +class ExclusiveLockRequired(NotAuthorized): + message = _("An exclusive lock is required, " + "but the current context has a shared lock.") + + +class NodeInUse(SmApiException): + message = _("Unable to complete the requested action because node " + "%(node)s is currently in use by another process.") + + +class NodeInWrongPowerState(SmApiException): + message = _("Can not change instance association while node " + "%(node)s is in power state %(pstate)s.") + + +class NodeNotConfigured(SmApiException): + message = _("Can not change power state because node %(node)s " + "is not fully configured.") + + +class ChassisNotEmpty(SmApiException): + message = _("Cannot complete the requested action because chassis " + "%(chassis)s contains nodes.") + + +class IPMIFailure(SmApiException): + message = _("IPMI call failed: %(cmd)s.") + + +class SSHConnectFailed(SmApiException): + message = _("Failed to establish SSH connection to host %(host)s.") + + +class UnsupportedObjectError(SmApiException): + message = _('Unsupported object type %(objtype)s') + + +class OrphanedObjectError(SmApiException): + message = _('Cannot call %(method)s on orphaned %(objtype)s object') + + +class IncompatibleObjectVersion(SmApiException): + message = _('Version %(objver)s of %(objname)s is not supported') + + +class GlanceConnectionFailed(SmApiException): + message = "Connection to glance host %(host)s:%(port)s failed: %(reason)s" + + +class ImageNotAuthorized(SmApiException): + message = "Not authorized for image %(image_id)s." + + +class InvalidImageRef(SmApiException): + message = "Invalid image href %(image_href)s." + code = 400 + + +class ServiceUnavailable(SmApiException): + message = "Connection failed" + + +class Forbidden(SmApiException): + message = "Requested OpenStack Images API is forbidden" + + +class BadRequest(SmApiException): + pass + + +class HTTPException(SmApiException): + message = "Requested version of OpenStack Images API is not available." + + +class InvalidEndpoint(SmApiException): + message = "The provided endpoint is invalid" + + +class CommunicationError(SmApiException): + message = "Unable to communicate with the server." + + +class HTTPForbidden(Forbidden): + pass + + +class Unauthorized(SmApiException): + pass + + +class HTTPNotFound(NotFound): + pass diff --git a/service-mgmt-api/sm-api/sm_api/common/log.py b/service-mgmt-api/sm-api/sm_api/common/log.py new file mode 100644 index 00000000..17b44288 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/log.py @@ -0,0 +1,77 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# + +""" +Logging +""" + +import logging +import logging.handlers + +LOG_FILE_NAME = "sm.log" +LOG_MAX_BYTES = 10485760 +LOG_BACKUP_COUNT = 5 + +_log_to_console = False +_log_to_syslog = False +_log_to_file = False + +_syslog_facility = None + +_loggers = {} + + +def _setup_logger(logger): + formatter = logging.Formatter("%(asctime)s %(threadName)s[%(process)d] " + "%(name)s.%(lineno)d - %(levelname)s " + "%(message)s") + + if _log_to_console: + handler = logging.StreamHandler() + handler.setFormatter(formatter) + logger.addHandler(handler) + + if _log_to_syslog: + handler = logging.handlers.SysLogHandler(address='/dev/log', + facility=_syslog_facility) + handler.setFormatter(formatter) + logger.addHandler(handler) + + if _log_to_file: + handler = logging.handlers.RotatingFileHandler(LOG_FILE_NAME, "a+", + LOG_MAX_BYTES, + LOG_BACKUP_COUNT) + handler.setFormatter(formatter) + logger.addHandler(handler) + + logger.setLevel(logging.DEBUG) + + +def get_logger(name): + """ Get a logger or create one . + """ + + global _loggers + + _loggers[name] = logging.getLogger(name) + return _loggers[name] + + +def configure(conf): + """ Setup logging. + """ + + global _loggers + global _log_to_syslog + global _syslog_facility + + if conf['logging']['use_syslog']: + _log_to_syslog = True + _syslog_facility = conf['logging']['log_facility'] + + for logger in _loggers: + _setup_logger(_loggers[logger]) diff --git a/service-mgmt-api/sm-api/sm_api/common/policy.py b/service-mgmt-api/sm-api/sm_api/common/policy.py new file mode 100644 index 00000000..fe7c474b --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/policy.py @@ -0,0 +1,135 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Policy Engine For Sm_api.""" + +import os.path + +from oslo_config import cfg + +from sm_api.common import exception +from sm_api.common import utils +from sm_api.openstack.common import policy + + +policy_opts = [ + cfg.StrOpt('policy_file', + default='policy.json', + help=_('JSON file representing policy')), + cfg.StrOpt('policy_default_rule', + default='default', + help=_('Rule checked when requested rule is not found')), + ] + +CONF = cfg.CONF +CONF.register_opts(policy_opts) + +_POLICY_PATH = None +_POLICY_CACHE = {} + + +def reset(): + global _POLICY_PATH + global _POLICY_CACHE + _POLICY_PATH = None + _POLICY_CACHE = {} + policy.reset() + + +def init(): + global _POLICY_PATH + global _POLICY_CACHE + if not _POLICY_PATH: + _POLICY_PATH = CONF.policy_file + if not os.path.exists(_POLICY_PATH): + _POLICY_PATH = CONF.find_file(_POLICY_PATH) + if not _POLICY_PATH: + raise exception.ConfigNotFound(path=CONF.policy_file) + utils.read_cached_file(_POLICY_PATH, _POLICY_CACHE, + reload_func=_set_rules) + + +def _set_rules(data): + default_rule = CONF.policy_default_rule + policy.set_rules(policy.Rules.load_json(data, default_rule)) + + +def enforce(context, action, target, do_raise=True): + """Verifies that the action is valid on the target in this context. + + :param context: sm_api context + :param action: string representing the action to be checked + this should be colon separated for clarity. + i.e. ``compute:create_instance``, + ``compute:attach_volume``, + ``volume:attach_volume`` + :param target: dictionary representing the object of the action + for object creation this should be a dictionary representing the + location of the object e.g. ``{'project_id': context.project_id}`` + :param do_raise: if True (the default), raises PolicyNotAuthorized; + if False, returns False + + :raises sm_api.exception.PolicyNotAuthorized: if verification fails + and do_raise is True. + + :return: returns a non-False value (not necessarily "True") if + authorized, and the exact value False if not authorized and + do_raise is False. + """ + init() + + credentials = context.to_dict() + + # Add the exception arguments if asked to do a raise + extra = {} + if do_raise: + extra.update(exc=exception.PolicyNotAuthorized, action=action) + + return policy.check(action, target, credentials, **extra) + + +def check_is_admin(context): + """Whether or not role contains 'admin' role according to policy setting. + + """ + init() + + credentials = context.to_dict() + target = credentials + + return policy.check('context_is_admin', target, credentials) + + +@policy.register('context_is_admin') +class IsAdminCheck(policy.Check): + """An explicit check for is_admin.""" + + def __init__(self, kind, match): + """Initialize the check.""" + + self.expected = (match.lower() == 'true') + + super(IsAdminCheck, self).__init__(kind, str(self.expected)) + + def __call__(self, target, creds): + """Determine whether is_admin matches the requested value.""" + + return creds['is_admin'] == self.expected diff --git a/service-mgmt-api/sm-api/sm_api/common/safe_utils.py b/service-mgmt-api/sm-api/sm_api/common/safe_utils.py new file mode 100644 index 00000000..1c994e31 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/safe_utils.py @@ -0,0 +1,59 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Justin Santa Barbara +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Utilities and helper functions that won't produce circular imports.""" + +import inspect + + +def getcallargs(function, *args, **kwargs): + """This is a simplified inspect.getcallargs (2.7+). + + It should be replaced when python >= 2.7 is standard. + """ + keyed_args = {} + argnames, varargs, keywords, defaults = inspect.getargspec(function) + + keyed_args.update(kwargs) + + #NOTE(alaski) the implicit 'self' or 'cls' argument shows up in + # argnames but not in args or kwargs. Uses 'in' rather than '==' because + # some tests use 'self2'. + if 'self' in argnames[0] or 'cls' == argnames[0]: + # The function may not actually be a method or have im_self. + # Typically seen when it's stubbed with mox. + if inspect.ismethod(function) and hasattr(function, 'im_self'): + keyed_args[argnames[0]] = function.im_self + else: + keyed_args[argnames[0]] = None + + remaining_argnames = filter(lambda x: x not in keyed_args, argnames) + keyed_args.update(dict(zip(remaining_argnames, args))) + + if defaults: + num_defaults = len(defaults) + for argname, value in zip(argnames[-num_defaults:], defaults): + if argname not in keyed_args: + keyed_args[argname] = value + + return keyed_args diff --git a/service-mgmt-api/sm-api/sm_api/common/service.py b/service-mgmt-api/sm-api/sm_api/common/service.py new file mode 100644 index 00000000..0e1bd10c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/service.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +# +# Copyright © 2012 eNovance +# +# Author: Julien Danjou +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import socket + +from oslo_config import cfg + +from sm_api.openstack.common import context +from sm_api.openstack.common import log +from sm_api.openstack.common import periodic_task +from sm_api.openstack.common import rpc +from sm_api.openstack.common.rpc import service as rpc_service + + +cfg.CONF.register_opts([ + cfg.IntOpt('periodic_interval', + default=60, + help='seconds between running periodic tasks'), + cfg.StrOpt('host', + default=socket.getfqdn(), + help='Name of this node. This can be an opaque identifier. ' + 'It is not necessarily a hostname, FQDN, or IP address. ' + 'However, the node name must be valid within ' + 'an AMQP key, and if using ZeroMQ, a valid ' + 'hostname, FQDN, or IP address'), +]) + + +class PeriodicService(rpc_service.Service, periodic_task.PeriodicTasks): + + def start(self): + super(PeriodicService, self).start() + admin_context = context.RequestContext('admin', 'admin', is_admin=True) + self.tg.add_timer(cfg.CONF.periodic_interval, + self.manager.periodic_tasks, + context=admin_context) + + +def prepare_service(argv=[]): + rpc.set_defaults(control_exchange='sm_api') + cfg.set_defaults(log.log_opts, + default_log_levels=['amqplib=WARN', + 'qpid.messaging=INFO', + 'sqlalchemy=WARN', + 'keystoneclient=INFO', + 'stevedore=INFO', + 'eventlet.wsgi.server=WARN' + ]) + cfg.CONF(argv[1:], project='sm_api') + log.setup('sm_api') diff --git a/service-mgmt-api/sm-api/sm_api/common/utils.py b/service-mgmt-api/sm-api/sm_api/common/utils.py new file mode 100644 index 00000000..00fc7238 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/common/utils.py @@ -0,0 +1,678 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Justin Santa Barbara +# Copyright (c) 2012 NTT DOCOMO, INC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Utilities and helper functions.""" + +import contextlib +import errno +import hashlib +import json +import os +#import paramiko +import random +import re +import shutil +import signal +import six +import socket +import tempfile +import uuid + +from eventlet.green import subprocess +from eventlet import greenthread +import netaddr + +from oslo_config import cfg + +from sm_api.common import exception +from sm_api.openstack.common import log as logging + +utils_opts = [ + cfg.StrOpt('rootwrap_config', + default="/etc/sm_api/rootwrap.conf", + help='Path to the rootwrap configuration file to use for ' + 'running commands as root'), + cfg.StrOpt('tempdir', + default=None, + help='Explicitly specify the temporary working directory'), +] + +CONF = cfg.CONF +CONF.register_opts(utils_opts) + +LOG = logging.getLogger(__name__) + +# Used for looking up extensions of text +# to their 'multiplied' byte amount +BYTE_MULTIPLIERS = { + '': 1, + 't': 1024 ** 4, + 'g': 1024 ** 3, + 'm': 1024 ** 2, + 'k': 1024, +} + + +def _subprocess_setup(): + # Python installs a SIGPIPE handler by default. This is usually not what + # non-Python subprocesses expect. + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + +def execute(*cmd, **kwargs): + """Helper method to execute command with optional retry. + + If you add a run_as_root=True command, don't forget to add the + corresponding filter to etc/sm_api/rootwrap.d ! + + :param cmd: Passed to subprocess.Popen. + :param process_input: Send to opened process. + :param check_exit_code: Single bool, int, or list of allowed exit + codes. Defaults to [0]. Raise + exception.ProcessExecutionError unless + program exits with one of these code. + :param delay_on_retry: True | False. Defaults to True. If set to + True, wait a short amount of time + before retrying. + :param attempts: How many times to retry cmd. + :param run_as_root: True | False. Defaults to False. If set to True, + the command is run with rootwrap. + + :raises exception.SmApiException: on receiving unknown arguments + :raises exception.ProcessExecutionError: + + :returns: a tuple, (stdout, stderr) from the spawned process, or None if + the command fails. + """ + process_input = kwargs.pop('process_input', None) + check_exit_code = kwargs.pop('check_exit_code', [0]) + ignore_exit_code = False + if isinstance(check_exit_code, bool): + ignore_exit_code = not check_exit_code + check_exit_code = [0] + elif isinstance(check_exit_code, int): + check_exit_code = [check_exit_code] + delay_on_retry = kwargs.pop('delay_on_retry', True) + attempts = kwargs.pop('attempts', 1) + run_as_root = kwargs.pop('run_as_root', False) + shell = kwargs.pop('shell', False) + + if len(kwargs): + raise exception.SmApiException(_('Got unknown keyword args ' + 'to utils.execute: %r') % kwargs) + + if run_as_root and os.geteuid() != 0: + cmd = ['sudo', 'sm_api-rootwrap', CONF.rootwrap_config] + list(cmd) + + cmd = map(str, cmd) + + while attempts > 0: + attempts -= 1 + try: + LOG.debug(_('Running cmd (subprocess): %s'), ' '.join(cmd)) + _PIPE = subprocess.PIPE # pylint: disable=E1101 + + if os.name == 'nt': + preexec_fn = None + close_fds = False + else: + preexec_fn = _subprocess_setup + close_fds = True + + obj = subprocess.Popen(cmd, + stdin=_PIPE, + stdout=_PIPE, + stderr=_PIPE, + close_fds=close_fds, + preexec_fn=preexec_fn, + shell=shell) + result = None + if process_input is not None: + result = obj.communicate(process_input) + else: + result = obj.communicate() + obj.stdin.close() # pylint: disable=E1101 + _returncode = obj.returncode # pylint: disable=E1101 + LOG.debug(_('Result was %s') % _returncode) + if not ignore_exit_code and _returncode not in check_exit_code: + (stdout, stderr) = result + raise exception.ProcessExecutionError( + exit_code=_returncode, + stdout=stdout, + stderr=stderr, + cmd=' '.join(cmd)) + return result + except exception.ProcessExecutionError: + if not attempts: + raise + else: + LOG.debug(_('%r failed. Retrying.'), cmd) + if delay_on_retry: + greenthread.sleep(random.randint(20, 200) / 100.0) + finally: + # NOTE(termie): this appears to be necessary to let the subprocess + # call clean something up in between calls, without + # it two execute calls in a row hangs the second one + greenthread.sleep(0) + + +def trycmd(*args, **kwargs): + """A wrapper around execute() to more easily handle warnings and errors. + + Returns an (out, err) tuple of strings containing the output of + the command's stdout and stderr. If 'err' is not empty then the + command can be considered to have failed. + + :discard_warnings True | False. Defaults to False. If set to True, + then for succeeding commands, stderr is cleared + + """ + discard_warnings = kwargs.pop('discard_warnings', False) + + try: + out, err = execute(*args, **kwargs) + failed = False + except exception.ProcessExecutionError as exn: + out, err = '', str(exn) + failed = True + + if not failed and discard_warnings and err: + # Handle commands that output to stderr but otherwise succeed + err = '' + + return out, err + + +# def ssh_connect(connection): +# """Method to connect to a remote system using ssh protocol. +# +# :param connection: a dict of connection parameters. +# :returns: paramiko.SSHClient -- an active ssh connection. +# :raises: SSHConnectFailed +# +# """ +# try: +# ssh = paramiko.SSHClient() +# ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +# ssh.connect(connection.get('host'), +# username=connection.get('username'), +# password=connection.get('password', None), +# port=connection.get('port', 22), +# key_filename=connection.get('key_filename', None), +# timeout=connection.get('timeout', 10)) +# +# # send TCP keepalive packets every 20 seconds +# ssh.get_transport().set_keepalive(20) +# except Exception: +# raise exception.SSHConnectFailed(host=connection.get('host')) +# +# return ssh + + +def generate_uid(topic, size=8): + characters = '01234567890abcdefghijklmnopqrstuvwxyz' + choices = [random.choice(characters) for _x in xrange(size)] + return '%s-%s' % (topic, ''.join(choices)) + + +def random_alnum(size=32): + characters = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + return ''.join(random.choice(characters) for _ in xrange(size)) + + +class LazyPluggable(object): + """A pluggable backend loaded lazily based on some value.""" + + def __init__(self, pivot, config_group=None, **backends): + self.__backends = backends + self.__pivot = pivot + self.__backend = None + self.__config_group = config_group + + def __get_backend(self): + if not self.__backend: + if self.__config_group is None: + backend_name = CONF[self.__pivot] + else: + backend_name = CONF[self.__config_group][self.__pivot] + if backend_name not in self.__backends: + msg = _('Invalid backend: %s') % backend_name + raise exception.SmApiException(msg) + + backend = self.__backends[backend_name] + if isinstance(backend, tuple): + name = backend[0] + fromlist = backend[1] + else: + name = backend + fromlist = backend + + self.__backend = __import__(name, None, None, fromlist) + return self.__backend + + def __getattr__(self, key): + backend = self.__get_backend() + return getattr(backend, key) + + +def delete_if_exists(pathname): + """delete a file, but ignore file not found error.""" + + try: + os.unlink(pathname) + except OSError as e: + if e.errno == errno.ENOENT: + return + else: + raise + + +def is_int_like(val): + """Check if a value looks like an int.""" + try: + return str(int(val)) == str(val) + except Exception: + return False + + +def is_valid_boolstr(val): + """Check if the provided string is a valid bool string or not.""" + boolstrs = ('true', 'false', 'yes', 'no', 'y', 'n', '1', '0') + return str(val).lower() in boolstrs + + +def is_valid_mac(address): + """Verify the format of a MAC addres.""" + m = "[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$" + if isinstance(address, six.string_types) and re.match(m, address.lower()): + return True + return False + + +def validate_and_normalize_mac(address): + """Validate a MAC address and return normalized form. + + Checks whether the supplied MAC address is formally correct and + normalize it to all lower case. + + :param address: MAC address to be validated and normalized. + :returns: Normalized and validated MAC address. + :raises: InvalidMAC If the MAC address is not valid. + + """ + if not is_valid_mac(address): + raise exception.InvalidMAC(mac=address) + return address.lower() + + +def is_valid_ipv4(address): + """Verify that address represents a valid IPv4 address.""" + try: + return netaddr.valid_ipv4(address) + except Exception: + return False + + +def is_valid_ipv6(address): + try: + return netaddr.valid_ipv6(address) + except Exception: + return False + + +def is_valid_ipv6_cidr(address): + try: + str(netaddr.IPNetwork(address, version=6).cidr) + return True + except Exception: + return False + + +def get_shortened_ipv6(address): + addr = netaddr.IPAddress(address, version=6) + return str(addr.ipv6()) + + +def get_shortened_ipv6_cidr(address): + net = netaddr.IPNetwork(address, version=6) + return str(net.cidr) + + +def is_valid_cidr(address): + """Check if the provided ipv4 or ipv6 address is a valid CIDR address.""" + try: + # Validate the correct CIDR Address + netaddr.IPNetwork(address) + except netaddr.core.AddrFormatError: + return False + except UnboundLocalError: + # NOTE(MotoKen): work around bug in netaddr 0.7.5 (see detail in + # https://github.com/drkjam/netaddr/issues/2) + return False + + # Prior validation partially verify /xx part + # Verify it here + ip_segment = address.split('/') + + if (len(ip_segment) <= 1 or + ip_segment[1] == ''): + return False + + return True + + +def get_ip_version(network): + """Returns the IP version of a network (IPv4 or IPv6). + + :raises: AddrFormatError if invalid network. + """ + if netaddr.IPNetwork(network).version == 6: + return "IPv6" + elif netaddr.IPNetwork(network).version == 4: + return "IPv4" + + +def convert_to_list_dict(lst, label): + """Convert a value or list into a list of dicts.""" + if not lst: + return None + if not isinstance(lst, list): + lst = [lst] + return [{label: x} for x in lst] + + +def sanitize_hostname(hostname): + """Return a hostname which conforms to RFC-952 and RFC-1123 specs.""" + if isinstance(hostname, unicode): + hostname = hostname.encode('latin-1', 'ignore') + + hostname = re.sub('[ _]', '-', hostname) + hostname = re.sub('[^\w.-]+', '', hostname) + hostname = hostname.lower() + hostname = hostname.strip('.-') + + return hostname + + +def read_cached_file(filename, cache_info, reload_func=None): + """Read from a file if it has been modified. + + :param cache_info: dictionary to hold opaque cache. + :param reload_func: optional function to be called with data when + file is reloaded due to a modification. + + :returns: data from file + + """ + mtime = os.path.getmtime(filename) + if not cache_info or mtime != cache_info.get('mtime'): + LOG.debug(_("Reloading cached file %s") % filename) + with open(filename) as fap: + cache_info['data'] = fap.read() + cache_info['mtime'] = mtime + if reload_func: + reload_func(cache_info['data']) + return cache_info['data'] + + +def file_open(*args, **kwargs): + """Open file + + see built-in file() documentation for more details + + Note: The reason this is kept in a separate module is to easily + be able to provide a stub module that doesn't alter system + state at all (for unit tests) + """ + return file(*args, **kwargs) + + +def hash_file(file_like_object): + """Generate a hash for the contents of a file.""" + checksum = hashlib.sha1() + for chunk in iter(lambda: file_like_object.read(32768), b''): + checksum.update(chunk) + return checksum.hexdigest() + + +@contextlib.contextmanager +def temporary_mutation(obj, **kwargs): + """Temporarily set the attr on a particular object to a given value then + revert when finished. + + One use of this is to temporarily set the read_deleted flag on a context + object: + + with temporary_mutation(context, read_deleted="yes"): + do_something_that_needed_deleted_objects() + """ + def is_dict_like(thing): + return hasattr(thing, 'has_key') + + def get(thing, attr, default): + if is_dict_like(thing): + return thing.get(attr, default) + else: + return getattr(thing, attr, default) + + def set_value(thing, attr, val): + if is_dict_like(thing): + thing[attr] = val + else: + setattr(thing, attr, val) + + def delete(thing, attr): + if is_dict_like(thing): + del thing[attr] + else: + delattr(thing, attr) + + NOT_PRESENT = object() + + old_values = {} + for attr, new_value in kwargs.items(): + old_values[attr] = get(obj, attr, NOT_PRESENT) + set_value(obj, attr, new_value) + + try: + yield + finally: + for attr, old_value in old_values.items(): + if old_value is NOT_PRESENT: + delete(obj, attr) + else: + set_value(obj, attr, old_value) + + +@contextlib.contextmanager +def tempdir(**kwargs): + tempfile.tempdir = CONF.tempdir + tmpdir = tempfile.mkdtemp(**kwargs) + try: + yield tmpdir + finally: + try: + shutil.rmtree(tmpdir) + except OSError as e: + LOG.error(_('Could not remove tmpdir: %s'), str(e)) + + +def mkfs(fs, path, label=None): + """Format a file or block device + + :param fs: Filesystem type (examples include 'swap', 'ext3', 'ext4' + 'btrfs', etc.) + :param path: Path to file or block device to format + :param label: Volume label to use + """ + if fs == 'swap': + args = ['mkswap'] + else: + args = ['mkfs', '-t', fs] + #add -F to force no interactive execute on non-block device. + if fs in ('ext3', 'ext4'): + args.extend(['-F']) + if label: + if fs in ('msdos', 'vfat'): + label_opt = '-n' + else: + label_opt = '-L' + args.extend([label_opt, label]) + args.append(path) + execute(*args) + + +# TODO(deva): Make these work in SmApi. +# Either copy nova/virt/utils (bad), +# or reimplement as a common lib, +# or make a driver that doesn't need to do this. +# +#def cache_image(context, target, image_id, user_id, project_id): +# if not os.path.exists(target): +# libvirt_utils.fetch_image(context, target, image_id, +# user_id, project_id) +# +# +#def inject_into_image(image, key, net, metadata, admin_password, +# files, partition, use_cow=False): +# try: +# disk_api.inject_data(image, key, net, metadata, admin_password, +# files, partition, use_cow) +# except Exception as e: +# LOG.warn(_("Failed to inject data into image %(image)s. " +# "Error: %(e)s") % locals()) + + +def unlink_without_raise(path): + try: + os.unlink(path) + except OSError as e: + if e.errno == errno.ENOENT: + return + else: + LOG.warn(_("Failed to unlink %(path)s, error: %(e)s") % + {'path': path, 'e': e}) + + +def rmtree_without_raise(path): + try: + if os.path.isdir(path): + shutil.rmtree(path) + except OSError as e: + LOG.warn(_("Failed to remove dir %(path)s, error: %(e)s") % + {'path': path, 'e': e}) + + +def write_to_file(path, contents): + with open(path, 'w') as f: + f.write(contents) + + +def create_link_without_raise(source, link): + try: + os.symlink(source, link) + except OSError as e: + if e.errno == errno.EEXIST: + return + else: + LOG.warn(_("Failed to create symlink from %(source)s to %(link)s" + ", error: %(e)s") % + {'source': source, 'link': link, 'e': e}) + + +def safe_rstrip(value, chars=None): + """Removes trailing characters from a string if that does not make it empty + + :param value: A string value that will be stripped. + :param chars: Characters to remove. + :return: Stripped value. + + """ + if not isinstance(value, six.string_types): + LOG.warn(_("Failed to remove trailing character. Returning original " + "object. Supplied object is not a string: %s,") % value) + return value + + return value.rstrip(chars) or value + + +def generate_uuid(): + return str(uuid.uuid4()) + + +def is_uuid_like(val): + """Returns validation of a value as a UUID. + + For our purposes, a UUID is a canonical form string: + aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa + + """ + try: + return str(uuid.UUID(val)) == val + except (TypeError, ValueError, AttributeError): + return False + + +def removekey(d, key): + r = dict(d) + del r[key] + return r + + +def notify_mtc_and_recv(mtc_address, mtc_port, idict): + mtc_response_dict = {} + mtc_response_dict['status'] = None + + serialized_idict = json.dumps(idict) + + # notify mtc this ihost has been added + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + s.setblocking(1) # blocking, timeout must be specified + s.settimeout(6) # give mtc a few secs to respond + s.connect((mtc_address, mtc_port)) + LOG.warning("Mtc Command : %s" % serialized_idict) + s.sendall(serialized_idict) + + mtc_response = s.recv(1024) # check if mtc allows + try: + mtc_response_dict = json.loads(mtc_response) + LOG.warning("Mtc Response: %s" % mtc_response_dict) + except: + LOG.exception("Mtc Response Error: %s" % mtc_response) + pass + + except socket.error, e: + LOG.exception(_("Socket Error: %s on %s:%s for %s") % (e, + mtc_address, mtc_port, serialized_idict)) + # if e not in [errno.EWOULDBLOCK, errno.EINTR]: + # raise exception.CommunicationError(_( + # "Socket error: address=%s port=%s error=%s ") % ( + # self._mtc_address, self._mtc_port, e)) + pass + + finally: + s.close() + + return mtc_response_dict diff --git a/service-mgmt-api/sm-api/sm_api/db/__init__.py b/service-mgmt-api/sm-api/sm_api/db/__init__.py new file mode 100644 index 00000000..42b3bf66 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/__init__.py @@ -0,0 +1,10 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# All Rights Reserved. +# diff --git a/service-mgmt-api/sm-api/sm_api/db/api.py b/service-mgmt-api/sm-api/sm_api/db/api.py new file mode 100644 index 00000000..975f95be --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/api.py @@ -0,0 +1,175 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# -*- encoding: utf-8 -*- +# +# +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +""" +Base classes for storage engines +""" + +import abc + +from sm_api.openstack.common.db import api as db_api + +_BACKEND_MAPPING = {'sqlalchemy': 'sm_api.db.sqlalchemy.api'} +IMPL = db_api.DBAPI(backend_mapping=_BACKEND_MAPPING) + + +def get_instance(): + """Return a DB API instance.""" + return IMPL + + +class Connection(object): + """Base class for storage system connections.""" + + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def __init__(self): + """Constructor.""" + + @abc.abstractmethod + def iservicegroup_get(self, server): + """Return a servicegroup. + + :param server: The id or uuid of a servicegroup. + :returns: An iservicegroup. + """ + + @abc.abstractmethod + def iservicegroup_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + """Return a list of servicegroupintances. + + :param limit: Maximum number of iServers to return. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted. + :param sort_dir: direction in which results should be sorted. + (asc, desc) + """ + + @abc.abstractmethod + def iservice_get(self, server): + """Return a service instance. + + :param server: The id or uuid of a server. + :returns: A server. + """ + + @abc.abstractmethod + def iservice_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + """Return a list of serviceintances. + + :param limit: Maximum number of iServers to return. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted. + :param sort_dir: direction in which results should be sorted. + (asc, desc) + """ + + @abc.abstractmethod + def iservice_get_by_name(self, name): + """Return a list of serviceinstance by service. + :param name: The name (service group) + returns: An iservice list + """ + + @abc.abstractmethod + def sm_sdm_get(self, server, service_group_name): + """get service_domain_member + + :param server: The name of the service_domain. + :param service_group: The name of the service_domain_member. + """ + + @abc.abstractmethod + def sm_sda_get(self, server): + """get service_domain_assignment + + :param server: The id or uuid of a service_domain_assignment. + """ + + @abc.abstractmethod + def sm_sda_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + """Return a list of service_domain_assignments. + + :param limit: Maximum number of entries to return. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted. + :param sort_dir: direction in which results should be sorted. + (asc, desc) + """ + + @abc.abstractmethod + def sm_node_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + """Return a list of nodes. + + :param limit: Maximum number of nodes to return. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted. + :param sort_dir: direction in which results should be sorted. + (asc, desc) + """ + + @abc.abstractmethod + def sm_node_get(self, server): + """get node + + :param server: The id or uuid of a node. + """ + + @abc.abstractmethod + def sm_node_get_by_name(self, name): + """Return a list of nodes by name. + :param name: The name of the hostname. + """ + + @abc.abstractmethod + def sm_service_get(self, server): + """get service + + :param server: The id or uuid of a service. + """ + + @abc.abstractmethod + def sm_service_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + """Return a list of services. + + :param limit: Maximum number of services to return. + :param marker: the last item of the previous page; we return the next + result set. + :param sort_key: Attribute by which results should be sorted. + :param sort_dir: direction in which results should be sorted. + (asc, desc) + """ + + @abc.abstractmethod + def sm_service_get_by_name(self, name): + """Return a list of services by name. + :param name: The name of the services. + """ diff --git a/service-mgmt-api/sm-api/sm_api/db/migration.py b/service-mgmt-api/sm-api/sm_api/db/migration.py new file mode 100644 index 00000000..9b93c7b9 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/migration.py @@ -0,0 +1,49 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Database setup and migration commands.""" + +from oslo_config import cfg + +from sm_api.common import utils + +CONF = cfg.CONF +CONF.import_opt('backend', + 'sm_api.openstack.common.db.api', + group='database') + +IMPL = utils.LazyPluggable( + pivot='backend', + config_group='database', + sqlalchemy='sm_api.db.sqlalchemy.migration') + +INIT_VERSION = 0 + + +def db_sync(version=None): + """Migrate the database to `version` or the most recent version.""" + return IMPL.db_sync(version=version) + + +def db_version(): + """Display the current database version.""" + return IMPL.db_version() diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/__init__.py b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/api.py b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/api.py new file mode 100755 index 00000000..0b550353 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/api.py @@ -0,0 +1,267 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# -*- encoding: utf-8 -*- +# +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""SQLAlchemy storage backend.""" + +from oslo_config import cfg + +# TODO(deva): import MultipleResultsFound and handle it appropriately +from sqlalchemy.orm.exc import NoResultFound + +from sm_api.common import exception +from sm_api.common import utils +from sm_api.db import api +from sm_api.db.sqlalchemy import models +from sm_api import objects +from sm_api.openstack.common.db import exception as db_exc +from sm_api.openstack.common.db.sqlalchemy import session as db_session +from sm_api.openstack.common.db.sqlalchemy import utils as db_utils +from sm_api.openstack.common import log +from sm_api.openstack.common import uuidutils + +CONF = cfg.CONF +CONF.import_opt('connection', + 'sm_api.openstack.common.db.sqlalchemy.session', + group='database') + +LOG = log.getLogger(__name__) + +get_engine = db_session.get_engine +get_session = db_session.get_session + + +def _paginate_query(model, limit=None, marker=None, sort_key=None, + sort_dir=None, query=None): + if not query: + query = model_query(model) + sort_keys = ['id'] + if sort_key and sort_key not in sort_keys: + sort_keys.insert(0, sort_key) + query = db_utils.paginate_query(query, model, limit, sort_keys, + marker=marker, sort_dir=sort_dir) + return query.all() + + +def get_backend(): + """The backend is this module itself.""" + return Connection() + + +def model_query(model, *args, **kwargs): + """Query helper for simpler session usage. + + :param session: if present, the session to use + """ + + session = kwargs.get('session') or get_session() + query = session.query(model, *args) + return query + + +def add_identity_filter(query, value, use_name=False): + """Adds an identity filter to a query. + + Filters results by ID, if supplied value is a valid integer. + Otherwise attempts to filter results by UUID. + + :param query: Initial query to add filter to. + :param value: Value for filtering results by. + :return: Modified query. + """ + if utils.is_int_like(value): + return query.filter_by(id=value) + elif uuidutils.is_uuid_like(value): + return query.filter_by(uuid=value) + else: + if use_name: + return query.filter_by(name=value) + else: + # JKUNG raise exception + return query.filter_by(hostname=value) + + +def add_filter_by_many_identities(query, model, values): + """Adds an identity filter to a query for values list. + + Filters results by ID, if supplied values contain a valid integer. + Otherwise attempts to filter results by UUID. + + :param query: Initial query to add filter to. + :param model: Model for filter. + :param values: Values for filtering results by. + :return: tuple (Modified query, filter field name). + """ + if not values: + raise exception.InvalidIdentity(identity=values) + value = values[0] + if utils.is_int_like(value): + return query.filter(getattr(model, 'id').in_(values)), 'id' + elif uuidutils.is_uuid_like(value): + return query.filter(getattr(model, 'uuid').in_(values)), 'uuid' + else: + raise exception.InvalidIdentity(identity=value) + + +class Connection(api.Connection): + """SqlAlchemy connection.""" + + def __init__(self): + pass + + @objects.objectify(objects.service_groups) + def iservicegroup_get(self, server): + query = model_query(models.iservicegroup) + query = add_identity_filter(query, server, use_name=True) + + try: + result = query.one() + except NoResultFound: + raise exception.ServerNotFound(server=server) + + return result + + @objects.objectify(objects.service_groups) + def iservicegroup_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + return _paginate_query(models.iservicegroup, limit, marker, + sort_key, sort_dir) + + @objects.objectify(objects.service) + def iservice_get(self, server): + # server may be passed as a string. It may be uuid or Int. + # server = int(server) + query = model_query(models.service) + query = add_identity_filter(query, server, use_name=True) + + try: + result = query.one() + except NoResultFound: + raise exception.ServerNotFound(server=server) + + return result + + @objects.objectify(objects.service) + def iservice_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + return _paginate_query(models.service, limit, marker, + sort_key, sort_dir) + + @objects.objectify(objects.service) + def iservice_get_by_name(self, name): + result = model_query(models.service, read_deleted="no").\ + filter_by(name=name) + # first() since want a list + + if not result: + raise exception.NodeNotFound(node=name) + + return result + + @objects.objectify(objects.sm_sdm) + def sm_sdm_get(self, server, service_group_name): + query = model_query(models.sm_sdm) + query = query.filter_by(name=server) + query = query.filter_by(service_group_name=service_group_name) + + try: + result = query.one() + except NoResultFound: + raise exception.ServerNotFound(server=server) + + return result + + @objects.objectify(objects.sm_sda) + def sm_sda_get(self, server): + query = model_query(models.sm_sda) + query = add_identity_filter(query, server, use_name=True) + + try: + result = query.one() + except NoResultFound: + raise exception.ServerNotFound(server=server) + + return result + + @objects.objectify(objects.sm_sda) + def sm_sda_get_list(self, limit=None, marker=None, sort_key=None, + sort_dir=None): + return _paginate_query(models.sm_sda, limit, marker, + sort_key, sort_dir) + + @objects.objectify(objects.sm_node) + def sm_node_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + return _paginate_query(models.sm_node, limit, marker, + sort_key, sort_dir) + + @objects.objectify(objects.sm_node) + def sm_node_get(self, server): + query = model_query(models.sm_node) + query = add_identity_filter(query, server, use_name=True) + + try: + result = query.one() + except NoResultFound: + raise exception.ServerNotFound(server=server) + + return result + + @objects.objectify(objects.sm_node) + def sm_node_get_by_name(self, name): + result = model_query(models.sm_node, read_deleted="no").\ + filter_by(name=name) + # first() since want a list + + if not result: + raise exception.NodeNotFound(node=name) + + return result + + @objects.objectify(objects.service) + def sm_service_get(self, server): + # server may be passed as a string. It may be uuid or Int. + # server = int(server) + query = model_query(models.service) + query = add_identity_filter(query, server, use_name=True) + + try: + result = query.one() + except NoResultFound: + raise exception.ServerNotFound(server=server) + + return result + + @objects.objectify(objects.service) + def sm_service_get_list(self, limit=None, marker=None, + sort_key=None, sort_dir=None): + return _paginate_query(models.service, limit, marker, + sort_key, sort_dir) + + @objects.objectify(objects.service) + def sm_service_get_by_name(self, name): + result = model_query(models.service, read_deleted="no").\ + filter_by(name=name) + # first() since want a list + + if not result: + raise exception.NodeNotFound(node=name) + + return result diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/__init__.py b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/manage.py b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/manage.py new file mode 100644 index 00000000..142d6c44 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/manage.py @@ -0,0 +1,26 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# -*- encoding: utf-8 -*- +# +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from migrate.versioning.shell import main + + +if __name__ == '__main__': + main(debug='False', repository='.') diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/migrate.cfg b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/migrate.cfg new file mode 100644 index 00000000..337df12d --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/migrate.cfg @@ -0,0 +1,20 @@ +[db_settings] +# Used to identify which repository this database is versioned under. +# You can use the name of your project. +repository_id=sm_api + +# The name of the database table used to track the schema version. +# This name shouldn't already be used by your project. +# If this is changed once a database is under version control, you'll need to +# change the table name in each database too. +version_table=migrate_version + +# When committing a change script, Migrate will attempt to generate the +# sql for all supported databases; normally, if one of them fails - probably +# because you don't have that database installed - it is ignored and the +# commit continues, perhaps ending successfully. +# Databases in this list MUST compile successfully during a commit, or the +# entire commit will fail. List the databases your application will actually +# be using to ensure your updates to that database work properly. +# This must be a list; example: ['postgres','sqlite'] +required_dbs=[] diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/versions/001_init.py b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/versions/001_init.py new file mode 100644 index 00000000..cc9d35cc --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/versions/001_init.py @@ -0,0 +1,74 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# + +from sqlalchemy import Column, MetaData, String, Table, UniqueConstraint +from sqlalchemy import Boolean, Integer, Enum, Text, ForeignKey, DateTime +from sqlalchemy import Index +from sqlalchemy.dialects import postgresql + +ENGINE = 'InnoDB' +CHARSET = 'utf8' + + +def upgrade(migrate_engine): + meta = MetaData() + meta.bind = migrate_engine + + i_ServiceGroup = Table( + 'i_servicegroup', + meta, + Column('created_at', DateTime), + Column('updated_at', DateTime), + Column('deleted_at', DateTime), + + Column('id', Integer, primary_key=True, nullable=False), + Column('uuid', String(36), unique=True), + + Column('servicename', String(255), unique=True), + Column('state', String(255), default="unknown"), + + mysql_engine=ENGINE, + mysql_charset=CHARSET, + ) + i_ServiceGroup.create() + + i_Service = Table( + 'i_service', + meta, + Column('created_at', DateTime), + Column('updated_at', DateTime), + Column('deleted_at', DateTime), + + Column('id', Integer, primary_key=True, nullable=False), # autoincr + Column('uuid', String(36), unique=True), + + Column('servicename', String(255)), + Column('hostname', String(255)), + Column('forihostid', Integer, + ForeignKey('i_host.id', ondelete='CASCADE')), + + Column('activity', String), # active/standby + Column('state', String), + Column('reason', Text), # JSON encodedlist of string + + UniqueConstraint('servicename', 'hostname', + name='u_servicehost'), + + mysql_engine=ENGINE, + mysql_charset=CHARSET, + ) + i_Service.create() + + +def downgrade(migrate_engine): + raise NotImplementedError('Downgrade from Initial is unsupported.') + + #t = Table('i_disk', meta, autoload=True) + #t.drop() diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/versions/__init__.py b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migrate_repo/versions/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migration.py b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migration.py new file mode 100644 index 00000000..c76f4d79 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/migration.py @@ -0,0 +1,116 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import distutils.version as dist_version +import os + +import migrate +from migrate.versioning import util as migrate_util +import sqlalchemy + +from sm_api.common import exception +from sm_api.db import migration +from sm_api.openstack.common.db.sqlalchemy import session as db_session + + +@migrate_util.decorator +def patched_with_engine(f, *a, **kw): + url = a[0] + engine = migrate_util.construct_engine(url, **kw) + + try: + kw['engine'] = engine + return f(*a, **kw) + finally: + if isinstance(engine, migrate_util.Engine) and engine is not url: + migrate_util.log.debug('Disposing SQLAlchemy engine %s', engine) + engine.dispose() + + +# TODO(jkoelker) When migrate 0.7.3 is released and nova depends +# on that version or higher, this can be removed +MIN_PKG_VERSION = dist_version.StrictVersion('0.7.3') +if (not hasattr(migrate, '__version__') or + dist_version.StrictVersion(migrate.__version__) < MIN_PKG_VERSION): + migrate_util.with_engine = patched_with_engine + + +# NOTE(jkoelker) Delay importing migrate until we are patched +from migrate import exceptions as versioning_exceptions +from migrate.versioning import api as versioning_api +from migrate.versioning.repository import Repository + +_REPOSITORY = None + +get_engine = db_session.get_engine + + +def db_sync(version=None): + if version is not None: + try: + version = int(version) + except ValueError: + raise exception.Sm_apiException(_("version should be an integer")) + + current_version = db_version() + repository = _find_migrate_repo() + if version is None or version > current_version: + return versioning_api.upgrade(get_engine(), repository, version) + else: + return versioning_api.downgrade(get_engine(), repository, + version) + + +def db_version(): + repository = _find_migrate_repo() + try: + return versioning_api.db_version(get_engine(), repository) + except versioning_exceptions.DatabaseNotControlledError: + meta = sqlalchemy.MetaData() + engine = get_engine() + meta.reflect(bind=engine) + tables = meta.tables + if len(tables) == 0: + db_version_control(migration.INIT_VERSION) + return versioning_api.db_version(get_engine(), repository) + else: + # Some pre-Essex DB's may not be version controlled. + # Require them to upgrade using Essex first. + raise exception.Sm_apiException( + _("Upgrade DB using Essex release first.")) + + +def db_version_control(version=None): + repository = _find_migrate_repo() + versioning_api.version_control(get_engine(), repository, version) + return version + + +def _find_migrate_repo(): + """Get the path for the migrate repository.""" + global _REPOSITORY + path = os.path.join(os.path.abspath(os.path.dirname(__file__)), + 'migrate_repo') + assert os.path.exists(path) + if _REPOSITORY is None: + _REPOSITORY = Repository(path) + return _REPOSITORY diff --git a/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/models.py b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/models.py new file mode 100755 index 00000000..024da109 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/db/sqlalchemy/models.py @@ -0,0 +1,154 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# -*- encoding: utf-8 -*- +# +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +SQLAlchemy models for sm_api data. +""" + +import json +import urlparse + +from oslo_config import cfg + +from sqlalchemy import Column, ForeignKey, Integer, Boolean +from sqlalchemy import Enum, UniqueConstraint, String +from sqlalchemy import Index +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.types import TypeDecorator, VARCHAR + +from sm_api.openstack.common.db.sqlalchemy import models + +sql_opts = [ + cfg.StrOpt('mysql_engine', + default='InnoDB', + help='MySQL engine') +] + +cfg.CONF.register_opts(sql_opts, 'database') + + +def table_args(): + engine_name = urlparse.urlparse(cfg.CONF.database_connection).scheme + if engine_name == 'mysql': + return {'mysql_engine': cfg.CONF.mysql_engine, + 'mysql_charset': "utf8"} + return None + + +class JSONEncodedDict(TypeDecorator): + """Represents an immutable structure as a json-encoded string.""" + + impl = VARCHAR + + def process_bind_param(self, value, dialect): + if value is not None: + value = json.dumps(value) + return value + + def process_result_value(self, value, dialect): + if value is not None: + value = json.loads(value) + return value + + +class Sm_apiBase(models.ModelBase): # models.TimestampMixin, + + metadata = None + + def as_dict(self): + d = {} + for c in self.__table__.columns: + d[c.name] = self[c.name] + return d + + +Base = declarative_base(cls=Sm_apiBase) + + +# table name in models +class iservicegroup(Base): + __tablename__ = 'service_groups' + + id = Column(Integer, primary_key=True) + name = Column(String(255)) + state = Column(String(255)) + status = Column(String(255)) + + +class iservice(Base): + __tablename__ = 'i_service' + id = Column(Integer, primary_key=True) + uuid = Column(String(36)) + + servicename = Column(String(255), unique=True) + hostname = Column(String(36)) + forihostid = Column(Integer, ForeignKey('i_host.id', + ondelete='CASCADE')) + + activity = Column(String(255), default="unknown") + state = Column(String(255), default="unknown") + reason = Column(JSONEncodedDict) + + +class service(Base): + __tablename__ = 'services' + id = Column(Integer, primary_key=True) + + name = Column(String(255)) + desired_state = Column(String(255)) + state = Column(String(255)) + status = Column(String(255)) + + +# sm_service_domain_members +class sm_sdm(Base): + __tablename__ = 'service_domain_members' + + id = Column(Integer, primary_key=True) + name = Column(String(255)) + service_group_name = Column(String(255)) + redundancy_model = Column(String(255)) # sm_types.h + + +# sm_service_domain_assignments +class sm_sda(Base): + __tablename__ = 'service_domain_assignments' + id = Column(Integer, primary_key=True) + uuid = Column(String(36)) + + name = Column(String(255)) + node_name = Column(String(255)) # hostname + service_group_name = Column(String(255)) + desired_state = Column(String(255)) # sm_types.h + state = Column(String(255)) # sm_types.h + status = Column(String(255)) + condition = Column(String(255)) + + +class sm_node(Base): + __tablename__ = 'nodes' + id = Column(Integer, primary_key=True) + + name = Column(String(255)) + administrative_state = Column(String(255)) # sm_types.h + operational_state = Column(String(255)) + availability_status = Column(String(255)) + ready_state = Column(String(255)) diff --git a/service-mgmt-api/sm-api/sm_api/objects/__init__.py b/service-mgmt-api/sm-api/sm_api/objects/__init__.py new file mode 100644 index 00000000..9869fd5c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/objects/__init__.py @@ -0,0 +1,56 @@ +# Copyright 2013 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import functools + +from sm_api.objects import smo_servicegroup +from sm_api.objects import smo_service +from sm_api.objects import smo_sdm +from sm_api.objects import smo_sda +from sm_api.objects import smo_node + + +def objectify(klass): + """Decorator to convert database results into specified objects.""" + def the_decorator(fn): + @functools.wraps(fn) + def wrapper(*args, **kwargs): + result = fn(*args, **kwargs) + try: + return klass._from_db_object(klass(), result) + except TypeError: + # TODO(deva): handle lists of objects better + # once support for those lands and is imported. + return [klass._from_db_object(klass(), obj) for obj in result] + return wrapper + return the_decorator + + +service_groups = smo_servicegroup.service_groups +service = smo_service.service +sm_sdm = smo_sdm.sm_sdm +sm_sda = smo_sda.sm_sda +sm_node = smo_node.sm_node + +__all__ = ( + service_groups, + service, + sm_sdm, + sm_sda, + sm_node, + objectify) diff --git a/service-mgmt-api/sm-api/sm_api/objects/base.py b/service-mgmt-api/sm-api/sm_api/objects/base.py new file mode 100644 index 00000000..657d18e6 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/objects/base.py @@ -0,0 +1,504 @@ +# Copyright 2013 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Sm common internal object model""" + +import collections + +from sm_api.common import exception +from sm_api.objects import utils as obj_utils +from sm_api.openstack.common import context +from sm_api.openstack.common import log as logging +from sm_api.openstack.common.rpc import common as rpc_common +from sm_api.openstack.common.rpc import serializer as rpc_serializer + + +LOG = logging.getLogger('object') + + +def get_attrname(name): + """Return the mangled name of the attribute's underlying storage.""" + return '_%s' % name + + +def make_class_properties(cls): + # NOTE(danms): Inherit Sm_apiObject's base fields only + cls.fields.update(Sm_apiObject.fields) + for name, typefn in cls.fields.iteritems(): + + def getter(self, name=name): + attrname = get_attrname(name) + if not hasattr(self, attrname): + self.obj_load_attr(name) + return getattr(self, attrname) + + def setter(self, value, name=name, typefn=typefn): + self._changed_fields.add(name) + try: + return setattr(self, get_attrname(name), typefn(value)) + except Exception: + attr = "%s.%s" % (self.obj_name(), name) + LOG.exception(_('Error setting %(attr)s') % + {'attr': attr}) + raise + + setattr(cls, name, property(getter, setter)) + + +class Sm_apiObjectMetaclass(type): + """Metaclass that allows tracking of object classes.""" + + # NOTE(danms): This is what controls whether object operations are + # remoted. If this is not None, use it to remote things over RPC. + indirection_api = None + + def __init__(cls, names, bases, dict_): + if not hasattr(cls, '_obj_classes'): + # This will be set in the 'Sm_apiObject' class. + cls._obj_classes = collections.defaultdict(list) + else: + # Add the subclass to Sm_apiObject._obj_classes + make_class_properties(cls) + cls._obj_classes[cls.obj_name()].append(cls) + + +# These are decorators that mark an object's method as remotable. +# If the metaclass is configured to forward object methods to an +# indirection service, these will result in making an RPC call +# instead of directly calling the implementation in the object. Instead, +# the object implementation on the remote end will perform the +# requested action and the result will be returned here. +def remotable_classmethod(fn): + """Decorator for remotable classmethods.""" + def wrapper(cls, context, *args, **kwargs): + if Sm_apiObject.indirection_api: + result = Sm_apiObject.indirection_api.object_class_action( + context, cls.obj_name(), fn.__name__, cls.version, + args, kwargs) + else: + result = fn(cls, context, *args, **kwargs) + if isinstance(result, Sm_apiObject): + result._context = context + return result + return classmethod(wrapper) + + +# See comment above for remotable_classmethod() +# +# Note that this will use either the provided context, or the one +# stashed in the object. If neither are present, the object is +# "orphaned" and remotable methods cannot be called. +def remotable(fn): + """Decorator for remotable object methods.""" + def wrapper(self, *args, **kwargs): + ctxt = self._context + try: + if isinstance(args[0], (context.RequestContext, + rpc_common.CommonRpcContext)): + ctxt = args[0] + args = args[1:] + except IndexError: + pass + if ctxt is None: + raise exception.OrphanedObjectError(method=fn.__name__, + objtype=self.obj_name()) + if Sm_apiObject.indirection_api: + updates, result = Sm_apiObject.indirection_api.object_action( + ctxt, self, fn.__name__, args, kwargs) + for key, value in updates.iteritems(): + if key in self.fields: + self[key] = self._attr_from_primitive(key, value) + self._changed_fields = set(updates.get('obj_what_changed', [])) + return result + else: + return fn(self, ctxt, *args, **kwargs) + return wrapper + + +# Object versioning rules +# +# Each service has its set of objects, each with a version attached. When +# a client attempts to call an object method, the server checks to see if +# the version of that object matches (in a compatible way) its object +# implementation. If so, cool, and if not, fail. +def check_object_version(server, client): + try: + client_major, _client_minor = client.split('.') + server_major, _server_minor = server.split('.') + client_minor = int(_client_minor) + server_minor = int(_server_minor) + except ValueError: + raise exception.IncompatibleObjectVersion( + _('Invalid version string')) + + if client_major != server_major: + raise exception.IncompatibleObjectVersion( + dict(client=client_major, server=server_major)) + if client_minor > server_minor: + raise exception.IncompatibleObjectVersion( + dict(client=client_minor, server=server_minor)) + + +class Sm_apiObject(object): + """Base class and object factory. + + This forms the base of all objects that can be remoted or instantiated + via RPC. Simply defining a class that inherits from this base class + will make it remotely instantiatable. Objects should implement the + necessary "get" classmethod routines as well as "save" object methods + as appropriate. + """ + __metaclass__ = Sm_apiObjectMetaclass + + # Version of this object (see rules above check_object_version()) + version = '1.0' + + # The fields present in this object as key:typefn pairs. For example: + # + # fields = { 'foo': int, + # 'bar': str, + # 'baz': lambda x: str(x).ljust(8), + # } + # + # NOTE(danms): The base Sm_apiObject class' fields will be inherited + # by subclasses, but that is a special case. Objects inheriting from + # other objects will not receive this merging of fields contents. + fields = {} + # JKUNG until avail 'created_at': obj_utils.datetime_or_str_or_none, + # 'updated_at': obj_utils.datetime_or_str_or_none, + # } + obj_extra_fields = [] + + def __init__(self): + self._changed_fields = set() + self._context = None + + @classmethod + def obj_name(cls): + """Return a canonical name for this object which will be used over + the wire for remote hydration. + """ + return cls.__name__ + + @classmethod + def obj_class_from_name(cls, objname, objver): + """Returns a class from the registry based on a name and version.""" + if objname not in cls._obj_classes: + LOG.error(_('Unable to instantiate unregistered object type ' + '%(objtype)s') % dict(objtype=objname)) + raise exception.UnsupportedObjectError(objtype=objname) + + compatible_match = None + for objclass in cls._obj_classes[objname]: + if objclass.version == objver: + return objclass + try: + check_object_version(objclass.version, objver) + compatible_match = objclass + except exception.IncompatibleObjectVersion: + pass + + if compatible_match: + return compatible_match + + raise exception.IncompatibleObjectVersion(objname=objname, + objver=objver) + + _attr_created_at_from_primitive = obj_utils.dt_deserializer + _attr_updated_at_from_primitive = obj_utils.dt_deserializer + + def _attr_from_primitive(self, attribute, value): + """Attribute deserialization dispatcher. + + This calls self._attr_foo_from_primitive(value) for an attribute + foo with value, if it exists, otherwise it assumes the value + is suitable for the attribute's setter method. + """ + handler = '_attr_%s_from_primitive' % attribute + if hasattr(self, handler): + return getattr(self, handler)(value) + return value + + @classmethod + def obj_from_primitive(cls, primitive, context=None): + """Simple base-case hydration. + + This calls self._attr_from_primitive() for each item in fields. + """ + if primitive['sm_api_object.namespace'] != 'sm_api': + # NOTE(danms): We don't do anything with this now, but it's + # there for "the future" + raise exception.UnsupportedObjectError( + objtype='%s.%s' % (primitive['sm_api_object.namespace'], + primitive['sm_api_object.name'])) + objname = primitive['sm_api_object.name'] + objver = primitive['sm_api_object.version'] + objdata = primitive['sm_api_object.data'] + objclass = cls.obj_class_from_name(objname, objver) + self = objclass() + self._context = context + for name in self.fields: + if name in objdata: + setattr(self, name, + self._attr_from_primitive(name, objdata[name])) + changes = primitive.get('sm_api_object.changes', []) + self._changed_fields = set([x for x in changes if x in self.fields]) + return self + + _attr_created_at_to_primitive = obj_utils.dt_serializer('created_at') + _attr_updated_at_to_primitive = obj_utils.dt_serializer('updated_at') + + def _attr_to_primitive(self, attribute): + """Attribute serialization dispatcher. + + This calls self._attr_foo_to_primitive() for an attribute foo, + if it exists, otherwise it assumes the attribute itself is + primitive-enough to be sent over the RPC wire. + """ + handler = '_attr_%s_to_primitive' % attribute + if hasattr(self, handler): + return getattr(self, handler)() + else: + return getattr(self, attribute) + + def obj_to_primitive(self): + """Simple base-case dehydration. + + This calls self._attr_to_primitive() for each item in fields. + """ + primitive = dict() + for name in self.fields: + if hasattr(self, get_attrname(name)): + primitive[name] = self._attr_to_primitive(name) + obj = {'sm_api_object.name': self.obj_name(), + 'sm_api_object.namespace': 'sm_api', + 'sm_api_object.version': self.version, + 'sm_api_object.data': primitive} + if self.obj_what_changed(): + obj['sm_api_object.changes'] = list(self.obj_what_changed()) + return obj + + def obj_load_attr(self, attrname): + """Load an additional attribute from the real object. + + This should use self._conductor, and cache any data that might + be useful for future load operations. + """ + raise NotImplementedError( + _("Cannot load '%(attrname)s' in the base class") % + {'attrname': attrname}) + + def save(self, context): + """Save the changed fields back to the store. + + This is optional for subclasses, but is presented here in the base + class for consistency among those that do. + """ + raise NotImplementedError('Cannot save anything in the base class') + + def obj_what_changed(self): + """Returns a set of fields that have been modified.""" + return self._changed_fields + + def obj_reset_changes(self, fields=None): + """Reset the list of fields that have been changed. + + Note that this is NOT "revert to previous values" + """ + if fields: + self._changed_fields -= set(fields) + else: + self._changed_fields.clear() + + # dictish syntactic sugar + def iteritems(self): + """For backwards-compatibility with dict-based objects. + + NOTE(danms): May be removed in the future. + """ + for name in self.fields.keys() + self.obj_extra_fields: + if (hasattr(self, get_attrname(name)) or + name in self.obj_extra_fields): + yield name, getattr(self, name) + + items = lambda self: list(self.iteritems()) + + def __getitem__(self, name): + """For backwards-compatibility with dict-based objects. + + NOTE(danms): May be removed in the future. + """ + return getattr(self, name) + + def __setitem__(self, name, value): + """For backwards-compatibility with dict-based objects. + + NOTE(danms): May be removed in the future. + """ + setattr(self, name, value) + + def __contains__(self, name): + """For backwards-compatibility with dict-based objects. + + NOTE(danms): May be removed in the future. + """ + return hasattr(self, get_attrname(name)) + + def get(self, key, value=None): + """For backwards-compatibility with dict-based objects. + + NOTE(danms): May be removed in the future. + """ + return self[key] + + def update(self, updates): + """For backwards-compatibility with dict-base objects. + + NOTE(danms): May be removed in the future. + """ + for key, value in updates.items(): + self[key] = value + + def as_dict(self): + return dict((k, getattr(self, k)) + for k in self.fields + if hasattr(self, k)) + + @classmethod + def get_defaults(cls): + """Return a dict of its fields with their default value.""" + return dict((k, v(None)) + for k, v in cls.fields.iteritems() + if k != "id" and callable(v)) + + +class ObjectListBase(object): + """Mixin class for lists of objects. + + This mixin class can be added as a base class for an object that + is implementing a list of objects. It adds a single field of 'objects', + which is the list store, and behaves like a list itself. It supports + serialization of the list of objects automatically. + """ + fields = { + 'objects': list, + } + + def __iter__(self): + """List iterator interface.""" + return iter(self.objects) + + def __len__(self): + """List length.""" + return len(self.objects) + + def __getitem__(self, index): + """List index access.""" + if isinstance(index, slice): + new_obj = self.__class__() + new_obj.objects = self.objects[index] + # NOTE(danms): We must be mixed in with an Sm_apiObject! + new_obj.obj_reset_changes() + new_obj._context = self._context + return new_obj + return self.objects[index] + + def __contains__(self, value): + """List membership test.""" + return value in self.objects + + def count(self, value): + """List count of value occurrences.""" + return self.objects.count(value) + + def index(self, value): + """List index of value.""" + return self.objects.index(value) + + def _attr_objects_to_primitive(self): + """Serialization of object list.""" + return [x.obj_to_primitive() for x in self.objects] + + def _attr_objects_from_primitive(self, value): + """Deserialization of object list.""" + objects = [] + for entity in value: + obj = Sm_apiObject.obj_from_primitive(entity, + context=self._context) + objects.append(obj) + return objects + + +class Sm_apiObjectSerializer(rpc_serializer.Serializer): + """A Sm_apiObject-aware Serializer. + + This implements the Oslo Serializer interface and provides the + ability to serialize and deserialize Sm_apiObject entities. Any service + that needs to accept or return Sm_apiObjects as arguments or result values + should pass this to its RpcProxy and RpcDispatcher objects. + """ + + def _process_iterable(self, context, action_fn, values): + """Process an iterable, taking an action on each value. + :param:context: Request context + :param:action_fn: Action to take on each item in values + :param:values: Iterable container of things to take action on + :returns: A new container of the same type (except set) with + items from values having had action applied. + """ + iterable = values.__class__ + if iterable == set: + # NOTE(danms): A set can't have an unhashable value inside, such as + # a dict. Convert sets to tuples, which is fine, since we can't + # send them over RPC anyway. + iterable = tuple + return iterable([action_fn(context, value) for value in values]) + + def serialize_entity(self, context, entity): + if isinstance(entity, (tuple, list, set)): + entity = self._process_iterable(context, self.serialize_entity, + entity) + elif (hasattr(entity, 'obj_to_primitive') and + callable(entity.obj_to_primitive)): + entity = entity.obj_to_primitive() + return entity + + def deserialize_entity(self, context, entity): + if isinstance(entity, dict) and 'sm_api_object.name' in entity: + entity = Sm_apiObject.obj_from_primitive(entity, context=context) + elif isinstance(entity, (tuple, list, set)): + entity = self._process_iterable(context, self.deserialize_entity, + entity) + return entity + + +def obj_to_primitive(obj): + """Recursively turn an object into a python primitive. + + An Sm_apiObject becomes a dict, and anything that implements ObjectListBase + becomes a list. + """ + if isinstance(obj, ObjectListBase): + return [obj_to_primitive(x) for x in obj] + elif isinstance(obj, Sm_apiObject): + result = {} + for key, value in obj.iteritems(): + result[key] = obj_to_primitive(value) + return result + else: + return obj diff --git a/service-mgmt-api/sm-api/sm_api/objects/smo_node.py b/service-mgmt-api/sm-api/sm_api/objects/smo_node.py new file mode 100644 index 00000000..603e456c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/objects/smo_node.py @@ -0,0 +1,72 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# coding=utf-8 +# + +from sm_api.db import api as db_api +from sm_api.objects import base +from sm_api.objects import utils + +class sm_node(base.Sm_apiObject): + + dbapi = db_api.get_instance() + + fields = { + 'id': int, + 'name': utils.str_or_none, + 'administrative_state': utils.str_or_none, + 'operational_state': utils.str_or_none, + 'availability_status': utils.str_or_none, + 'ready_state': utils.str_or_none, + } + + @staticmethod + def _from_db_object(server, db_server): + """Converts a database entity to a formal object.""" + for field in server.fields: + server[field] = db_server[field] + + server.obj_reset_changes() + return server + + @base.remotable_classmethod + def get_by_uuid(cls, context, uuid): + """Find a server based on uuid and return a Node object. + + :param uuid: the uuid of a server. + :returns: a :class:`Node` object. + """ + db_server = cls.dbapi.sm_node_get(uuid) + return sm_node._from_db_object(cls(), db_server) + + # @base.remotable + # def save(self, context): + # """Save updates to this Node. + + # Column-wise updates will be made based on the result of + # self.what_changed(). If target_power_state is provided, + # it will be checked against the in-database copy of the + # server before updates are made. + + # :param context: Security context + # """ + # updates = {} + # changes = self.obj_what_changed() + # for field in changes: + # updates[field] = self[field] + # self.dbapi.sm_node_update(self.uuid, updates) + # + # self.obj_reset_changes() + + @base.remotable + def refresh(self, context): + current = self.__class__.get_by_uuid(context, uuid=self.uuid) + for field in self.fields: + if (hasattr(self, base.get_attrname(field)) and + self[field] != current[field]): + self[field] = current[field] diff --git a/service-mgmt-api/sm-api/sm_api/objects/smo_sda.py b/service-mgmt-api/sm-api/sm_api/objects/smo_sda.py new file mode 100755 index 00000000..2c4ad036 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/objects/smo_sda.py @@ -0,0 +1,81 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# coding=utf-8 +# + +from sm_api.db import api as db_api +from sm_api.objects import base +from sm_api.objects import utils + + +class sm_sda(base.Sm_apiObject): + + dbapi = db_api.get_instance() + + fields = { + 'id': int, + 'uuid': utils.str_or_none, + # 'deleted': utils.str_or_none, + + # 'created_at': utils.datetime_str_or_none, + # 'updated_at': utils.datetime_str_or_none, + 'name': utils.str_or_none, + 'node_name': utils.str_or_none, + 'service_group_name': utils.str_or_none, + 'state': utils.str_or_none, + 'desired_state': utils.str_or_none, + 'status': utils.str_or_none, + 'condition': utils.str_or_none, + } + + @staticmethod + def _from_db_object(server, db_server): + """Converts a database entity to a formal object.""" + for field in server.fields: + server[field] = db_server[field] + + server.obj_reset_changes() + return server + + @base.remotable_classmethod + def get_by_uuid(cls, context, uuid): + """Find a server based on uuid and return a Node object. + + :param uuid: the uuid of a server. + :returns: a :class:`Node` object. + """ + # TODO(deva): enable getting ports for this server + db_server = cls.dbapi.sm_sda_get(uuid) + return sm_sda._from_db_object(cls(), db_server) + + # @base.remotable + # def save(self, context): + # """Save updates to this Node. + + # Column-wise updates will be made based on the result of + # self.what_changed(). If target_power_state is provided, + # it will be checked against the in-database copy of the + # server before updates are made. + + # :param context: Security context + # """ + # updates = {} + # changes = self.obj_what_changed() + # for field in changes: + # updates[field] = self[field] + # self.dbapi.sm_sda_update(self.uuid, updates) + # + # self.obj_reset_changes() + + @base.remotable + def refresh(self, context): + current = self.__class__.get_by_uuid(context, uuid=self.uuid) + for field in self.fields: + if (hasattr(self, base.get_attrname(field)) and + self[field] != current[field]): + self[field] = current[field] diff --git a/service-mgmt-api/sm-api/sm_api/objects/smo_sdm.py b/service-mgmt-api/sm-api/sm_api/objects/smo_sdm.py new file mode 100644 index 00000000..03c616bb --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/objects/smo_sdm.py @@ -0,0 +1,72 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# coding=utf-8 +# + +from sm_api.db import api as db_api +from sm_api.objects import base +from sm_api.objects import utils + + +class sm_sdm(base.Sm_apiObject): + + dbapi = db_api.get_instance() + + fields = { + 'id': int, + 'name': utils.str_or_none, + 'service_group_name': utils.str_or_none, + 'redundancy_model': utils.str_or_none, + } + + @staticmethod + def _from_db_object(server, db_server): + """Converts a database entity to a formal object.""" + for field in server.fields: + server[field] = db_server[field] + + server.obj_reset_changes() + return server + + @base.remotable_classmethod + def get_by_uuid(cls, context, uuid): + """Find a server based on uuid and return a Node object. + + :param uuid: the uuid of a server. + :returns: a :class:`Node` object. + """ + # TODO(deva): enable getting ports for this server + db_server = cls.dbapi.sm_sda_get(uuid) + return sm_sda._from_db_object(cls(), db_server) + + # @base.remotable + # def save(self, context): + # """Save updates to this Node. + + # Column-wise updates will be made based on the result of + # self.what_changed(). If target_power_state is provided, + # it will be checked against the in-database copy of the + # server before updates are made. + + # :param context: Security context + # """ + # updates = {} + # changes = self.obj_what_changed() + # for field in changes: + # updates[field] = self[field] + # self.dbapi.sm_sda_update(self.uuid, updates) + # + # self.obj_reset_changes() + + @base.remotable + def refresh(self, context): + current = self.__class__.get_by_uuid(context, uuid=self.uuid) + for field in self.fields: + if (hasattr(self, base.get_attrname(field)) and + self[field] != current[field]): + self[field] = current[field] diff --git a/service-mgmt-api/sm-api/sm_api/objects/smo_service.py b/service-mgmt-api/sm-api/sm_api/objects/smo_service.py new file mode 100644 index 00000000..73cc53b7 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/objects/smo_service.py @@ -0,0 +1,77 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# coding=utf-8 +# + +from sm_api.db import api as db_api +from sm_api.objects import base +from sm_api.objects import utils + + +class service(base.Sm_apiObject): + + dbapi = db_api.get_instance() + + fields = { + 'id': int, + 'name': utils.str_or_none, + 'desired_state': utils.str_or_none, + 'state': utils.str_or_none, + 'status': utils.str_or_none, + } + + @staticmethod + def _from_db_object(server, db_server): + """Converts a database entity to a formal object.""" + for field in server.fields: + server[field] = db_server[field] + + server.obj_reset_changes() + return server + + @base.remotable_classmethod + def get_by_uuid(cls, context, uuid): + """Find a server based on uuid and return a Node object. + + :param uuid: the uuid of a server. + :returns: a :class:`Node` object. + """ + # TODO(deva): enable getting ports for this server + db_server = cls.dbapi.sm_service_get(uuid) + return service._from_db_object(cls(), db_server) + + @base.remotable + def save(self, context): + """Save updates to this Node. + + Column-wise updates will be made based on the result of + self.what_changed(). If target_power_state is provided, + it will be checked against the in-database copy of the + server before updates are made. + + :param context: Security context + """ + # TODO(deva): enforce safe limits on what fields may be changed + # depending on state. Eg., do not allow changing + # instance_uuid of an already-provisioned server. + # Raise exception if unsafe to change something. + updates = {} + changes = self.obj_what_changed() + for field in changes: + updates[field] = self[field] + self.dbapi.sm_service_update(self.uuid, updates) + + self.obj_reset_changes() + + @base.remotable + def refresh(self, context): + current = self.__class__.get_by_uuid(context, uuid=self.uuid) + for field in self.fields: + if (hasattr(self, base.get_attrname(field)) and + self[field] != current[field]): + self[field] = current[field] diff --git a/service-mgmt-api/sm-api/sm_api/objects/smo_servicegroup.py b/service-mgmt-api/sm-api/sm_api/objects/smo_servicegroup.py new file mode 100644 index 00000000..0e7e5db7 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/objects/smo_servicegroup.py @@ -0,0 +1,80 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 +# coding=utf-8 +# + +from sm_api.db import api as db_api +from sm_api.objects import base +from sm_api.objects import utils + + +class service_groups(base.Sm_apiObject): + + dbapi = db_api.get_instance() + + fields = { + 'id': utils.int_or_none, + # 'uuid': utils.str_or_none, + # 'deleted': utils.str_or_none, + + # 'created_at': utils.datetime_str_or_none, + # 'updated_at': utils.datetime_str_or_none, + 'name': utils.str_or_none, + 'state': utils.str_or_none, + 'status': utils.str_or_none, + } + + @staticmethod + def _from_db_object(server, db_server): + """Converts a database entity to a formal object.""" + for field in server.fields: + server[field] = db_server[field] + + server.obj_reset_changes() + return server + + @base.remotable_classmethod + def get_by_uuid(cls, context, uuid): + """Find a server based on uuid and return a Node object. + + :param uuid: the uuid of a server. + :returns: a :class:`Node` object. + """ + db_server = cls.dbapi.iservicegroup_get(uuid) + return service_groups._from_db_object(cls(), db_server) + + @base.remotable + def save(self, context): + """Save updates to this Node. + + Column-wise updates will be made based on the result of + self.what_changed(). If target_power_state is provided, + it will be checked against the in-database copy of the + server before updates are made. + + :param context: Security context + """ + # TODO(deva): enforce safe limits on what fields may be changed + # depending on state. Eg., do not allow changing + # instance_uuid of an already-provisioned server. + # Raise exception if unsafe to change something. + updates = {} + changes = self.obj_what_changed() + for field in changes: + updates[field] = self[field] + self.dbapi.iservicegroup_update(self.uuid, updates) + + self.obj_reset_changes() + + @base.remotable + def refresh(self, context): + current = self.__class__.get_by_uuid(context, uuid=self.uuid) + for field in self.fields: + if (hasattr(self, base.get_attrname(field)) and + self[field] != current[field]): + self[field] = current[field] diff --git a/service-mgmt-api/sm-api/sm_api/objects/utils.py b/service-mgmt-api/sm-api/sm_api/objects/utils.py new file mode 100644 index 00000000..c641920b --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/objects/utils.py @@ -0,0 +1,129 @@ +# Copyright 2013 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Utility methods for objects""" + +import ast +import datetime +import iso8601 +import netaddr + +from sm_api.openstack.common import timeutils + + +def datetime_or_none(dt): + """Validate a datetime or None value.""" + if dt is None: + return None + elif isinstance(dt, datetime.datetime): + if dt.utcoffset() is None: + # NOTE(danms): Legacy objects from sqlalchemy are stored in UTC, + # but are returned without a timezone attached. + # As a transitional aid, assume a tz-naive object is in UTC. + return dt.replace(tzinfo=iso8601.iso8601.Utc()) + else: + return dt + raise ValueError('A datetime.datetime is required here') + + +def datetime_or_str_or_none(val): + if isinstance(val, basestring): + return timeutils.parse_isotime(val) + return datetime_or_none(val) + + +def int_or_none(val): + """Attempt to parse an integer value, or None.""" + if val is None: + return val + else: + return int(val) + + +def int_or_zero(val): + """Attempt to parse an integer value, if None return zero.""" + if val is None: + return int(0) + else: + return int(val) + + +def str_or_none(val): + """Attempt to stringify a value, or None.""" + if val is None: + return val + else: + return str(val) + + +def dict_or_none(val): + """Attempt to dictify a value, or None.""" + if val is None: + return {} + elif isinstance(val, str): + return dict(ast.literal_eval(val)) + else: + try: + return dict(val) + except ValueError: + return {} + + +def ip_or_none(version): + """Return a version-specific IP address validator.""" + def validator(val, version=version): + if val is None: + return val + else: + return netaddr.IPAddress(val, version=version) + return validator + + +def nested_object_or_none(objclass): + def validator(val, objclass=objclass): + if val is None or isinstance(val, objclass): + return val + raise ValueError('An object of class %s is required here' % objclass) + return validator + + +def dt_serializer(name): + """Return a datetime serializer for a named attribute.""" + def serializer(self, name=name): + if getattr(self, name) is not None: + return timeutils.isotime(getattr(self, name)) + else: + return None + return serializer + + +def dt_deserializer(instance, val): + """A deserializer method for datetime attributes.""" + if val is None: + return None + else: + return timeutils.parse_isotime(val) + + +def obj_serializer(name): + def serializer(self, name=name): + if getattr(self, name) is not None: + return getattr(self, name).obj_to_primitive() + else: + return None + return serializer diff --git a/service-mgmt-api/sm-api/sm_api/openstack/__init__.py b/service-mgmt-api/sm-api/sm_api/openstack/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/__init__.py b/service-mgmt-api/sm-api/sm_api/openstack/common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/cliutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/cliutils.py new file mode 100644 index 00000000..4e37ff8f --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/cliutils.py @@ -0,0 +1,67 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import inspect + + +class MissingArgs(Exception): + + def __init__(self, missing): + self.missing = missing + + def __str__(self): + if len(self.missing) == 1: + return "An argument is missing" + else: + return ("%(num)d arguments are missing" % + dict(num=len(self.missing))) + + +def validate_args(fn, *args, **kwargs): + """Check that the supplied args are sufficient for calling a function. + + >>> validate_args(lambda a: None) + Traceback (most recent call last): + ... + MissingArgs: An argument is missing + >>> validate_args(lambda a, b, c, d: None, 0, c=1) + Traceback (most recent call last): + ... + MissingArgs: 2 arguments are missing + + :param fn: the function to check + :param arg: the positional arguments supplied + :param kwargs: the keyword arguments supplied + """ + argspec = inspect.getargspec(fn) + + num_defaults = len(argspec.defaults or []) + required_args = argspec.args[:len(argspec.args) - num_defaults] + + def isbound(method): + return getattr(method, 'im_self', None) is not None + + if isbound(fn): + required_args.pop(0) + + missing = [arg for arg in required_args if arg not in kwargs] + missing = missing[len(args):] + if missing: + raise MissingArgs(missing) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/config/generator.py b/service-mgmt-api/sm-api/sm_api/openstack/common/config/generator.py new file mode 100755 index 00000000..9e555c90 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/config/generator.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 SINA Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +# +# @author: Zhongyue Luo, SINA Corporation. +# +"""Extracts OpenStack config option info from module(s).""" + +import imp +import os +import re +import socket +import sys +import textwrap + +from oslo_config import cfg + +from sm_api.openstack.common import gettextutils +from sm_api.openstack.common import importutils + +gettextutils.install('sm_api') + +STROPT = "StrOpt" +BOOLOPT = "BoolOpt" +INTOPT = "IntOpt" +FLOATOPT = "FloatOpt" +LISTOPT = "ListOpt" +MULTISTROPT = "MultiStrOpt" + +OPT_TYPES = { + STROPT: 'string value', + BOOLOPT: 'boolean value', + INTOPT: 'integer value', + FLOATOPT: 'floating point value', + LISTOPT: 'list value', + MULTISTROPT: 'multi valued', +} + +OPTION_COUNT = 0 +OPTION_REGEX = re.compile(r"(%s)" % "|".join([STROPT, BOOLOPT, INTOPT, + FLOATOPT, LISTOPT, + MULTISTROPT])) + +PY_EXT = ".py" +BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), + "../../../../")) +WORDWRAP_WIDTH = 60 + + +def generate(srcfiles): + mods_by_pkg = dict() + for filepath in srcfiles: + pkg_name = filepath.split(os.sep)[1] + mod_str = '.'.join(['.'.join(filepath.split(os.sep)[:-1]), + os.path.basename(filepath).split('.')[0]]) + mods_by_pkg.setdefault(pkg_name, list()).append(mod_str) + # NOTE(lzyeval): place top level modules before packages + pkg_names = filter(lambda x: x.endswith(PY_EXT), mods_by_pkg.keys()) + pkg_names.sort() + ext_names = filter(lambda x: x not in pkg_names, mods_by_pkg.keys()) + ext_names.sort() + pkg_names.extend(ext_names) + + # opts_by_group is a mapping of group name to an options list + # The options list is a list of (module, options) tuples + opts_by_group = {'DEFAULT': []} + + for pkg_name in pkg_names: + mods = mods_by_pkg.get(pkg_name) + mods.sort() + for mod_str in mods: + if mod_str.endswith('.__init__'): + mod_str = mod_str[:mod_str.rfind(".")] + + mod_obj = _import_module(mod_str) + if not mod_obj: + continue + + for group, opts in _list_opts(mod_obj): + opts_by_group.setdefault(group, []).append((mod_str, opts)) + + print_group_opts('DEFAULT', opts_by_group.pop('DEFAULT', [])) + for group, opts in opts_by_group.items(): + print_group_opts(group, opts) + + print "# Total option count: %d" % OPTION_COUNT + + +def _import_module(mod_str): + try: + if mod_str.startswith('bin.'): + imp.load_source(mod_str[4:], os.path.join('bin', mod_str[4:])) + return sys.modules[mod_str[4:]] + else: + return importutils.import_module(mod_str) + except ImportError as ie: + sys.stderr.write("%s\n" % str(ie)) + return None + except Exception: + return None + + +def _is_in_group(opt, group): + "Check if opt is in group." + for key, value in group._opts.items(): + if value['opt'] == opt: + return True + return False + + +def _guess_groups(opt, mod_obj): + # is it in the DEFAULT group? + if _is_in_group(opt, cfg.CONF): + return 'DEFAULT' + + # what other groups is it in? + for key, value in cfg.CONF.items(): + if isinstance(value, cfg.CONF.GroupAttr): + if _is_in_group(opt, value._group): + return value._group.name + + raise RuntimeError( + "Unable to find group for option %s, " + "maybe it's defined twice in the same group?" + % opt.name + ) + + +def _list_opts(obj): + def is_opt(o): + return (isinstance(o, cfg.Opt) and + not isinstance(o, cfg.SubCommandOpt)) + + opts = list() + for attr_str in dir(obj): + attr_obj = getattr(obj, attr_str) + if is_opt(attr_obj): + opts.append(attr_obj) + elif (isinstance(attr_obj, list) and + all(map(lambda x: is_opt(x), attr_obj))): + opts.extend(attr_obj) + + ret = {} + for opt in opts: + ret.setdefault(_guess_groups(opt, obj), []).append(opt) + return ret.items() + + +def print_group_opts(group, opts_by_module): + print "[%s]" % group + print + global OPTION_COUNT + for mod, opts in opts_by_module: + OPTION_COUNT += len(opts) + print '#' + print '# Options defined in %s' % mod + print '#' + print + for opt in opts: + _print_opt(opt) + print + + +def _get_my_ip(): + try: + csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + csock.connect(('8.8.8.8', 80)) + (addr, port) = csock.getsockname() + csock.close() + return addr + except socket.error: + return None + + +def _sanitize_default(s): + """Set up a reasonably sensible default for pybasedir, my_ip and host.""" + if s.startswith(BASEDIR): + return s.replace(BASEDIR, '/usr/lib/python/site-packages') + elif BASEDIR in s: + return s.replace(BASEDIR, '') + elif s == _get_my_ip(): + return '10.0.0.1' + elif s == socket.gethostname(): + return 'sm_api' + elif s.strip() != s: + return '"%s"' % s + return s + + +def _print_opt(opt): + opt_name, opt_default, opt_help = opt.dest, opt.default, opt.help + if not opt_help: + sys.stderr.write('WARNING: "%s" is missing help string.\n' % opt_name) + opt_type = None + try: + opt_type = OPTION_REGEX.search(str(type(opt))).group(0) + except (ValueError, AttributeError) as err: + sys.stderr.write("%s\n" % str(err)) + sys.exit(1) + opt_help += ' (' + OPT_TYPES[opt_type] + ')' + print '#', "\n# ".join(textwrap.wrap(opt_help, WORDWRAP_WIDTH)) + try: + if opt_default is None: + print '#%s=' % opt_name + elif opt_type == STROPT: + assert(isinstance(opt_default, basestring)) + print '#%s=%s' % (opt_name, _sanitize_default(opt_default)) + elif opt_type == BOOLOPT: + assert(isinstance(opt_default, bool)) + print '#%s=%s' % (opt_name, str(opt_default).lower()) + elif opt_type == INTOPT: + assert(isinstance(opt_default, int) and + not isinstance(opt_default, bool)) + print '#%s=%s' % (opt_name, opt_default) + elif opt_type == FLOATOPT: + assert(isinstance(opt_default, float)) + print '#%s=%s' % (opt_name, opt_default) + elif opt_type == LISTOPT: + assert(isinstance(opt_default, list)) + print '#%s=%s' % (opt_name, ','.join(opt_default)) + elif opt_type == MULTISTROPT: + assert(isinstance(opt_default, list)) + if not opt_default: + opt_default = [''] + for default in opt_default: + print '#%s=%s' % (opt_name, default) + print + except Exception: + sys.stderr.write('Error in option "%s"\n' % opt_name) + sys.exit(1) + + +def main(): + if len(sys.argv) < 2: + print "usage: %s [srcfile]...\n" % sys.argv[0] + sys.exit(0) + generate(sys.argv[1:]) + +if __name__ == '__main__': + main() diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/context.py b/service-mgmt-api/sm-api/sm_api/openstack/common/context.py new file mode 100644 index 00000000..bc47846d --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/context.py @@ -0,0 +1,86 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Simple class that stores security context information in the web request. + +Projects should subclass this class if they wish to enhance the request +context or provide additional information in their specific WSGI pipeline. +""" + +import itertools + +from sm_api.openstack.common import uuidutils + + +def generate_request_id(): + return 'req-%s' % uuidutils.generate_uuid() + + +class RequestContext(object): + + """ + Stores information about the security context under which the user + accesses the system, as well as additional request information. + """ + + def __init__(self, auth_token=None, user=None, tenant=None, is_admin=False, + read_only=False, show_deleted=False, request_id=None): + self.auth_token = auth_token + self.user = user + self.tenant = tenant + self.is_admin = is_admin + self.read_only = read_only + self.show_deleted = show_deleted + if not request_id: + request_id = generate_request_id() + self.request_id = request_id + + def to_dict(self): + return {'user': self.user, + 'tenant': self.tenant, + 'is_admin': self.is_admin, + 'read_only': self.read_only, + 'show_deleted': self.show_deleted, + 'auth_token': self.auth_token, + 'request_id': self.request_id} + + +def get_admin_context(show_deleted="no"): + context = RequestContext(None, + tenant=None, + is_admin=True, + show_deleted=show_deleted) + return context + + +def get_context_from_function_and_args(function, args, kwargs): + """Find an arg of type RequestContext and return it. + + This is useful in a couple of decorators where we don't + know much about the function we're wrapping. + """ + + for arg in itertools.chain(kwargs.values(), args): + if isinstance(arg, RequestContext): + return arg + + return None diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/db/__init__.py b/service-mgmt-api/sm-api/sm_api/openstack/common/db/__init__.py new file mode 100644 index 00000000..0d617c5c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/db/__init__.py @@ -0,0 +1,20 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Cloudscaling Group, Inc +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/db/api.py b/service-mgmt-api/sm-api/sm_api/openstack/common/db/api.py new file mode 100644 index 00000000..30c0a27d --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/db/api.py @@ -0,0 +1,110 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2013 Rackspace Hosting +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Multiple DB API backend support. + +Supported configuration options: + +The following two parameters are in the 'database' group: +`backend`: DB backend name or full module path to DB backend module. +`use_tpool`: Enable thread pooling of DB API calls. + +A DB backend module should implement a method named 'get_backend' which +takes no arguments. The method can return any object that implements DB +API methods. + +*NOTE*: There are bugs in eventlet when using tpool combined with +threading locks. The python logging module happens to use such locks. To +work around this issue, be sure to specify thread=False with +eventlet.monkey_patch(). + +A bug for eventlet has been filed here: + +https://bitbucket.org/eventlet/eventlet/issue/137/ +""" +import functools + +from oslo_config import cfg + +from sm_api.openstack.common import importutils +from sm_api.openstack.common import lockutils + + +db_opts = [ + cfg.StrOpt('backend', + default='sqlalchemy', + deprecated_name='db_backend', + deprecated_group='DEFAULT', + help='The backend to use for db'), + cfg.BoolOpt('use_tpool', + default=False, + deprecated_name='dbapi_use_tpool', + deprecated_group='DEFAULT', + help='Enable the experimental use of thread pooling for ' + 'all DB API calls') +] + +CONF = cfg.CONF +CONF.register_opts(db_opts, 'database') + + +class DBAPI(object): + def __init__(self, backend_mapping=None): + if backend_mapping is None: + backend_mapping = {} + self.__backend = None + self.__backend_mapping = backend_mapping + + @lockutils.synchronized('dbapi_backend', 'sm_api-') + def __get_backend(self): + """Get the actual backend. May be a module or an instance of + a class. Doesn't matter to us. We do this synchronized as it's + possible multiple greenthreads started very quickly trying to do + DB calls and eventlet can switch threads before self.__backend gets + assigned. + """ + if self.__backend: + # Another thread assigned it + return self.__backend + backend_name = CONF.database.backend + self.__use_tpool = CONF.database.use_tpool + if self.__use_tpool: + from eventlet import tpool + self.__tpool = tpool + # Import the untranslated name if we don't have a + # mapping. + backend_path = self.__backend_mapping.get(backend_name, + backend_name) + backend_mod = importutils.import_module(backend_path) + self.__backend = backend_mod.get_backend() + return self.__backend + + def __getattr__(self, key): + backend = self.__backend or self.__get_backend() + attr = getattr(backend, key) + if not self.__use_tpool or not hasattr(attr, '__call__'): + return attr + + def tpool_wrapper(*args, **kwargs): + return self.__tpool.execute(attr, *args, **kwargs) + + functools.update_wrapper(tpool_wrapper, attr) + return tpool_wrapper diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/db/exception.py b/service-mgmt-api/sm-api/sm_api/openstack/common/db/exception.py new file mode 100644 index 00000000..b88c799e --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/db/exception.py @@ -0,0 +1,58 @@ +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""DB related custom exceptions.""" + +from sm_api.openstack.common.gettextutils import _ # noqa + + +class DBError(Exception): + """Wraps an implementation specific exception.""" + def __init__(self, inner_exception=None): + self.inner_exception = inner_exception + super(DBError, self).__init__(str(inner_exception)) + + +class DBDuplicateEntry(DBError): + """Wraps an implementation specific exception.""" + def __init__(self, columns=[], inner_exception=None): + self.columns = columns + super(DBDuplicateEntry, self).__init__(inner_exception) + + +class DBDeadlock(DBError): + def __init__(self, inner_exception=None): + super(DBDeadlock, self).__init__(inner_exception) + + +class DBInvalidUnicodeParameter(Exception): + message = _("Invalid Parameter: " + "Unicode is not supported by the current database.") + + +class DbMigrationError(DBError): + """Wraps migration specific exception.""" + def __init__(self, message=None): + super(DbMigrationError, self).__init__(str(message)) + + +class DBConnectionError(DBError): + """Wraps connection specific exception.""" + pass diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/__init__.py b/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/__init__.py new file mode 100644 index 00000000..0d617c5c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/__init__.py @@ -0,0 +1,20 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Cloudscaling Group, Inc +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/models.py b/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/models.py new file mode 100644 index 00000000..bcbaff96 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/models.py @@ -0,0 +1,109 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 X.commerce, a business unit of eBay Inc. +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Piston Cloud Computing, Inc. +# Copyright 2012 Cloudscaling Group, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +""" +SQLAlchemy models. +""" + +from sqlalchemy import Column, Integer +from sqlalchemy import DateTime +from sqlalchemy.orm import object_mapper + +from sm_api.openstack.common.db.sqlalchemy.session import get_session +from sm_api.openstack.common import timeutils + + +class ModelBase(object): + """Base class for models.""" + __table_initialized__ = False + + def save(self, session=None): + """Save this object.""" + if not session: + session = get_session() + # NOTE(boris-42): This part of code should be look like: + # sesssion.add(self) + # session.flush() + # But there is a bug in sqlalchemy and eventlet that + # raises NoneType exception if there is no running + # transaction and rollback is called. As long as + # sqlalchemy has this bug we have to create transaction + # explicity. + with session.begin(subtransactions=True): + session.add(self) + session.flush() + + def __setitem__(self, key, value): + setattr(self, key, value) + + def __getitem__(self, key): + return getattr(self, key) + + def get(self, key, default=None): + return getattr(self, key, default) + + def __iter__(self): + columns = dict(object_mapper(self).columns).keys() + # NOTE(russellb): Allow models to specify other keys that can be looked + # up, beyond the actual db columns. An example would be the 'name' + # property for an Instance. + if hasattr(self, '_extra_keys'): + columns.extend(self._extra_keys()) + self._i = iter(columns) + return self + + def next(self): + n = self._i.next() + return n, getattr(self, n) + + def update(self, values): + """Make the model object behave like a dict.""" + for k, v in values.iteritems(): + setattr(self, k, v) + + def iteritems(self): + """Make the model object behave like a dict. + + Includes attributes from joins.""" + local = dict(self) + joined = dict([(k, v) for k, v in self.__dict__.iteritems() + if not k[0] == '_']) + local.update(joined) + return local.iteritems() + + +class TimestampMixin(object): + created_at = Column(DateTime, default=timeutils.utcnow) + updated_at = Column(DateTime, onupdate=timeutils.utcnow) + + +class SoftDeleteMixin(object): + deleted_at = Column(DateTime) + deleted = Column(Integer, default=0) + + def soft_delete(self, session=None): + """Mark this object as deleted.""" + self.deleted = self.id + self.deleted_at = timeutils.utcnow() + self.save(session=session) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/session.py b/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/session.py new file mode 100644 index 00000000..3250e0c4 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/session.py @@ -0,0 +1,700 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Session Handling for SQLAlchemy backend. + +Initializing: + +* Call set_defaults with the minimal of the following kwargs: + sql_connection, sqlite_db + + Example: + + session.set_defaults( + sql_connection="sqlite:///var/lib/sm_api/sqlite.db", + sqlite_db="/var/lib/sm_api/sqlite.db") + +Recommended ways to use sessions within this framework: + +* Don't use them explicitly; this is like running with AUTOCOMMIT=1. + model_query() will implicitly use a session when called without one + supplied. This is the ideal situation because it will allow queries + to be automatically retried if the database connection is interrupted. + + Note: Automatic retry will be enabled in a future patch. + + It is generally fine to issue several queries in a row like this. Even though + they may be run in separate transactions and/or separate sessions, each one + will see the data from the prior calls. If needed, undo- or rollback-like + functionality should be handled at a logical level. For an example, look at + the code around quotas and reservation_rollback(). + + Examples: + + def get_foo(context, foo): + return model_query(context, models.Foo).\ + filter_by(foo=foo).\ + first() + + def update_foo(context, id, newfoo): + model_query(context, models.Foo).\ + filter_by(id=id).\ + update({'foo': newfoo}) + + def create_foo(context, values): + foo_ref = models.Foo() + foo_ref.update(values) + foo_ref.save() + return foo_ref + + +* Within the scope of a single method, keeping all the reads and writes within + the context managed by a single session. In this way, the session's __exit__ + handler will take care of calling flush() and commit() for you. + If using this approach, you should not explicitly call flush() or commit(). + Any error within the context of the session will cause the session to emit + a ROLLBACK. If the connection is dropped before this is possible, the + database will implicitly rollback the transaction. + + Note: statements in the session scope will not be automatically retried. + + If you create models within the session, they need to be added, but you + do not need to call model.save() + + def create_many_foo(context, foos): + session = get_session() + with session.begin(): + for foo in foos: + foo_ref = models.Foo() + foo_ref.update(foo) + session.add(foo_ref) + + def update_bar(context, foo_id, newbar): + session = get_session() + with session.begin(): + foo_ref = model_query(context, models.Foo, session).\ + filter_by(id=foo_id).\ + first() + model_query(context, models.Bar, session).\ + filter_by(id=foo_ref['bar_id']).\ + update({'bar': newbar}) + + Note: update_bar is a trivially simple example of using "with session.begin". + Whereas create_many_foo is a good example of when a transaction is needed, + it is always best to use as few queries as possible. The two queries in + update_bar can be better expressed using a single query which avoids + the need for an explicit transaction. It can be expressed like so: + + def update_bar(context, foo_id, newbar): + subq = model_query(context, models.Foo.id).\ + filter_by(id=foo_id).\ + limit(1).\ + subquery() + model_query(context, models.Bar).\ + filter_by(id=subq.as_scalar()).\ + update({'bar': newbar}) + + For reference, this emits approximagely the following SQL statement: + + UPDATE bar SET bar = ${newbar} + WHERE id=(SELECT bar_id FROM foo WHERE id = ${foo_id} LIMIT 1); + +* Passing an active session between methods. Sessions should only be passed + to private methods. The private method must use a subtransaction; otherwise + SQLAlchemy will throw an error when you call session.begin() on an existing + transaction. Public methods should not accept a session parameter and should + not be involved in sessions within the caller's scope. + + Note that this incurs more overhead in SQLAlchemy than the above means + due to nesting transactions, and it is not possible to implicitly retry + failed database operations when using this approach. + + This also makes code somewhat more difficult to read and debug, because a + single database transaction spans more than one method. Error handling + becomes less clear in this situation. When this is needed for code clarity, + it should be clearly documented. + + def myfunc(foo): + session = get_session() + with session.begin(): + # do some database things + bar = _private_func(foo, session) + return bar + + def _private_func(foo, session=None): + if not session: + session = get_session() + with session.begin(subtransaction=True): + # do some other database things + return bar + + +There are some things which it is best to avoid: + +* Don't keep a transaction open any longer than necessary. + + This means that your "with session.begin()" block should be as short + as possible, while still containing all the related calls for that + transaction. + +* Avoid "with_lockmode('UPDATE')" when possible. + + In MySQL/InnoDB, when a "SELECT ... FOR UPDATE" query does not match + any rows, it will take a gap-lock. This is a form of write-lock on the + "gap" where no rows exist, and prevents any other writes to that space. + This can effectively prevent any INSERT into a table by locking the gap + at the end of the index. Similar problems will occur if the SELECT FOR UPDATE + has an overly broad WHERE clause, or doesn't properly use an index. + + One idea proposed at ODS Fall '12 was to use a normal SELECT to test the + number of rows matching a query, and if only one row is returned, + then issue the SELECT FOR UPDATE. + + The better long-term solution is to use INSERT .. ON DUPLICATE KEY UPDATE. + However, this can not be done until the "deleted" columns are removed and + proper UNIQUE constraints are added to the tables. + + +Enabling soft deletes: + +* To use/enable soft-deletes, the SoftDeleteMixin must be added + to your model class. For example: + + class NovaBase(models.SoftDeleteMixin, models.ModelBase): + pass + + +Efficient use of soft deletes: + +* There are two possible ways to mark a record as deleted: + model.soft_delete() and query.soft_delete(). + + model.soft_delete() method works with single already fetched entry. + query.soft_delete() makes only one db request for all entries that correspond + to query. + +* In almost all cases you should use query.soft_delete(). Some examples: + + def soft_delete_bar(): + count = model_query(BarModel).find(some_condition).soft_delete() + if count == 0: + raise Exception("0 entries were soft deleted") + + def complex_soft_delete_with_synchronization_bar(session=None): + if session is None: + session = get_session() + with session.begin(subtransactions=True): + count = model_query(BarModel).\ + find(some_condition).\ + soft_delete(synchronize_session=True) + # Here synchronize_session is required, because we + # don't know what is going on in outer session. + if count == 0: + raise Exception("0 entries were soft deleted") + +* There is only one situation where model.soft_delete() is appropriate: when + you fetch a single record, work with it, and mark it as deleted in the same + transaction. + + def soft_delete_bar_model(): + session = get_session() + with session.begin(): + bar_ref = model_query(BarModel).find(some_condition).first() + # Work with bar_ref + bar_ref.soft_delete(session=session) + + However, if you need to work with all entries that correspond to query and + then soft delete them you should use query.soft_delete() method: + + def soft_delete_multi_models(): + session = get_session() + with session.begin(): + query = model_query(BarModel, session=session).\ + find(some_condition) + model_refs = query.all() + # Work with model_refs + query.soft_delete(synchronize_session=False) + # synchronize_session=False should be set if there is no outer + # session and these entries are not used after this. + + When working with many rows, it is very important to use query.soft_delete, + which issues a single query. Using model.soft_delete(), as in the following + example, is very inefficient. + + for bar_ref in bar_refs: + bar_ref.soft_delete(session=session) + # This will produce count(bar_refs) db requests. + +""" + +import os.path +import re +import time + +from eventlet import greenthread +from oslo_config import cfg +import six +from sqlalchemy import exc as sqla_exc +import sqlalchemy.interfaces +from sqlalchemy.interfaces import PoolListener +import sqlalchemy.orm +from sqlalchemy.pool import NullPool, StaticPool +from sqlalchemy.sql.expression import literal_column + +from sm_api.openstack.common.db import exception +from sm_api.openstack.common import log as logging +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import timeutils + +DEFAULT = 'DEFAULT' + +sqlite_db_opts = [ + cfg.StrOpt('sqlite_db', + default='sm.db', + help='the filename to use with sqlite'), + cfg.BoolOpt('sqlite_synchronous', + default=True, + help='If true, use synchronous mode for sqlite'), +] + +database_opts = [ + cfg.StrOpt('connection', + default='sqlite:////var/run/sm/sm.db', + help='The SQLAlchemy connection string used to connect to the ' + 'database', + deprecated_name='sql_connection', + deprecated_group=DEFAULT, + secret=True), + cfg.IntOpt('idle_timeout', + default=3600, + deprecated_name='sql_idle_timeout', + deprecated_group=DEFAULT, + help='timeout before idle sql connections are reaped'), + cfg.IntOpt('min_pool_size', + default=1, + deprecated_name='sql_min_pool_size', + deprecated_group=DEFAULT, + help='Minimum number of SQL connections to keep open in a ' + 'pool'), + cfg.IntOpt('max_pool_size', + default=5, + deprecated_name='sql_max_pool_size', + deprecated_group=DEFAULT, + help='Maximum number of SQL connections to keep open in a ' + 'pool'), + cfg.IntOpt('max_retries', + default=10, + deprecated_name='sql_max_retries', + deprecated_group=DEFAULT, + help='maximum db connection retries during startup. ' + '(setting -1 implies an infinite retry count)'), + cfg.IntOpt('retry_interval', + default=10, + deprecated_name='sql_retry_interval', + deprecated_group=DEFAULT, + help='interval between retries of opening a sql connection'), + cfg.IntOpt('max_overflow', + default=None, + deprecated_name='sql_max_overflow', + deprecated_group=DEFAULT, + help='If set, use this value for max_overflow with sqlalchemy'), + cfg.IntOpt('connection_debug', + default=0, + deprecated_name='sql_connection_debug', + deprecated_group=DEFAULT, + help='Verbosity of SQL debugging information. 0=None, ' + '100=Everything'), + cfg.BoolOpt('connection_trace', + default=False, + deprecated_name='sql_connection_trace', + deprecated_group=DEFAULT, + help='Add python stack traces to SQL as comment strings'), +] + +CONF = cfg.CONF +CONF.register_opts(sqlite_db_opts) +CONF.register_opts(database_opts, 'database') +LOG = logging.getLogger(__name__) + +_ENGINE = None +_MAKER = None + + +def set_defaults(sql_connection, sqlite_db): + """Set defaults for configuration variables.""" + cfg.set_defaults(database_opts, + connection=sql_connection) + cfg.set_defaults(sqlite_db_opts, + sqlite_db=sqlite_db) + + +def cleanup(): + global _ENGINE, _MAKER + + if _MAKER: + _MAKER.close_all() + _MAKER = None + if _ENGINE: + _ENGINE.dispose() + _ENGINE = None + + +class SqliteForeignKeysListener(PoolListener): + """ + Ensures that the foreign key constraints are enforced in SQLite. + + The foreign key constraints are disabled by default in SQLite, + so the foreign key constraints will be enabled here for every + database connection + """ + def connect(self, dbapi_con, con_record): + dbapi_con.execute('pragma foreign_keys=ON') + + +def get_session(autocommit=True, expire_on_commit=False, + sqlite_fk=False): + """Return a SQLAlchemy session.""" + global _MAKER + + if _MAKER is None: + engine = get_engine(sqlite_fk=sqlite_fk) + _MAKER = get_maker(engine, autocommit, expire_on_commit) + + session = _MAKER() + return session + + +# note(boris-42): In current versions of DB backends unique constraint +# violation messages follow the structure: +# +# sqlite: +# 1 column - (IntegrityError) column c1 is not unique +# N columns - (IntegrityError) column c1, c2, ..., N are not unique +# +# postgres: +# 1 column - (IntegrityError) duplicate key value violates unique +# constraint "users_c1_key" +# N columns - (IntegrityError) duplicate key value violates unique +# constraint "name_of_our_constraint" +# +# mysql: +# 1 column - (IntegrityError) (1062, "Duplicate entry 'value_of_c1' for key +# 'c1'") +# N columns - (IntegrityError) (1062, "Duplicate entry 'values joined +# with -' for key 'name_of_our_constraint'") +_DUP_KEY_RE_DB = { + "sqlite": re.compile(r"^.*columns?([^)]+)(is|are)\s+not\s+unique$"), + "postgresql": re.compile(r"^.*duplicate\s+key.*\"([^\"]+)\"\s*\n.*$"), + "mysql": re.compile(r"^.*\(1062,.*'([^\']+)'\"\)$") +} + + +def _raise_if_duplicate_entry_error(integrity_error, engine_name): + """ + In this function will be raised DBDuplicateEntry exception if integrity + error wrap unique constraint violation. + """ + + def get_columns_from_uniq_cons_or_name(columns): + # note(boris-42): UniqueConstraint name convention: "uniq_c1_x_c2_x_c3" + # means that columns c1, c2, c3 are in UniqueConstraint. + uniqbase = "uniq_" + if not columns.startswith(uniqbase): + if engine_name == "postgresql": + return [columns[columns.index("_") + 1:columns.rindex("_")]] + return [columns] + return columns[len(uniqbase):].split("_x_") + + if engine_name not in ["mysql", "sqlite", "postgresql"]: + return + + m = _DUP_KEY_RE_DB[engine_name].match(integrity_error.message) + if not m: + return + columns = m.group(1) + + if engine_name == "sqlite": + columns = columns.strip().split(", ") + else: + columns = get_columns_from_uniq_cons_or_name(columns) + raise exception.DBDuplicateEntry(columns, integrity_error) + + +# NOTE(comstud): In current versions of DB backends, Deadlock violation +# messages follow the structure: +# +# mysql: +# (OperationalError) (1213, 'Deadlock found when trying to get lock; try ' +# 'restarting transaction') +_DEADLOCK_RE_DB = { + "mysql": re.compile(r"^.*\(1213, 'Deadlock.*") +} + + +def _raise_if_deadlock_error(operational_error, engine_name): + """ + Raise DBDeadlock exception if OperationalError contains a Deadlock + condition. + """ + re = _DEADLOCK_RE_DB.get(engine_name) + if re is None: + return + m = re.match(operational_error.message) + if not m: + return + raise exception.DBDeadlock(operational_error) + + +def _wrap_db_error(f): + def _wrap(*args, **kwargs): + try: + return f(*args, **kwargs) + except UnicodeEncodeError: + raise exception.DBInvalidUnicodeParameter() + # note(boris-42): We should catch unique constraint violation and + # wrap it by our own DBDuplicateEntry exception. Unique constraint + # violation is wrapped by IntegrityError. + except sqla_exc.OperationalError as e: + _raise_if_deadlock_error(e, get_engine().name) + # NOTE(comstud): A lot of code is checking for OperationalError + # so let's not wrap it for now. + raise + except sqla_exc.IntegrityError as e: + # note(boris-42): SqlAlchemy doesn't unify errors from different + # DBs so we must do this. Also in some tables (for example + # instance_types) there are more than one unique constraint. This + # means we should get names of columns, which values violate + # unique constraint, from error message. + _raise_if_duplicate_entry_error(e, get_engine().name) + raise exception.DBError(e) + except Exception as e: + LOG.exception(_('DB exception wrapped.')) + raise exception.DBError(e) + _wrap.func_name = f.func_name + return _wrap + + +def get_engine(sqlite_fk=False): + """Return a SQLAlchemy engine.""" + global _ENGINE + if _ENGINE is None: + _ENGINE = create_engine(CONF.database.connection, + sqlite_fk=sqlite_fk) + return _ENGINE + + +def _synchronous_switch_listener(dbapi_conn, connection_rec): + """Switch sqlite connections to non-synchronous mode.""" + dbapi_conn.execute("PRAGMA synchronous = OFF") + + +def _add_regexp_listener(dbapi_con, con_record): + """Add REGEXP function to sqlite connections.""" + + def regexp(expr, item): + reg = re.compile(expr) + return reg.search(six.text_type(item)) is not None + dbapi_con.create_function('regexp', 2, regexp) + + +def _greenthread_yield(dbapi_con, con_record): + """ + Ensure other greenthreads get a chance to execute by forcing a context + switch. With common database backends (eg MySQLdb and sqlite), there is + no implicit yield caused by network I/O since they are implemented by + C libraries that eventlet cannot monkey patch. + """ + greenthread.sleep(0) + + +def _ping_listener(dbapi_conn, connection_rec, connection_proxy): + """ + Ensures that MySQL connections checked out of the + pool are alive. + + Borrowed from: + http://groups.google.com/group/sqlalchemy/msg/a4ce563d802c929f + """ + try: + dbapi_conn.cursor().execute('select 1') + except dbapi_conn.OperationalError as ex: + if ex.args[0] in (2006, 2013, 2014, 2045, 2055): + LOG.warn(_('Got mysql server has gone away: %s'), ex) + raise sqla_exc.DisconnectionError("Database server went away") + else: + raise + + +def _is_db_connection_error(args): + """Return True if error in connecting to db.""" + # NOTE(adam_g): This is currently MySQL specific and needs to be extended + # to support Postgres and others. + conn_err_codes = ('2002', '2003', '2006') + for err_code in conn_err_codes: + if args.find(err_code) != -1: + return True + return False + + +def create_engine(sql_connection, sqlite_fk=False): + """Return a new SQLAlchemy engine.""" + connection_dict = sqlalchemy.engine.url.make_url(sql_connection) + + engine_args = { + "pool_recycle": CONF.database.idle_timeout, + "echo": False, + 'convert_unicode': True, + } + + # Map our SQL debug level to SQLAlchemy's options + if CONF.database.connection_debug >= 100: + engine_args['echo'] = 'debug' + elif CONF.database.connection_debug >= 50: + engine_args['echo'] = True + + if "sqlite" in connection_dict.drivername: + if sqlite_fk: + engine_args["listeners"] = [SqliteForeignKeysListener()] + engine_args["poolclass"] = NullPool + + if CONF.database.connection == "sqlite://": + engine_args["poolclass"] = StaticPool + engine_args["connect_args"] = {'check_same_thread': False} + else: + engine_args['pool_size'] = CONF.database.max_pool_size + if CONF.database.max_overflow is not None: + engine_args['max_overflow'] = CONF.database.max_overflow + + engine = sqlalchemy.create_engine(sql_connection, **engine_args) + + sqlalchemy.event.listen(engine, 'checkin', _greenthread_yield) + + if 'mysql' in connection_dict.drivername: + sqlalchemy.event.listen(engine, 'checkout', _ping_listener) + elif 'sqlite' in connection_dict.drivername: + if not CONF.sqlite_synchronous: + sqlalchemy.event.listen(engine, 'connect', + _synchronous_switch_listener) + sqlalchemy.event.listen(engine, 'connect', _add_regexp_listener) + + if (CONF.database.connection_trace and + engine.dialect.dbapi.__name__ == 'MySQLdb'): + _patch_mysqldb_with_stacktrace_comments() + + try: + engine.connect() + except sqla_exc.OperationalError as e: + if not _is_db_connection_error(e.args[0]): + raise + + remaining = CONF.database.max_retries + if remaining == -1: + remaining = 'infinite' + while True: + msg = _('SQL connection failed. %s attempts left.') + LOG.warn(msg % remaining) + if remaining != 'infinite': + remaining -= 1 + time.sleep(CONF.database.retry_interval) + try: + engine.connect() + break + except sqla_exc.OperationalError as e: + if (remaining != 'infinite' and remaining == 0) or \ + not _is_db_connection_error(e.args[0]): + raise + return engine + + +class Query(sqlalchemy.orm.query.Query): + """Subclass of sqlalchemy.query with soft_delete() method.""" + def soft_delete(self, synchronize_session='evaluate'): + return self.update({'deleted': literal_column('id'), + 'updated_at': literal_column('updated_at'), + 'deleted_at': timeutils.utcnow()}, + synchronize_session=synchronize_session) + + +class Session(sqlalchemy.orm.session.Session): + """Custom Session class to avoid SqlAlchemy Session monkey patching.""" + @_wrap_db_error + def query(self, *args, **kwargs): + return super(Session, self).query(*args, **kwargs) + + @_wrap_db_error + def flush(self, *args, **kwargs): + return super(Session, self).flush(*args, **kwargs) + + @_wrap_db_error + def execute(self, *args, **kwargs): + return super(Session, self).execute(*args, **kwargs) + + +def get_maker(engine, autocommit=True, expire_on_commit=False): + """Return a SQLAlchemy sessionmaker using the given engine.""" + return sqlalchemy.orm.sessionmaker(bind=engine, + class_=Session, + autocommit=autocommit, + expire_on_commit=expire_on_commit, + query_cls=Query) + + +def _patch_mysqldb_with_stacktrace_comments(): + """Adds current stack trace as a comment in queries by patching + MySQLdb.cursors.BaseCursor._do_query. + """ + import MySQLdb.cursors + import traceback + + old_mysql_do_query = MySQLdb.cursors.BaseCursor._do_query + + def _do_query(self, q): + stack = '' + for file, line, method, function in traceback.extract_stack(): + # exclude various common things from trace + if file.endswith('session.py') and method == '_do_query': + continue + if file.endswith('api.py') and method == 'wrapper': + continue + if file.endswith('utils.py') and method == '_inner': + continue + if file.endswith('exception.py') and method == '_wrap': + continue + # db/api is just a wrapper around db/sqlalchemy/api + if file.endswith('db/api.py'): + continue + # only trace inside sm_api + index = file.rfind('sm_api') + if index == -1: + continue + stack += "File:%s:%s Method:%s() Line:%s | " \ + % (file[index:], line, method, function) + + # strip trailing " | " from stack + if stack: + stack = stack[:-3] + qq = "%s /* %s */" % (q, stack) + else: + qq = q + old_mysql_do_query(self, qq) + + setattr(MySQLdb.cursors.BaseCursor, '_do_query', _do_query) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/utils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/utils.py new file mode 100644 index 00000000..822932ee --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/db/sqlalchemy/utils.py @@ -0,0 +1,150 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2010-2011 OpenStack Foundation. +# Copyright 2012 Justin Santa Barbara +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Implementation of paginate query.""" + +import sqlalchemy + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging + + +LOG = logging.getLogger(__name__) + + +class InvalidSortKey(Exception): + message = _("Sort key supplied was not valid.") + + +# copy from glance/db/sqlalchemy/api.py +def paginate_query(query, model, limit, sort_keys, marker=None, + sort_dir=None, sort_dirs=None): + """Returns a query with sorting / pagination criteria added. + + Pagination works by requiring a unique sort_key, specified by sort_keys. + (If sort_keys is not unique, then we risk looping through values.) + We use the last row in the previous page as the 'marker' for pagination. + So we must return values that follow the passed marker in the order. + With a single-valued sort_key, this would be easy: sort_key > X. + With a compound-values sort_key, (k1, k2, k3) we must do this to repeat + the lexicographical ordering: + (k1 > X1) or (k1 == X1 && k2 > X2) or (k1 == X1 && k2 == X2 && k3 > X3) + + We also have to cope with different sort_directions. + + Typically, the id of the last row is used as the client-facing pagination + marker, then the actual marker object must be fetched from the db and + passed in to us as marker. + + :param query: the query object to which we should add paging/sorting + :param model: the ORM model class + :param limit: maximum number of items to return + :param sort_keys: array of attributes by which results should be sorted + :param marker: the last item of the previous page; we returns the next + results after this value. + :param sort_dir: direction in which results should be sorted (asc, desc) + :param sort_dirs: per-column array of sort_dirs, corresponding to sort_keys + + :rtype: sqlalchemy.orm.query.Query + :return: The query with sorting/pagination added. + """ + + if 'id' not in sort_keys: + # TODO(justinsb): If this ever gives a false-positive, check + # the actual primary key, rather than assuming its id + LOG.warn(_('id not in sort_keys; is sort_keys unique?')) + + assert(not (sort_dir and sort_dirs)) + + # Default the sort direction to ascending + if sort_dirs is None and sort_dir is None: + sort_dir = 'asc' + + # Ensure a per-column sort direction + if sort_dirs is None: + sort_dirs = [sort_dir for _sort_key in sort_keys] + + assert(len(sort_dirs) == len(sort_keys)) + + # Add sorting + for current_sort_key, current_sort_dir in zip(sort_keys, sort_dirs): + sort_dir_func = { + 'asc': sqlalchemy.asc, + 'desc': sqlalchemy.desc, + }[current_sort_dir] + + if (current_sort_key == 'id') and ('name' in sort_keys): + continue # dont double sort if name + + try: + sort_key_attr = getattr(model, current_sort_key) + except AttributeError: + raise InvalidSortKey() + query = query.order_by(sort_dir_func(sort_key_attr)) + + # Add pagination + if marker is not None: + marker_values = [] + for sort_key in sort_keys: + v = getattr(marker, sort_key) + marker_values.append(v) + + # Build up an array of sort criteria as in the docstring + criteria_list = [] + for i in range(0, len(sort_keys)): + crit_attrs = [] + for j in range(0, i): + model_attr = getattr(model, sort_keys[j]) + crit_attrs.append((model_attr == marker_values[j])) + + model_attr = getattr(model, sort_keys[i]) + if sort_dirs[i] == 'desc': + crit_attrs.append((model_attr < marker_values[i])) + elif sort_dirs[i] == 'asc': + crit_attrs.append((model_attr > marker_values[i])) + else: + raise ValueError(_("Unknown sort direction, " + "must be 'desc' or 'asc'")) + + criteria = sqlalchemy.sql.and_(*crit_attrs) + criteria_list.append(criteria) + + f = sqlalchemy.sql.or_(*criteria_list) + query = query.filter(f) + + if limit is not None: + query = query.limit(limit) + + return query + + +def get_table(engine, name): + """Returns an sqlalchemy table dynamically from db. + + Needed because the models don't work for us in migrations + as models will be far out of sync with the current data. + """ + metadata = sqlalchemy.MetaData() + metadata.bind = engine + return sqlalchemy.Table(name, metadata, autoload=True) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/eventlet_backdoor.py b/service-mgmt-api/sm-api/sm_api/openstack/common/eventlet_backdoor.py new file mode 100644 index 00000000..4d213590 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/eventlet_backdoor.py @@ -0,0 +1,93 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2012 OpenStack Foundation. +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from __future__ import print_function + +import gc +import pprint +import sys +import traceback + +import eventlet +import eventlet.backdoor +import greenlet +from oslo_config import cfg + +eventlet_backdoor_opts = [ + cfg.IntOpt('backdoor_port', + default=None, + help='port for eventlet backdoor to listen') +] + +CONF = cfg.CONF +CONF.register_opts(eventlet_backdoor_opts) + + +def _dont_use_this(): + print("Don't use this, just disconnect instead") + + +def _find_objects(t): + return filter(lambda o: isinstance(o, t), gc.get_objects()) + + +def _print_greenthreads(): + for i, gt in enumerate(_find_objects(greenlet.greenlet)): + print(i, gt) + traceback.print_stack(gt.gr_frame) + print() + + +def _print_nativethreads(): + for threadId, stack in sys._current_frames().items(): + print(threadId) + traceback.print_stack(stack) + print() + + +def initialize_if_enabled(): + backdoor_locals = { + 'exit': _dont_use_this, # So we don't exit the entire process + 'quit': _dont_use_this, # So we don't exit the entire process + 'fo': _find_objects, + 'pgt': _print_greenthreads, + 'pnt': _print_nativethreads, + } + + if CONF.backdoor_port is None: + return None + + # NOTE(johannes): The standard sys.displayhook will print the value of + # the last expression and set it to __builtin__._, which overwrites + # the __builtin__._ that gettext sets. Let's switch to using pprint + # since it won't interact poorly with gettext, and it's easier to + # read the output too. + def displayhook(val): + if val is not None: + pprint.pprint(val) + sys.displayhook = displayhook + + sock = eventlet.listen(('localhost', CONF.backdoor_port)) + port = sock.getsockname()[1] + eventlet.spawn_n(eventlet.backdoor.backdoor_server, sock, + locals=backdoor_locals) + return port diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/excutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/excutils.py new file mode 100644 index 00000000..4af93f35 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/excutils.py @@ -0,0 +1,55 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# Copyright 2012, Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Exception related utilities. +""" + +import contextlib +import logging +import sys +import traceback + +from sm_api.openstack.common.gettextutils import _ + + +@contextlib.contextmanager +def save_and_reraise_exception(): + """Save current exception, run some code and then re-raise. + + In some cases the exception context can be cleared, resulting in None + being attempted to be re-raised after an exception handler is run. This + can happen when eventlet switches greenthreads or when running an + exception handler, code raises and catches an exception. In both + cases the exception context will be cleared. + + To work around this, we save the exception state, run handler code, and + then re-raise the original exception. If another exception occurs, the + saved exception is logged and the new exception is re-raised. + """ + type_, value, tb = sys.exc_info() + try: + yield + except Exception: + logging.error(_('Original exception being dropped: %s'), + traceback.format_exception(type_, value, tb)) + raise + raise type_, value, tb diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/fileutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/fileutils.py new file mode 100644 index 00000000..19a8a9fb --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/fileutils.py @@ -0,0 +1,114 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + + +import contextlib +import errno +import os + +from sm_api.openstack.common import excutils +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging + +LOG = logging.getLogger(__name__) + +_FILE_CACHE = {} + + +def ensure_tree(path): + """Create a directory (and any ancestor directories required) + + :param path: Directory to create + """ + try: + os.makedirs(path) + except OSError as exc: + if exc.errno == errno.EEXIST: + if not os.path.isdir(path): + raise + else: + raise + + +def read_cached_file(filename, force_reload=False): + """Read from a file if it has been modified. + + :param force_reload: Whether to reload the file. + :returns: A tuple with a boolean specifying if the data is fresh + or not. + """ + global _FILE_CACHE + + if force_reload and filename in _FILE_CACHE: + del _FILE_CACHE[filename] + + reloaded = False + mtime = os.path.getmtime(filename) + cache_info = _FILE_CACHE.setdefault(filename, {}) + + if not cache_info or mtime > cache_info.get('mtime', 0): + LOG.debug(_("Reloading cached file %s") % filename) + with open(filename) as fap: + cache_info['data'] = fap.read() + cache_info['mtime'] = mtime + reloaded = True + return (reloaded, cache_info['data']) + + +def delete_if_exists(path): + """Delete a file, but ignore file not found error. + + :param path: File to delete + """ + + try: + os.unlink(path) + except OSError as e: + if e.errno == errno.ENOENT: + return + else: + raise + + +@contextlib.contextmanager +def remove_path_on_error(path): + """Protect code that wants to operate on PATH atomically. + Any exception will cause PATH to be removed. + + :param path: File to work with + """ + try: + yield + except Exception: + with excutils.save_and_reraise_exception(): + delete_if_exists(path) + + +def file_open(*args, **kwargs): + """Open file + + see built-in file() documentation for more details + + Note: The reason this is kept in a separate module is to easily + be able to provide a stub module that doesn't alter system + state at all (for unit tests) + """ + return file(*args, **kwargs) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/fixture/__init__.py b/service-mgmt-api/sm-api/sm_api/openstack/common/fixture/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/fixture/mockpatch.py b/service-mgmt-api/sm-api/sm_api/openstack/common/fixture/mockpatch.py new file mode 100644 index 00000000..ac5f1b62 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/fixture/mockpatch.py @@ -0,0 +1,55 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import fixtures +import mock + + +class PatchObject(fixtures.Fixture): + """Deal with code around mock.""" + + def __init__(self, obj, attr, **kwargs): + self.obj = obj + self.attr = attr + self.kwargs = kwargs + + def setUp(self): + super(PatchObject, self).setUp() + _p = mock.patch.object(self.obj, self.attr, **self.kwargs) + self.mock = _p.start() + self.addCleanup(_p.stop) + + +class Patch(fixtures.Fixture): + + """Deal with code around mock.patch.""" + + def __init__(self, obj, **kwargs): + self.obj = obj + self.kwargs = kwargs + + def setUp(self): + super(Patch, self).setUp() + _p = mock.patch(self.obj, **self.kwargs) + self.mock = _p.start() + self.addCleanup(_p.stop) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/fixture/moxstubout.py b/service-mgmt-api/sm-api/sm_api/openstack/common/fixture/moxstubout.py new file mode 100644 index 00000000..6f92497a --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/fixture/moxstubout.py @@ -0,0 +1,41 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import fixtures +import mox +import stubout + + +class MoxStubout(fixtures.Fixture): + """Deal with code around mox and stubout as a fixture.""" + + def setUp(self): + super(MoxStubout, self).setUp() + # emulate some of the mox stuff, we can't use the metaclass + # because it screws with our generators + self.mox = mox.Mox() + self.stubs = stubout.StubOutForTesting() + self.addCleanup(self.mox.UnsetStubs) + self.addCleanup(self.stubs.UnsetAll) + self.addCleanup(self.stubs.SmartUnsetAll) + self.addCleanup(self.mox.VerifyAll) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/gettextutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/gettextutils.py new file mode 100644 index 00000000..d4da5070 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/gettextutils.py @@ -0,0 +1,54 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +gettext for openstack-common modules. + +Usual usage in an openstack.common module: + + from sm_api.openstack.common.gettextutils import _ +""" + +import gettext +import os + +_localedir = os.environ.get('sm_api'.upper() + '_LOCALEDIR') +_t = gettext.translation('sm_api', localedir=_localedir, fallback=True) + + +def _(msg): + return _t.ugettext(msg) + + +def install(domain): + """Install a _() function using the given translation domain. + + Given a translation domain, install a _() function using gettext's + install() function. + + The main difference from gettext.install() is that we allow + overriding the default localedir (e.g. /usr/share/locale) using + a translation-domain-specific environment variable (e.g. + NOVA_LOCALEDIR). + """ + gettext.install(domain, + localedir=os.environ.get(domain.upper() + '_LOCALEDIR'), + unicode=True) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/importutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/importutils.py new file mode 100644 index 00000000..9ee48932 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/importutils.py @@ -0,0 +1,71 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Import related utilities and helper functions. +""" + +import sys +import traceback + + +def import_class(import_str): + """Returns a class from a string including module and class""" + mod_str, _sep, class_str = import_str.rpartition('.') + try: + __import__(mod_str) + return getattr(sys.modules[mod_str], class_str) + except (ValueError, AttributeError): + raise ImportError('Class %s cannot be found (%s)' % + (class_str, + traceback.format_exception(*sys.exc_info()))) + + +def import_object(import_str, *args, **kwargs): + """Import a class and return an instance of it.""" + return import_class(import_str)(*args, **kwargs) + + +def import_object_ns(name_space, import_str, *args, **kwargs): + """ + Import a class and return an instance of it, first by trying + to find the class in a default namespace, then failing back to + a full path if not found in the default namespace. + """ + import_value = "%s.%s" % (name_space, import_str) + try: + return import_class(import_value)(*args, **kwargs) + except ImportError: + return import_class(import_str)(*args, **kwargs) + + +def import_module(import_str): + """Import a module.""" + __import__(import_str) + return sys.modules[import_str] + + +def try_import(import_str, default=None): + """Try to import a module and if it fails return default.""" + try: + return import_module(import_str) + except ImportError: + return default diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/jsonutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/jsonutils.py new file mode 100644 index 00000000..f7388a51 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/jsonutils.py @@ -0,0 +1,173 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Justin Santa Barbara +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +''' +JSON related utilities. + +This module provides a few things: + + 1) A handy function for getting an object down to something that can be + JSON serialized. See to_primitive(). + + 2) Wrappers around loads() and dumps(). The dumps() wrapper will + automatically use to_primitive() for you if needed. + + 3) This sets up anyjson to use the loads() and dumps() wrappers if anyjson + is available. +''' + + +import datetime +import functools +import inspect +import itertools +import json +import types +import xmlrpclib + +import six + +from sm_api.openstack.common import timeutils + + +_nasty_type_tests = [inspect.ismodule, inspect.isclass, inspect.ismethod, + inspect.isfunction, inspect.isgeneratorfunction, + inspect.isgenerator, inspect.istraceback, inspect.isframe, + inspect.iscode, inspect.isbuiltin, inspect.isroutine, + inspect.isabstract] + +_simple_types = (types.NoneType, int, basestring, bool, float, long) + + +def to_primitive(value, convert_instances=False, convert_datetime=True, + level=0, max_depth=3): + """Convert a complex object into primitives. + + Handy for JSON serialization. We can optionally handle instances, + but since this is a recursive function, we could have cyclical + data structures. + + To handle cyclical data structures we could track the actual objects + visited in a set, but not all objects are hashable. Instead we just + track the depth of the object inspections and don't go too deep. + + Therefore, convert_instances=True is lossy ... be aware. + + """ + # handle obvious types first - order of basic types determined by running + # full tests on nova project, resulting in the following counts: + # 572754 + # 460353 + # 379632 + # 274610 + # 199918 + # 114200 + # 51817 + # 26164 + # 6491 + # 283 + # 19 + if isinstance(value, _simple_types): + return value + + if isinstance(value, datetime.datetime): + if convert_datetime: + return timeutils.strtime(value) + else: + return value + + # value of itertools.count doesn't get caught by nasty_type_tests + # and results in infinite loop when list(value) is called. + if type(value) == itertools.count: + return six.text_type(value) + + # FIXME(vish): Workaround for LP bug 852095. Without this workaround, + # tests that raise an exception in a mocked method that + # has a @wrap_exception with a notifier will fail. If + # we up the dependency to 0.5.4 (when it is released) we + # can remove this workaround. + if getattr(value, '__module__', None) == 'mox': + return 'mock' + + if level > max_depth: + return '?' + + # The try block may not be necessary after the class check above, + # but just in case ... + try: + recursive = functools.partial(to_primitive, + convert_instances=convert_instances, + convert_datetime=convert_datetime, + level=level, + max_depth=max_depth) + if isinstance(value, dict): + return dict((k, recursive(v)) for k, v in value.iteritems()) + elif isinstance(value, (list, tuple)): + return [recursive(lv) for lv in value] + + # It's not clear why xmlrpclib created their own DateTime type, but + # for our purposes, make it a datetime type which is explicitly + # handled + if isinstance(value, xmlrpclib.DateTime): + value = datetime.datetime(*tuple(value.timetuple())[:6]) + + if convert_datetime and isinstance(value, datetime.datetime): + return timeutils.strtime(value) + elif hasattr(value, 'iteritems'): + return recursive(dict(value.iteritems()), level=level + 1) + elif hasattr(value, '__iter__'): + return recursive(list(value)) + elif convert_instances and hasattr(value, '__dict__'): + # Likely an instance of something. Watch for cycles. + # Ignore class member vars. + return recursive(value.__dict__, level=level + 1) + else: + if any(test(value) for test in _nasty_type_tests): + return six.text_type(value) + return value + except TypeError: + # Class objects are tricky since they may define something like + # __iter__ defined but it isn't callable as list(). + return six.text_type(value) + + +def dumps(value, default=to_primitive, **kwargs): + return json.dumps(value, default=default, **kwargs) + + +def loads(s): + return json.loads(s) + + +def load(s): + return json.load(s) + + +try: + import anyjson +except ImportError: + pass +else: + anyjson._modules.append((__name__, 'dumps', TypeError, + 'loads', ValueError, 'load')) + anyjson.force_implementation(__name__) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/local.py b/service-mgmt-api/sm-api/sm_api/openstack/common/local.py new file mode 100644 index 00000000..711da100 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/local.py @@ -0,0 +1,52 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Greenthread local storage of variables using weak references""" + +import weakref + +from eventlet import corolocal + + +class WeakLocal(corolocal.local): + def __getattribute__(self, attr): + rval = corolocal.local.__getattribute__(self, attr) + if rval: + # NOTE(mikal): this bit is confusing. What is stored is a weak + # reference, not the value itself. We therefore need to lookup + # the weak reference and return the inner value here. + rval = rval() + return rval + + def __setattr__(self, attr, value): + value = weakref.ref(value) + return corolocal.local.__setattr__(self, attr, value) + + +# NOTE(mikal): the name "store" should be deprecated in the future +store = WeakLocal() + +# A "weak" store uses weak references and allows an object to fall out of scope +# when it falls out of scope in the code that uses the thread local storage. A +# "strong" store will hold a reference to the object so that it never falls out +# of scope. +weak_store = WeakLocal() +strong_store = corolocal.local diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/lockutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/lockutils.py new file mode 100644 index 00000000..98c3bfe8 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/lockutils.py @@ -0,0 +1,282 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + + +import errno +import functools +import os +import shutil +import tempfile +import time +import weakref + +from eventlet import semaphore +from oslo_config import cfg + +from sm_api.openstack.common import fileutils +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import local +from sm_api.openstack.common import log as logging + + +LOG = logging.getLogger(__name__) + + +util_opts = [ + cfg.BoolOpt('disable_process_locking', default=False, + help='Whether to disable inter-process locks'), + cfg.StrOpt('lock_path', + help=('Directory to use for lock files. Default to a ' + 'temp directory')) +] + + +CONF = cfg.CONF +CONF.register_opts(util_opts) + + +def set_defaults(lock_path): + cfg.set_defaults(util_opts, lock_path=lock_path) + + +class _InterProcessLock(object): + """Lock implementation which allows multiple locks, working around + issues like bugs.debian.org/cgi-bin/bugreport.cgi?bug=632857 and does + not require any cleanup. Since the lock is always held on a file + descriptor rather than outside of the process, the lock gets dropped + automatically if the process crashes, even if __exit__ is not executed. + + There are no guarantees regarding usage by multiple green threads in a + single process here. This lock works only between processes. Exclusive + access between local threads should be achieved using the semaphores + in the @synchronized decorator. + + Note these locks are released when the descriptor is closed, so it's not + safe to close the file descriptor while another green thread holds the + lock. Just opening and closing the lock file can break synchronisation, + so lock files must be accessed only using this abstraction. + """ + + def __init__(self, name): + self.lockfile = None + self.fname = name + + def __enter__(self): + self.lockfile = open(self.fname, 'w') + + while True: + try: + # Using non-blocking locks since green threads are not + # patched to deal with blocking locking calls. + # Also upon reading the MSDN docs for locking(), it seems + # to have a laughable 10 attempts "blocking" mechanism. + self.trylock() + return self + except IOError as e: + if e.errno in (errno.EACCES, errno.EAGAIN): + # external locks synchronise things like iptables + # updates - give it some time to prevent busy spinning + time.sleep(0.01) + else: + raise + + def __exit__(self, exc_type, exc_val, exc_tb): + try: + self.unlock() + self.lockfile.close() + except IOError: + LOG.exception(_("Could not release the acquired lock `%s`"), + self.fname) + + def trylock(self): + raise NotImplementedError() + + def unlock(self): + raise NotImplementedError() + + +class _WindowsLock(_InterProcessLock): + def trylock(self): + msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_NBLCK, 1) + + def unlock(self): + msvcrt.locking(self.lockfile.fileno(), msvcrt.LK_UNLCK, 1) + + +class _PosixLock(_InterProcessLock): + def trylock(self): + fcntl.lockf(self.lockfile, fcntl.LOCK_EX | fcntl.LOCK_NB) + + def unlock(self): + fcntl.lockf(self.lockfile, fcntl.LOCK_UN) + + +if os.name == 'nt': + import msvcrt + InterProcessLock = _WindowsLock +else: + import fcntl + InterProcessLock = _PosixLock + +_semaphores = weakref.WeakValueDictionary() + + +def synchronized(name, lock_file_prefix, external=False, lock_path=None): + """Synchronization decorator. + + Decorating a method like so:: + + @synchronized('mylock') + def foo(self, *args): + ... + + ensures that only one thread will execute the foo method at a time. + + Different methods can share the same lock:: + + @synchronized('mylock') + def foo(self, *args): + ... + + @synchronized('mylock') + def bar(self, *args): + ... + + This way only one of either foo or bar can be executing at a time. + + The lock_file_prefix argument is used to provide lock files on disk with a + meaningful prefix. The prefix should end with a hyphen ('-') if specified. + + The external keyword argument denotes whether this lock should work across + multiple processes. This means that if two different workers both run a + a method decorated with @synchronized('mylock', external=True), only one + of them will execute at a time. + + The lock_path keyword argument is used to specify a special location for + external lock files to live. If nothing is set, then CONF.lock_path is + used as a default. + """ + + def wrap(f): + @functools.wraps(f) + def inner(*args, **kwargs): + # NOTE(soren): If we ever go natively threaded, this will be racy. + # See http://stackoverflow.com/questions/5390569/dyn + # amically-allocating-and-destroying-mutexes + sem = _semaphores.get(name, semaphore.Semaphore()) + if name not in _semaphores: + # this check is not racy - we're already holding ref locally + # so GC won't remove the item and there was no IO switch + # (only valid in greenthreads) + _semaphores[name] = sem + + with sem: + LOG.debug(_('Got semaphore "%(lock)s" for method ' + '"%(method)s"...'), {'lock': name, + 'method': f.__name__}) + + # NOTE(mikal): I know this looks odd + if not hasattr(local.strong_store, 'locks_held'): + local.strong_store.locks_held = [] + local.strong_store.locks_held.append(name) + + try: + if external and not CONF.disable_process_locking: + LOG.debug(_('Attempting to grab file lock "%(lock)s" ' + 'for method "%(method)s"...'), + {'lock': name, 'method': f.__name__}) + cleanup_dir = False + + # We need a copy of lock_path because it is non-local + local_lock_path = lock_path + if not local_lock_path: + local_lock_path = CONF.lock_path + + if not local_lock_path: + cleanup_dir = True + local_lock_path = tempfile.mkdtemp() + + if not os.path.exists(local_lock_path): + fileutils.ensure_tree(local_lock_path) + + # NOTE(mikal): the lock name cannot contain directory + # separators + safe_name = name.replace(os.sep, '_') + lock_file_name = '%s%s' % (lock_file_prefix, safe_name) + lock_file_path = os.path.join(local_lock_path, + lock_file_name) + + try: + lock = InterProcessLock(lock_file_path) + with lock: + LOG.debug(_('Got file lock "%(lock)s" at ' + '%(path)s for method ' + '"%(method)s"...'), + {'lock': name, + 'path': lock_file_path, + 'method': f.__name__}) + retval = f(*args, **kwargs) + finally: + LOG.debug(_('Released file lock "%(lock)s" at ' + '%(path)s for method "%(method)s"...'), + {'lock': name, + 'path': lock_file_path, + 'method': f.__name__}) + # NOTE(vish): This removes the tempdir if we needed + # to create one. This is used to + # cleanup the locks left behind by unit + # tests. + if cleanup_dir: + shutil.rmtree(local_lock_path) + else: + retval = f(*args, **kwargs) + + finally: + local.strong_store.locks_held.remove(name) + + return retval + return inner + return wrap + + +def synchronized_with_prefix(lock_file_prefix): + """Partial object generator for the synchronization decorator. + + Redefine @synchronized in each project like so:: + + (in nova/utils.py) + from nova.openstack.common import lockutils + + synchronized = lockutils.synchronized_with_prefix('nova-') + + + (in nova/foo.py) + from nova import utils + + @utils.synchronized('mylock') + def bar(self, *args): + ... + + The lock_file_prefix argument is used to provide lock files on disk with a + meaningful prefix. The prefix should end with a hyphen ('-') if specified. + """ + + return functools.partial(synchronized, lock_file_prefix=lock_file_prefix) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/log.py b/service-mgmt-api/sm-api/sm_api/openstack/common/log.py new file mode 100644 index 00000000..9293af47 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/log.py @@ -0,0 +1,562 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Openstack logging handler. + +This module adds to logging functionality by adding the option to specify +a context object when calling the various log methods. If the context object +is not specified, default formatting is used. Additionally, an instance uuid +may be passed as part of the log message, which is intended to make it easier +for admins to find messages related to a specific instance. + +It also allows setting of formatting information through conf. + +""" + +import ConfigParser +import cStringIO +import inspect +import itertools +import logging +import logging.config +import logging.handlers +import os +import sys +import traceback + +from oslo_config import cfg + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import importutils +from sm_api.openstack.common import jsonutils +from sm_api.openstack.common import local + + +_DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S" + +common_cli_opts = [ + cfg.BoolOpt('debug', + short='d', + default=False, + help='Print debugging output (set logging level to ' + 'DEBUG instead of default WARNING level).'), + cfg.BoolOpt('verbose', + short='v', + default=False, + help='Print more verbose output (set logging level to ' + 'INFO instead of default WARNING level).'), +] + +logging_cli_opts = [ + cfg.StrOpt('log-config', + metavar='PATH', + help='If this option is specified, the logging configuration ' + 'file specified is used and overrides any other logging ' + 'options specified. Please see the Python logging module ' + 'documentation for details on logging configuration ' + 'files.'), + cfg.StrOpt('log-format', + default=None, + metavar='FORMAT', + help='A logging.Formatter log message format string which may ' + 'use any of the available logging.LogRecord attributes. ' + 'This option is deprecated. Please use ' + 'logging_context_format_string and ' + 'logging_default_format_string instead.'), + cfg.StrOpt('log-date-format', + default=_DEFAULT_LOG_DATE_FORMAT, + metavar='DATE_FORMAT', + help='Format string for %%(asctime)s in log records. ' + 'Default: %(default)s'), + cfg.StrOpt('log-file', + metavar='PATH', + deprecated_name='logfile', + help='(Optional) Name of log file to output to. ' + 'If no default is set, logging will go to stdout.'), + cfg.StrOpt('log-dir', + deprecated_name='logdir', + help='(Optional) The base directory used for relative ' + '--log-file paths'), + cfg.BoolOpt('use-syslog', + default=False, + help='Use syslog for logging.'), + cfg.StrOpt('syslog-log-facility', + default='LOG_USER', + help='syslog facility to receive log lines') +] + +generic_log_opts = [ + cfg.BoolOpt('use_stderr', + default=True, + help='Log output to standard error') +] + +log_opts = [ + cfg.StrOpt('logging_context_format_string', + default='sm-api %(process)d ' + '%(name)s [%(request_id)s %(user)s %(tenant)s] ' + '%(instance)s%(message)s', + help='format string to use for log messages with context'), + cfg.StrOpt('logging_default_format_string', + default='sm-api %(process)d ' + '%(name)s [-] %(instance)s%(message)s', + help='format string to use for log messages without context'), + cfg.StrOpt('logging_debug_format_suffix', + default='%(funcName)s %(pathname)s:%(lineno)d', + help='data to append to log format when level is DEBUG'), + cfg.StrOpt('logging_exception_prefix', + default='%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s ' + '%(instance)s', + help='prefix each line of exception output with this format'), + cfg.ListOpt('default_log_levels', + default=[ + 'amqplib=WARN', + 'sqlalchemy=WARN', + 'boto=WARN', + 'suds=INFO', + 'keystone=INFO', + 'eventlet.wsgi.server=WARN' + ], + help='list of logger=LEVEL pairs'), + cfg.BoolOpt('publish_errors', + default=False, + help='publish error events'), + cfg.BoolOpt('fatal_deprecations', + default=False, + help='make deprecations fatal'), + + # NOTE(mikal): there are two options here because sometimes we are handed + # a full instance (and could include more information), and other times we + # are just handed a UUID for the instance. + cfg.StrOpt('instance_format', + default='[instance: %(uuid)s] ', + help='If an instance is passed with the log message, format ' + 'it like this'), + cfg.StrOpt('instance_uuid_format', + default='[instance: %(uuid)s] ', + help='If an instance UUID is passed with the log message, ' + 'format it like this'), +] + +CONF = cfg.CONF +CONF.register_cli_opts(common_cli_opts) +CONF.register_cli_opts(logging_cli_opts) +CONF.register_opts(generic_log_opts) +CONF.register_opts(log_opts) + +# our new audit level +# NOTE(jkoelker) Since we synthesized an audit level, make the logging +# module aware of it so it acts like other levels. +logging.AUDIT = logging.INFO + 1 +logging.addLevelName(logging.AUDIT, 'AUDIT') + + +try: + NullHandler = logging.NullHandler +except AttributeError: # NOTE(jkoelker) NullHandler added in Python 2.7 + class NullHandler(logging.Handler): + def handle(self, record): + pass + + def emit(self, record): + pass + + def createLock(self): + self.lock = None + + +def _dictify_context(context): + if context is None: + return None + if not isinstance(context, dict) and getattr(context, 'to_dict', None): + context = context.to_dict() + return context + + +def _get_binary_name(): + return os.path.basename(inspect.stack()[-1][1]) + + +def _get_log_file_path(binary=None): + logfile = CONF.log_file + logdir = CONF.log_dir + + if logfile and not logdir: + return logfile + + if logfile and logdir: + return os.path.join(logdir, logfile) + + if logdir: + binary = binary or _get_binary_name() + return '%s.log' % (os.path.join(logdir, binary),) + + +class BaseLoggerAdapter(logging.LoggerAdapter): + + def audit(self, msg, *args, **kwargs): + self.log(logging.AUDIT, msg, *args, **kwargs) + + +class LazyAdapter(BaseLoggerAdapter): + def __init__(self, name='unknown', version='unknown'): + self._logger = None + self.extra = {} + self.name = name + self.version = version + + @property + def logger(self): + if not self._logger: + self._logger = getLogger(self.name, self.version) + return self._logger + + +class ContextAdapter(BaseLoggerAdapter): + warn = logging.LoggerAdapter.warning + + def __init__(self, logger, project_name, version_string): + self.logger = logger + self.project = project_name + self.version = version_string + + @property + def handlers(self): + return self.logger.handlers + + def deprecated(self, msg, *args, **kwargs): + stdmsg = _("Deprecated: %s") % msg + if CONF.fatal_deprecations: + self.critical(stdmsg, *args, **kwargs) + raise DeprecatedConfig(msg=stdmsg) + else: + self.warn(stdmsg, *args, **kwargs) + + def process(self, msg, kwargs): + if 'extra' not in kwargs: + kwargs['extra'] = {} + extra = kwargs['extra'] + + context = kwargs.pop('context', None) + if not context: + context = getattr(local.store, 'context', None) + if context: + extra.update(_dictify_context(context)) + + instance = kwargs.pop('instance', None) + instance_extra = '' + if instance: + instance_extra = CONF.instance_format % instance + else: + instance_uuid = kwargs.pop('instance_uuid', None) + if instance_uuid: + instance_extra = (CONF.instance_uuid_format + % {'uuid': instance_uuid}) + extra.update({'instance': instance_extra}) + + extra.update({"project": self.project}) + extra.update({"version": self.version}) + extra['extra'] = extra.copy() + return msg, kwargs + + +class JSONFormatter(logging.Formatter): + def __init__(self, fmt=None, datefmt=None): + # NOTE(jkoelker) we ignore the fmt argument, but its still there + # since logging.config.fileConfig passes it. + self.datefmt = datefmt + + def formatException(self, ei, strip_newlines=True): + lines = traceback.format_exception(*ei) + if strip_newlines: + lines = [itertools.ifilter( + lambda x: x, + line.rstrip().splitlines()) for line in lines] + lines = list(itertools.chain(*lines)) + return lines + + def format(self, record): + message = {'message': record.getMessage(), + 'asctime': self.formatTime(record, self.datefmt), + 'name': record.name, + 'msg': record.msg, + 'args': record.args, + 'levelname': record.levelname, + 'levelno': record.levelno, + 'pathname': record.pathname, + 'filename': record.filename, + 'module': record.module, + 'lineno': record.lineno, + 'funcname': record.funcName, + 'created': record.created, + 'msecs': record.msecs, + 'relative_created': record.relativeCreated, + 'thread': record.thread, + 'thread_name': record.threadName, + 'process_name': record.processName, + 'process': record.process, + 'traceback': None} + + if hasattr(record, 'extra'): + message['extra'] = record.extra + + if record.exc_info: + message['traceback'] = self.formatException(record.exc_info) + + return jsonutils.dumps(message) + + +def _create_logging_excepthook(product_name): + def logging_excepthook(type, value, tb): + extra = {} + if CONF.verbose: + extra['exc_info'] = (type, value, tb) + getLogger(product_name).critical(str(value), **extra) + return logging_excepthook + + +class LogConfigError(Exception): + + message = _('Error loading logging config %(log_config)s: %(err_msg)s') + + def __init__(self, log_config, err_msg): + self.log_config = log_config + self.err_msg = err_msg + + def __str__(self): + return self.message % dict(log_config=self.log_config, + err_msg=self.err_msg) + + +def _load_log_config(log_config): + try: + logging.config.fileConfig(log_config) + except ConfigParser.Error as exc: + raise LogConfigError(log_config, str(exc)) + + +def setup(product_name): + """Setup logging.""" + if CONF.log_config: + _load_log_config(CONF.log_config) + else: + _setup_logging_from_conf() + sys.excepthook = _create_logging_excepthook(product_name) + + +def set_defaults(logging_context_format_string): + cfg.set_defaults(log_opts, + logging_context_format_string= + logging_context_format_string) + + +def _find_facility_from_conf(): + facility_names = logging.handlers.SysLogHandler.facility_names + facility = getattr(logging.handlers.SysLogHandler, + CONF.syslog_log_facility, + None) + + if facility is None and CONF.syslog_log_facility in facility_names: + facility = facility_names.get(CONF.syslog_log_facility) + + if facility is None: + valid_facilities = facility_names.keys() + consts = ['LOG_AUTH', 'LOG_AUTHPRIV', 'LOG_CRON', 'LOG_DAEMON', + 'LOG_FTP', 'LOG_KERN', 'LOG_LPR', 'LOG_MAIL', 'LOG_NEWS', + 'LOG_AUTH', 'LOG_SYSLOG', 'LOG_USER', 'LOG_UUCP', + 'LOG_LOCAL0', 'LOG_LOCAL1', 'LOG_LOCAL2', 'LOG_LOCAL3', + 'LOG_LOCAL4', 'LOG_LOCAL5', 'LOG_LOCAL6', 'LOG_LOCAL7'] + valid_facilities.extend(consts) + raise TypeError(_('syslog facility must be one of: %s') % + ', '.join("'%s'" % fac + for fac in valid_facilities)) + + return facility + + +def _setup_logging_from_conf(): + log_root = getLogger(None).logger + for handler in log_root.handlers: + log_root.removeHandler(handler) + + if CONF.use_syslog: + facility = _find_facility_from_conf() + syslog = logging.handlers.SysLogHandler(address='/dev/log', + facility=facility) + log_root.addHandler(syslog) + + logpath = _get_log_file_path() + if logpath: + filelog = logging.handlers.WatchedFileHandler(logpath) + log_root.addHandler(filelog) + + if CONF.use_stderr: + streamlog = ColorHandler() + log_root.addHandler(streamlog) + + elif not CONF.log_file: + # pass sys.stdout as a positional argument + # python2.6 calls the argument strm, in 2.7 it's stream + streamlog = logging.StreamHandler(sys.stdout) + log_root.addHandler(streamlog) + + if CONF.publish_errors: + handler = importutils.import_object( + "sm_api.openstack.common.log_handler.PublishErrorsHandler", + logging.ERROR) + log_root.addHandler(handler) + + datefmt = CONF.log_date_format + for handler in log_root.handlers: + # NOTE(alaski): CONF.log_format overrides everything currently. This + # should be deprecated in favor of context aware formatting. + if CONF.log_format: + handler.setFormatter(logging.Formatter(fmt=CONF.log_format, + datefmt=datefmt)) + log_root.info('Deprecated: log_format is now deprecated and will ' + 'be removed in the next release') + else: + handler.setFormatter(ContextFormatter(datefmt=datefmt)) + + if CONF.debug: + log_root.setLevel(logging.DEBUG) + elif CONF.verbose: + log_root.setLevel(logging.INFO) + else: + log_root.setLevel(logging.WARNING) + + for pair in CONF.default_log_levels: + mod, _sep, level_name = pair.partition('=') + level = logging.getLevelName(level_name) + logger = logging.getLogger(mod) + logger.setLevel(level) + +_loggers = {} + + +def getLogger(name='unknown', version='unknown'): + if name not in _loggers: + _loggers[name] = ContextAdapter(logging.getLogger(name), + name, + version) + return _loggers[name] + + +def getLazyLogger(name='unknown', version='unknown'): + """ + create a pass-through logger that does not create the real logger + until it is really needed and delegates all calls to the real logger + once it is created + """ + return LazyAdapter(name, version) + + +class WritableLogger(object): + """A thin wrapper that responds to `write` and logs.""" + + def __init__(self, logger, level=logging.INFO): + self.logger = logger + self.level = level + + def write(self, msg): + self.logger.log(self.level, msg) + + +class ContextFormatter(logging.Formatter): + """A context.RequestContext aware formatter configured through flags. + + The flags used to set format strings are: logging_context_format_string + and logging_default_format_string. You can also specify + logging_debug_format_suffix to append extra formatting if the log level is + debug. + + For information about what variables are available for the formatter see: + http://docs.python.org/library/logging.html#formatter + + """ + + def format(self, record): + """Uses contextstring if request_id is set, otherwise default.""" + # NOTE(sdague): default the fancier formating params + # to an empty string so we don't throw an exception if + # they get used + for key in ('instance', 'color'): + if key not in record.__dict__: + record.__dict__[key] = '' + + if record.__dict__.get('request_id', None): + self._fmt = CONF.logging_context_format_string + else: + self._fmt = CONF.logging_default_format_string + + if (record.levelno == logging.DEBUG and + CONF.logging_debug_format_suffix): + self._fmt += " " + CONF.logging_debug_format_suffix + + # Cache this on the record, Logger will respect our formated copy + if record.exc_info: + record.exc_text = self.formatException(record.exc_info, record) + return logging.Formatter.format(self, record) + + def formatException(self, exc_info, record=None): + """Format exception output with CONF.logging_exception_prefix.""" + if not record: + return logging.Formatter.formatException(self, exc_info) + + stringbuffer = cStringIO.StringIO() + traceback.print_exception(exc_info[0], exc_info[1], exc_info[2], + None, stringbuffer) + lines = stringbuffer.getvalue().split('\n') + stringbuffer.close() + + if CONF.logging_exception_prefix.find('%(asctime)') != -1: + record.asctime = self.formatTime(record, self.datefmt) + + formatted_lines = [] + for line in lines: + pl = CONF.logging_exception_prefix % record.__dict__ + fl = '%s%s' % (pl, line) + formatted_lines.append(fl) + return '\n'.join(formatted_lines) + + +class ColorHandler(logging.StreamHandler): + LEVEL_COLORS = { + logging.DEBUG: '\033[00;32m', # GREEN + logging.INFO: '\033[00;36m', # CYAN + logging.AUDIT: '\033[01;36m', # BOLD CYAN + logging.WARN: '\033[01;33m', # BOLD YELLOW + logging.ERROR: '\033[01;31m', # BOLD RED + logging.CRITICAL: '\033[01;31m', # BOLD RED + } + + def format(self, record): + record.color = self.LEVEL_COLORS[record.levelno] + return logging.StreamHandler.format(self, record) + + +class DeprecatedConfig(Exception): + message = _("Fatal call to deprecated config: %(msg)s") + + def __init__(self, msg): + super(Exception, self).__init__(self.message % dict(msg=msg)) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/log_handler.py b/service-mgmt-api/sm-api/sm_api/openstack/common/log_handler.py new file mode 100644 index 00000000..f319794a --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/log_handler.py @@ -0,0 +1,35 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +import logging + +from sm_api.openstack.common import notifier + +from oslo_config import cfg + + +class PublishErrorsHandler(logging.Handler): + def emit(self, record): + if ('sm_api.openstack.common.notifier.log_notifier' in + cfg.CONF.notification_driver): + return + notifier.api.notify(None, 'error.publisher', + 'error_notification', + notifier.api.ERROR, + dict(error=record.msg)) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/loopingcall.py b/service-mgmt-api/sm-api/sm_api/openstack/common/loopingcall.py new file mode 100644 index 00000000..51e0e74b --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/loopingcall.py @@ -0,0 +1,151 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Justin Santa Barbara +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import sys + +from eventlet import event +from eventlet import greenthread + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import timeutils + +LOG = logging.getLogger(__name__) + + +class LoopingCallDone(Exception): + """Exception to break out and stop a LoopingCall. + + The poll-function passed to LoopingCall can raise this exception to + break out of the loop normally. This is somewhat analogous to + StopIteration. + + An optional return-value can be included as the argument to the exception; + this return-value will be returned by LoopingCall.wait() + + """ + + def __init__(self, retvalue=True): + """:param retvalue: Value that LoopingCall.wait() should return.""" + self.retvalue = retvalue + + +class LoopingCallBase(object): + def __init__(self, f=None, *args, **kw): + self.args = args + self.kw = kw + self.f = f + self._running = False + self.done = None + + def stop(self): + self._running = False + + def wait(self): + return self.done.wait() + + +class FixedIntervalLoopingCall(LoopingCallBase): + """A fixed interval looping call.""" + + def start(self, interval, initial_delay=None): + self._running = True + done = event.Event() + + def _inner(): + if initial_delay: + greenthread.sleep(initial_delay) + + try: + while self._running: + start = timeutils.utcnow() + self.f(*self.args, **self.kw) + end = timeutils.utcnow() + if not self._running: + break + delay = interval - timeutils.delta_seconds(start, end) + if delay <= 0: + LOG.warn(_('task run outlasted interval by %s sec') % + -delay) + greenthread.sleep(delay if delay > 0 else 0) + except LoopingCallDone as e: + self.stop() + done.send(e.retvalue) + except Exception: + LOG.exception(_('in fixed duration looping call')) + done.send_exception(*sys.exc_info()) + return + else: + done.send(True) + + self.done = done + + greenthread.spawn_n(_inner) + return self.done + + +# TODO(mikal): this class name is deprecated in Havana and should be removed +# in the I release +LoopingCall = FixedIntervalLoopingCall + + +class DynamicLoopingCall(LoopingCallBase): + """A looping call which sleeps until the next known event. + + The function called should return how long to sleep for before being + called again. + """ + + def start(self, initial_delay=None, periodic_interval_max=None): + self._running = True + done = event.Event() + + def _inner(): + if initial_delay: + greenthread.sleep(initial_delay) + + try: + while self._running: + idle = self.f(*self.args, **self.kw) + if not self._running: + break + + if periodic_interval_max is not None: + idle = min(idle, periodic_interval_max) + LOG.debug(_('Dynamic looping call sleeping for %.02f ' + 'seconds'), idle) + greenthread.sleep(idle) + except LoopingCallDone as e: + self.stop() + done.send(e.retvalue) + except Exception: + LOG.exception(_('in dynamic looping call')) + done.send_exception(*sys.exc_info()) + return + else: + done.send(True) + + self.done = done + + greenthread.spawn(_inner) + return self.done diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/network_utils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/network_utils.py new file mode 100644 index 00000000..e7973d15 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/network_utils.py @@ -0,0 +1,73 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Network-related utilities and helper functions. +""" + +from sm_api.openstack.common import log as logging + + +LOG = logging.getLogger(__name__) + + +def parse_host_port(address, default_port=None): + """ + Interpret a string as a host:port pair. + An IPv6 address MUST be escaped if accompanied by a port, + because otherwise ambiguity ensues: 2001:db8:85a3::8a2e:370:7334 + means both [2001:db8:85a3::8a2e:370:7334] and + [2001:db8:85a3::8a2e:370]:7334. + + >>> parse_host_port('server01:80') + ('server01', 80) + >>> parse_host_port('server01') + ('server01', None) + >>> parse_host_port('server01', default_port=1234) + ('server01', 1234) + >>> parse_host_port('[::1]:80') + ('::1', 80) + >>> parse_host_port('[::1]') + ('::1', None) + >>> parse_host_port('[::1]', default_port=1234) + ('::1', 1234) + >>> parse_host_port('2001:db8:85a3::8a2e:370:7334', default_port=1234) + ('2001:db8:85a3::8a2e:370:7334', 1234) + + """ + if address[0] == '[': + # Escaped ipv6 + _host, _port = address[1:].split(']') + host = _host + if ':' in _port: + port = _port.split(':')[1] + else: + port = default_port + else: + if address.count(':') == 1: + host, port = address.split(':') + else: + # 0 means ipv4, >1 means ipv6. + # We prohibit unescaped ipv6 addresses with port. + host = address + port = default_port + + return (host, None if port is None else int(port)) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/__init__.py b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/__init__.py new file mode 100644 index 00000000..95c9e656 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/api.py b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/api.py new file mode 100644 index 00000000..8c9e33be --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/api.py @@ -0,0 +1,186 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import uuid + +from oslo_config import cfg + +from sm_api.openstack.common import context +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import importutils +from sm_api.openstack.common import jsonutils +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import timeutils + + +LOG = logging.getLogger(__name__) + +notifier_opts = [ + cfg.MultiStrOpt('notification_driver', + default=[], + help='Driver or drivers to handle sending notifications'), + cfg.StrOpt('default_notification_level', + default='INFO', + help='Default notification level for outgoing notifications'), + cfg.StrOpt('default_publisher_id', + default='$host', + help='Default publisher_id for outgoing notifications'), +] + +CONF = cfg.CONF +CONF.register_opts(notifier_opts) + +WARN = 'WARN' +INFO = 'INFO' +ERROR = 'ERROR' +CRITICAL = 'CRITICAL' +DEBUG = 'DEBUG' + +log_levels = (DEBUG, WARN, INFO, ERROR, CRITICAL) + + +class BadPriorityException(Exception): + pass + + +def notify_decorator(name, fn): + """ decorator for notify which is used from utils.monkey_patch() + + :param name: name of the function + :param function: - object of the function + :returns: function -- decorated function + + """ + def wrapped_func(*args, **kwarg): + body = {} + body['args'] = [] + body['kwarg'] = {} + for arg in args: + body['args'].append(arg) + for key in kwarg: + body['kwarg'][key] = kwarg[key] + + ctxt = context.get_context_from_function_and_args(fn, args, kwarg) + notify(ctxt, + CONF.default_publisher_id, + name, + CONF.default_notification_level, + body) + return fn(*args, **kwarg) + return wrapped_func + + +def publisher_id(service, host=None): + if not host: + host = CONF.host + return "%s.%s" % (service, host) + + +def notify(context, publisher_id, event_type, priority, payload): + """Sends a notification using the specified driver + + :param publisher_id: the source worker_type.host of the message + :param event_type: the literal type of event (ex. Instance Creation) + :param priority: patterned after the enumeration of Python logging + levels in the set (DEBUG, WARN, INFO, ERROR, CRITICAL) + :param payload: A python dictionary of attributes + + Outgoing message format includes the above parameters, and appends the + following: + + message_id + a UUID representing the id for this notification + + timestamp + the GMT timestamp the notification was sent at + + The composite message will be constructed as a dictionary of the above + attributes, which will then be sent via the transport mechanism defined + by the driver. + + Message example:: + + {'message_id': str(uuid.uuid4()), + 'publisher_id': 'compute.host1', + 'timestamp': timeutils.utcnow(), + 'priority': 'WARN', + 'event_type': 'compute.create_instance', + 'payload': {'instance_id': 12, ... }} + + """ + if priority not in log_levels: + raise BadPriorityException( + _('%s not in valid priorities') % priority) + + # Ensure everything is JSON serializable. + payload = jsonutils.to_primitive(payload, convert_instances=True) + + msg = dict(message_id=str(uuid.uuid4()), + publisher_id=publisher_id, + event_type=event_type, + priority=priority, + payload=payload, + timestamp=str(timeutils.utcnow())) + + for driver in _get_drivers(): + try: + driver.notify(context, msg) + except Exception as e: + LOG.exception(_("Problem '%(e)s' attempting to " + "send to notification system. " + "Payload=%(payload)s") + % dict(e=e, payload=payload)) + + +_drivers = None + + +def _get_drivers(): + """Instantiate, cache, and return drivers based on the CONF.""" + global _drivers + if _drivers is None: + _drivers = {} + for notification_driver in CONF.notification_driver: + add_driver(notification_driver) + + return _drivers.values() + + +def add_driver(notification_driver): + """Add a notification driver at runtime.""" + # Make sure the driver list is initialized. + _get_drivers() + if isinstance(notification_driver, basestring): + # Load and add + try: + driver = importutils.import_module(notification_driver) + _drivers[notification_driver] = driver + except ImportError: + LOG.exception(_("Failed to load notifier %s. " + "These notifications will not be sent.") % + notification_driver) + else: + # Driver is already loaded; just add the object. + _drivers[notification_driver] = notification_driver + + +def _reset_drivers(): + """Used by unit tests to reset the drivers.""" + global _drivers + _drivers = None diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/log_notifier.py b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/log_notifier.py new file mode 100644 index 00000000..bd06b65b --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/log_notifier.py @@ -0,0 +1,39 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from oslo_config import cfg + +from sm_api.openstack.common import jsonutils +from sm_api.openstack.common import log as logging + + +CONF = cfg.CONF + + +def notify(_context, message): + """Notifies the recipient of the desired event given the model. + Log notifications using openstack's default logging system""" + + priority = message.get('priority', + CONF.default_notification_level) + priority = priority.lower() + logger = logging.getLogger( + 'sm_api.openstack.common.notification.%s' % + message['event_type']) + getattr(logger, priority)(jsonutils.dumps(message)) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/no_op_notifier.py b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/no_op_notifier.py new file mode 100644 index 00000000..6a90b891 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/no_op_notifier.py @@ -0,0 +1,23 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + + +def notify(_context, message): + """Notifies the recipient of the desired event given the model""" + pass diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/rpc_notifier.py b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/rpc_notifier.py new file mode 100644 index 00000000..9d6c98c5 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/rpc_notifier.py @@ -0,0 +1,50 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from oslo_config import cfg + +from sm_api.openstack.common import context as req_context +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import rpc + +LOG = logging.getLogger(__name__) + +notification_topic_opt = cfg.ListOpt( + 'notification_topics', default=['notifications', ], + help='AMQP topic used for openstack notifications') + +CONF = cfg.CONF +CONF.register_opt(notification_topic_opt) + + +def notify(context, message): + """Sends a notification via RPC""" + if not context: + context = req_context.get_admin_context() + priority = message.get('priority', + CONF.default_notification_level) + priority = priority.lower() + for topic in CONF.notification_topics: + topic = '%s.%s' % (topic, priority) + try: + rpc.notify(context, topic, message) + except Exception: + LOG.exception(_("Could not send notification to %(topic)s. " + "Payload=%(message)s"), locals()) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/rpc_notifier2.py b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/rpc_notifier2.py new file mode 100644 index 00000000..09fa728f --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/rpc_notifier2.py @@ -0,0 +1,56 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +'''messaging based notification driver, with message envelopes''' + +from oslo_config import cfg + +from sm_api.openstack.common import context as req_context +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import rpc + +LOG = logging.getLogger(__name__) + +notification_topic_opt = cfg.ListOpt( + 'topics', default=['notifications', ], + help='AMQP topic(s) used for openstack notifications') + +opt_group = cfg.OptGroup(name='rpc_notifier2', + title='Options for rpc_notifier2') + +CONF = cfg.CONF +CONF.register_group(opt_group) +CONF.register_opt(notification_topic_opt, opt_group) + + +def notify(context, message): + """Sends a notification via RPC""" + if not context: + context = req_context.get_admin_context() + priority = message.get('priority', + CONF.default_notification_level) + priority = priority.lower() + for topic in CONF.rpc_notifier2.topics: + topic = '%s.%s' % (topic, priority) + try: + rpc.notify(context, topic, message, envelope=True) + except Exception: + LOG.exception(_("Could not send notification to %(topic)s. " + "Payload=%(message)s"), locals()) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/test_notifier.py b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/test_notifier.py new file mode 100644 index 00000000..8be4e7d7 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/notifier/test_notifier.py @@ -0,0 +1,26 @@ +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + + +NOTIFICATIONS = [] + + +def notify(_context, message): + """Test notifier, stores notifications in memory for unittests.""" + NOTIFICATIONS.append(message) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/periodic_task.py b/service-mgmt-api/sm-api/sm_api/openstack/common/periodic_task.py new file mode 100644 index 00000000..bec193a0 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/periodic_task.py @@ -0,0 +1,185 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# + +import datetime +import time + +from oslo_config import cfg +import six + +from sm_api.openstack.common.gettextutils import _ # noqa +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import timeutils + + +periodic_opts = [ + cfg.BoolOpt('run_external_periodic_tasks', + default=True, + help=('Some periodic tasks can be run in a separate process. ' + 'Should we run them here?')), +] + +CONF = cfg.CONF +CONF.register_opts(periodic_opts) + +LOG = logging.getLogger(__name__) + +DEFAULT_INTERVAL = 60.0 + + +class InvalidPeriodicTaskArg(Exception): + message = _("Unexpected argument for periodic task creation: %(arg)s.") + + +def periodic_task(*args, **kwargs): + """Decorator to indicate that a method is a periodic task. + + This decorator can be used in two ways: + + 1. Without arguments '@periodic_task', this will be run on every cycle + of the periodic scheduler. + + 2. With arguments: + @periodic_task(spacing=N [, run_immediately=[True|False]]) + this will be run on approximately every N seconds. If this number is + negative the periodic task will be disabled. If the run_immediately + argument is provided and has a value of 'True', the first run of the + task will be shortly after task scheduler starts. If + run_immediately is omitted or set to 'False', the first time the + task runs will be approximately N seconds after the task scheduler + starts. + """ + def decorator(f): + # Test for old style invocation + if 'ticks_between_runs' in kwargs: + raise InvalidPeriodicTaskArg(arg='ticks_between_runs') + + # Control if run at all + f._periodic_task = True + f._periodic_external_ok = kwargs.pop('external_process_ok', False) + if f._periodic_external_ok and not CONF.run_external_periodic_tasks: + f._periodic_enabled = False + else: + f._periodic_enabled = kwargs.pop('enabled', True) + + # Control frequency + f._periodic_spacing = kwargs.pop('spacing', 0) + f._periodic_immediate = kwargs.pop('run_immediately', False) + if f._periodic_immediate: + f._periodic_last_run = None + else: + f._periodic_last_run = timeutils.utcnow() + return f + + # NOTE(sirp): The `if` is necessary to allow the decorator to be used with + # and without parens. + # + # In the 'with-parens' case (with kwargs present), this function needs to + # return a decorator function since the interpreter will invoke it like: + # + # periodic_task(*args, **kwargs)(f) + # + # In the 'without-parens' case, the original function will be passed + # in as the first argument, like: + # + # periodic_task(f) + if kwargs: + return decorator + else: + return decorator(args[0]) + + +class _PeriodicTasksMeta(type): + def __init__(cls, names, bases, dict_): + """Metaclass that allows us to collect decorated periodic tasks.""" + super(_PeriodicTasksMeta, cls).__init__(names, bases, dict_) + + # NOTE(sirp): if the attribute is not present then we must be the base + # class, so, go ahead an initialize it. If the attribute is present, + # then we're a subclass so make a copy of it so we don't step on our + # parent's toes. + try: + cls._periodic_tasks = cls._periodic_tasks[:] + except AttributeError: + cls._periodic_tasks = [] + + try: + cls._periodic_last_run = cls._periodic_last_run.copy() + except AttributeError: + cls._periodic_last_run = {} + + try: + cls._periodic_spacing = cls._periodic_spacing.copy() + except AttributeError: + cls._periodic_spacing = {} + + for value in cls.__dict__.values(): + if getattr(value, '_periodic_task', False): + task = value + name = task.__name__ + + if task._periodic_spacing < 0: + LOG.info(_('Skipping periodic task %(task)s because ' + 'its interval is negative'), + {'task': name}) + continue + if not task._periodic_enabled: + LOG.info(_('Skipping periodic task %(task)s because ' + 'it is disabled'), + {'task': name}) + continue + + # A periodic spacing of zero indicates that this task should + # be run every pass + if task._periodic_spacing == 0: + task._periodic_spacing = None + + cls._periodic_tasks.append((name, task)) + cls._periodic_spacing[name] = task._periodic_spacing + cls._periodic_last_run[name] = task._periodic_last_run + + +@six.add_metaclass(_PeriodicTasksMeta) +class PeriodicTasks(object): + + def run_periodic_tasks(self, context, raise_on_error=False): + """Tasks to be run at a periodic interval.""" + idle_for = DEFAULT_INTERVAL + for task_name, task in self._periodic_tasks: + full_task_name = '.'.join([self.__class__.__name__, task_name]) + + now = timeutils.utcnow() + spacing = self._periodic_spacing[task_name] + last_run = self._periodic_last_run[task_name] + + # If a periodic task is _nearly_ due, then we'll run it early + if spacing is not None and last_run is not None: + due = last_run + datetime.timedelta(seconds=spacing) + if not timeutils.is_soon(due, 0.2): + idle_for = min(idle_for, timeutils.delta_seconds(now, due)) + continue + + if spacing is not None: + idle_for = min(idle_for, spacing) + + LOG.debug(_("Running periodic task %(full_task_name)s"), + {"full_task_name": full_task_name}) + self._periodic_last_run[task_name] = timeutils.utcnow() + + try: + task(self, context) + except Exception as e: + if raise_on_error: + raise + LOG.exception(_("Error during %(full_task_name)s: %(e)s"), + {"full_task_name": full_task_name, "e": e}) + time.sleep(0) + + return idle_for diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/policy.py b/service-mgmt-api/sm-api/sm_api/openstack/common/policy.py new file mode 100644 index 00000000..ea959767 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/policy.py @@ -0,0 +1,784 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2012 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Common Policy Engine Implementation + +Policies can be expressed in one of two forms: A list of lists, or a +string written in the new policy language. + +In the list-of-lists representation, each check inside the innermost +list is combined as with an "and" conjunction--for that check to pass, +all the specified checks must pass. These innermost lists are then +combined as with an "or" conjunction. This is the original way of +expressing policies, but there now exists a new way: the policy +language. + +In the policy language, each check is specified the same way as in the +list-of-lists representation: a simple "a:b" pair that is matched to +the correct code to perform that check. However, conjunction +operators are available, allowing for more expressiveness in crafting +policies. + +As an example, take the following rule, expressed in the list-of-lists +representation:: + + [["role:admin"], ["project_id:%(project_id)s", "role:projectadmin"]] + +In the policy language, this becomes:: + + role:admin or (project_id:%(project_id)s and role:projectadmin) + +The policy language also has the "not" operator, allowing a richer +policy rule:: + + project_id:%(project_id)s and not role:dunce + +Finally, two special policy checks should be mentioned; the policy +check "@" will always accept an access, and the policy check "!" will +always reject an access. (Note that if a rule is either the empty +list ("[]") or the empty string, this is equivalent to the "@" policy +check.) Of these, the "!" policy check is probably the most useful, +as it allows particular rules to be explicitly disabled. +""" + +import abc +import re +import urllib + +import six +import urllib2 + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import jsonutils +from sm_api.openstack.common import log as logging + + +LOG = logging.getLogger(__name__) + + +_rules = None +_checks = {} + + +class Rules(dict): + """ + A store for rules. Handles the default_rule setting directly. + """ + + @classmethod + def load_json(cls, data, default_rule=None): + """ + Allow loading of JSON rule data. + """ + + # Suck in the JSON data and parse the rules + rules = dict((k, parse_rule(v)) for k, v in + jsonutils.loads(data).items()) + + return cls(rules, default_rule) + + def __init__(self, rules=None, default_rule=None): + """Initialize the Rules store.""" + + super(Rules, self).__init__(rules or {}) + self.default_rule = default_rule + + def __missing__(self, key): + """Implements the default rule handling.""" + + # If the default rule isn't actually defined, do something + # reasonably intelligent + if not self.default_rule or self.default_rule not in self: + raise KeyError(key) + + return self[self.default_rule] + + def __str__(self): + """Dumps a string representation of the rules.""" + + # Start by building the canonical strings for the rules + out_rules = {} + for key, value in self.items(): + # Use empty string for singleton TrueCheck instances + if isinstance(value, TrueCheck): + out_rules[key] = '' + else: + out_rules[key] = str(value) + + # Dump a pretty-printed JSON representation + return jsonutils.dumps(out_rules, indent=4) + + +# Really have to figure out a way to deprecate this +def set_rules(rules): + """Set the rules in use for policy checks.""" + + global _rules + + _rules = rules + + +# Ditto +def reset(): + """Clear the rules used for policy checks.""" + + global _rules + + _rules = None + + +def check(rule, target, creds, exc=None, *args, **kwargs): + """ + Checks authorization of a rule against the target and credentials. + + :param rule: The rule to evaluate. + :param target: As much information about the object being operated + on as possible, as a dictionary. + :param creds: As much information about the user performing the + action as possible, as a dictionary. + :param exc: Class of the exception to raise if the check fails. + Any remaining arguments passed to check() (both + positional and keyword arguments) will be passed to + the exception class. If exc is not provided, returns + False. + + :return: Returns False if the policy does not allow the action and + exc is not provided; otherwise, returns a value that + evaluates to True. Note: for rules using the "case" + expression, this True value will be the specified string + from the expression. + """ + + # Allow the rule to be a Check tree + if isinstance(rule, BaseCheck): + result = rule(target, creds) + elif not _rules: + # No rules to reference means we're going to fail closed + result = False + else: + try: + # Evaluate the rule + result = _rules[rule](target, creds) + except KeyError: + # If the rule doesn't exist, fail closed + result = False + + # If it is False, raise the exception if requested + if exc and result is False: + raise exc(*args, **kwargs) + + return result + + +class BaseCheck(object): + """ + Abstract base class for Check classes. + """ + + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def __str__(self): + """ + Retrieve a string representation of the Check tree rooted at + this node. + """ + + pass + + @abc.abstractmethod + def __call__(self, target, cred): + """ + Perform the check. Returns False to reject the access or a + true value (not necessary True) to accept the access. + """ + + pass + + +class FalseCheck(BaseCheck): + """ + A policy check that always returns False (disallow). + """ + + def __str__(self): + """Return a string representation of this check.""" + + return "!" + + def __call__(self, target, cred): + """Check the policy.""" + + return False + + +class TrueCheck(BaseCheck): + """ + A policy check that always returns True (allow). + """ + + def __str__(self): + """Return a string representation of this check.""" + + return "@" + + def __call__(self, target, cred): + """Check the policy.""" + + return True + + +class Check(BaseCheck): + """ + A base class to allow for user-defined policy checks. + """ + + def __init__(self, kind, match): + """ + :param kind: The kind of the check, i.e., the field before the + ':'. + :param match: The match of the check, i.e., the field after + the ':'. + """ + + self.kind = kind + self.match = match + + def __str__(self): + """Return a string representation of this check.""" + + return "%s:%s" % (self.kind, self.match) + + +class NotCheck(BaseCheck): + """ + A policy check that inverts the result of another policy check. + Implements the "not" operator. + """ + + def __init__(self, rule): + """ + Initialize the 'not' check. + + :param rule: The rule to negate. Must be a Check. + """ + + self.rule = rule + + def __str__(self): + """Return a string representation of this check.""" + + return "not %s" % self.rule + + def __call__(self, target, cred): + """ + Check the policy. Returns the logical inverse of the wrapped + check. + """ + + return not self.rule(target, cred) + + +class AndCheck(BaseCheck): + """ + A policy check that requires that a list of other checks all + return True. Implements the "and" operator. + """ + + def __init__(self, rules): + """ + Initialize the 'and' check. + + :param rules: A list of rules that will be tested. + """ + + self.rules = rules + + def __str__(self): + """Return a string representation of this check.""" + + return "(%s)" % ' and '.join(str(r) for r in self.rules) + + def __call__(self, target, cred): + """ + Check the policy. Requires that all rules accept in order to + return True. + """ + + for rule in self.rules: + if not rule(target, cred): + return False + + return True + + def add_check(self, rule): + """ + Allows addition of another rule to the list of rules that will + be tested. Returns the AndCheck object for convenience. + """ + + self.rules.append(rule) + return self + + +class OrCheck(BaseCheck): + """ + A policy check that requires that at least one of a list of other + checks returns True. Implements the "or" operator. + """ + + def __init__(self, rules): + """ + Initialize the 'or' check. + + :param rules: A list of rules that will be tested. + """ + + self.rules = rules + + def __str__(self): + """Return a string representation of this check.""" + + return "(%s)" % ' or '.join(str(r) for r in self.rules) + + def __call__(self, target, cred): + """ + Check the policy. Requires that at least one rule accept in + order to return True. + """ + + for rule in self.rules: + if rule(target, cred): + return True + + return False + + def add_check(self, rule): + """ + Allows addition of another rule to the list of rules that will + be tested. Returns the OrCheck object for convenience. + """ + + self.rules.append(rule) + return self + + +def _parse_check(rule): + """ + Parse a single base check rule into an appropriate Check object. + """ + + # Handle the special checks + if rule == '!': + return FalseCheck() + elif rule == '@': + return TrueCheck() + + try: + kind, match = rule.split(':', 1) + except Exception: + LOG.exception(_("Failed to understand rule %(rule)s") % locals()) + # If the rule is invalid, we'll fail closed + return FalseCheck() + + # Find what implements the check + if kind in _checks: + return _checks[kind](kind, match) + elif None in _checks: + return _checks[None](kind, match) + else: + LOG.error(_("No handler for matches of kind %s") % kind) + return FalseCheck() + + +def _parse_list_rule(rule): + """ + Provided for backwards compatibility. Translates the old + list-of-lists syntax into a tree of Check objects. + """ + + # Empty rule defaults to True + if not rule: + return TrueCheck() + + # Outer list is joined by "or"; inner list by "and" + or_list = [] + for inner_rule in rule: + # Elide empty inner lists + if not inner_rule: + continue + + # Handle bare strings + if isinstance(inner_rule, basestring): + inner_rule = [inner_rule] + + # Parse the inner rules into Check objects + and_list = [_parse_check(r) for r in inner_rule] + + # Append the appropriate check to the or_list + if len(and_list) == 1: + or_list.append(and_list[0]) + else: + or_list.append(AndCheck(and_list)) + + # If we have only one check, omit the "or" + if not or_list: + return FalseCheck() + elif len(or_list) == 1: + return or_list[0] + + return OrCheck(or_list) + + +# Used for tokenizing the policy language +_tokenize_re = re.compile(r'\s+') + + +def _parse_tokenize(rule): + """ + Tokenizer for the policy language. + + Most of the single-character tokens are specified in the + _tokenize_re; however, parentheses need to be handled specially, + because they can appear inside a check string. Thankfully, those + parentheses that appear inside a check string can never occur at + the very beginning or end ("%(variable)s" is the correct syntax). + """ + + for tok in _tokenize_re.split(rule): + # Skip empty tokens + if not tok or tok.isspace(): + continue + + # Handle leading parens on the token + clean = tok.lstrip('(') + for i in range(len(tok) - len(clean)): + yield '(', '(' + + # If it was only parentheses, continue + if not clean: + continue + else: + tok = clean + + # Handle trailing parens on the token + clean = tok.rstrip(')') + trail = len(tok) - len(clean) + + # Yield the cleaned token + lowered = clean.lower() + if lowered in ('and', 'or', 'not'): + # Special tokens + yield lowered, clean + elif clean: + # Not a special token, but not composed solely of ')' + if len(tok) >= 2 and ((tok[0], tok[-1]) in + [('"', '"'), ("'", "'")]): + # It's a quoted string + yield 'string', tok[1:-1] + else: + yield 'check', _parse_check(clean) + + # Yield the trailing parens + for i in range(trail): + yield ')', ')' + + +class ParseStateMeta(type): + """ + Metaclass for the ParseState class. Facilitates identifying + reduction methods. + """ + + def __new__(mcs, name, bases, cls_dict): + """ + Create the class. Injects the 'reducers' list, a list of + tuples matching token sequences to the names of the + corresponding reduction methods. + """ + + reducers = [] + + for key, value in cls_dict.items(): + if not hasattr(value, 'reducers'): + continue + for reduction in value.reducers: + reducers.append((reduction, key)) + + cls_dict['reducers'] = reducers + + return super(ParseStateMeta, mcs).__new__(mcs, name, bases, cls_dict) + + +def reducer(*tokens): + """ + Decorator for reduction methods. Arguments are a sequence of + tokens, in order, which should trigger running this reduction + method. + """ + + def decorator(func): + # Make sure we have a list of reducer sequences + if not hasattr(func, 'reducers'): + func.reducers = [] + + # Add the tokens to the list of reducer sequences + func.reducers.append(list(tokens)) + + return func + + return decorator + + +class ParseState(object): + """ + Implement the core of parsing the policy language. Uses a greedy + reduction algorithm to reduce a sequence of tokens into a single + terminal, the value of which will be the root of the Check tree. + + Note: error reporting is rather lacking. The best we can get with + this parser formulation is an overall "parse failed" error. + Fortunately, the policy language is simple enough that this + shouldn't be that big a problem. + """ + + __metaclass__ = ParseStateMeta + + def __init__(self): + """Initialize the ParseState.""" + + self.tokens = [] + self.values = [] + + def reduce(self): + """ + Perform a greedy reduction of the token stream. If a reducer + method matches, it will be executed, then the reduce() method + will be called recursively to search for any more possible + reductions. + """ + + for reduction, methname in self.reducers: + if (len(self.tokens) >= len(reduction) and + self.tokens[-len(reduction):] == reduction): + # Get the reduction method + meth = getattr(self, methname) + + # Reduce the token stream + results = meth(*self.values[-len(reduction):]) + + # Update the tokens and values + self.tokens[-len(reduction):] = [r[0] for r in results] + self.values[-len(reduction):] = [r[1] for r in results] + + # Check for any more reductions + return self.reduce() + + def shift(self, tok, value): + """Adds one more token to the state. Calls reduce().""" + + self.tokens.append(tok) + self.values.append(value) + + # Do a greedy reduce... + self.reduce() + + @property + def result(self): + """ + Obtain the final result of the parse. Raises ValueError if + the parse failed to reduce to a single result. + """ + + if len(self.values) != 1: + raise ValueError("Could not parse rule") + return self.values[0] + + @reducer('(', 'check', ')') + @reducer('(', 'and_expr', ')') + @reducer('(', 'or_expr', ')') + def _wrap_check(self, _p1, check, _p2): + """Turn parenthesized expressions into a 'check' token.""" + + return [('check', check)] + + @reducer('check', 'and', 'check') + def _make_and_expr(self, check1, _and, check2): + """ + Create an 'and_expr' from two checks joined by the 'and' + operator. + """ + + return [('and_expr', AndCheck([check1, check2]))] + + @reducer('and_expr', 'and', 'check') + def _extend_and_expr(self, and_expr, _and, check): + """ + Extend an 'and_expr' by adding one more check. + """ + + return [('and_expr', and_expr.add_check(check))] + + @reducer('check', 'or', 'check') + def _make_or_expr(self, check1, _or, check2): + """ + Create an 'or_expr' from two checks joined by the 'or' + operator. + """ + + return [('or_expr', OrCheck([check1, check2]))] + + @reducer('or_expr', 'or', 'check') + def _extend_or_expr(self, or_expr, _or, check): + """ + Extend an 'or_expr' by adding one more check. + """ + + return [('or_expr', or_expr.add_check(check))] + + @reducer('not', 'check') + def _make_not_expr(self, _not, check): + """Invert the result of another check.""" + + return [('check', NotCheck(check))] + + +def _parse_text_rule(rule): + """ + Translates a policy written in the policy language into a tree of + Check objects. + """ + + # Empty rule means always accept + if not rule: + return TrueCheck() + + # Parse the token stream + state = ParseState() + for tok, value in _parse_tokenize(rule): + state.shift(tok, value) + + try: + return state.result + except ValueError: + # Couldn't parse the rule + LOG.exception(_("Failed to understand rule %(rule)r") % locals()) + + # Fail closed + return FalseCheck() + + +def parse_rule(rule): + """ + Parses a policy rule into a tree of Check objects. + """ + + # If the rule is a string, it's in the policy language + if isinstance(rule, basestring): + return _parse_text_rule(rule) + return _parse_list_rule(rule) + + +def register(name, func=None): + """ + Register a function or Check class as a policy check. + + :param name: Gives the name of the check type, e.g., 'rule', + 'role', etc. If name is None, a default check type + will be registered. + :param func: If given, provides the function or class to register. + If not given, returns a function taking one argument + to specify the function or class to register, + allowing use as a decorator. + """ + + # Perform the actual decoration by registering the function or + # class. Returns the function or class for compliance with the + # decorator interface. + def decorator(func): + _checks[name] = func + return func + + # If the function or class is given, do the registration + if func: + return decorator(func) + + return decorator + + +@register("rule") +class RuleCheck(Check): + def __call__(self, target, creds): + """ + Recursively checks credentials based on the defined rules. + """ + + try: + return _rules[self.match](target, creds) + except KeyError: + # We don't have any matching rule; fail closed + return False + + +@register("role") +class RoleCheck(Check): + def __call__(self, target, creds): + """Check that there is a matching role in the cred dict.""" + + return self.match.lower() in [x.lower() for x in creds['roles']] + + +@register('http') +class HttpCheck(Check): + def __call__(self, target, creds): + """ + Check http: rules by calling to a remote server. + + This example implementation simply verifies that the response + is exactly 'True'. + """ + + url = ('http:' + self.match) % target + data = {'target': jsonutils.dumps(target), + 'credentials': jsonutils.dumps(creds)} + post_data = urllib.urlencode(data) + f = urllib2.urlopen(url, post_data) + return f.read() == "True" + + +@register(None) +class GenericCheck(Check): + def __call__(self, target, creds): + """ + Check an individual match. + + Matches look like: + + tenant:%(tenant_id)s + role:compute:admin + """ + + # TODO(termie): do dict inspection via dot syntax + match = self.match % target + if self.kind in creds: + return match == six.text_type(creds[self.kind]) + return False diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/processutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/processutils.py new file mode 100644 index 00000000..86a29d03 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/processutils.py @@ -0,0 +1,251 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +System-level utilities and helper functions. +""" + +import os +import random +import shlex +import signal + +from eventlet.green import subprocess +from eventlet import greenthread + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging + + +LOG = logging.getLogger(__name__) + + +class InvalidArgumentError(Exception): + def __init__(self, message=None): + super(InvalidArgumentError, self).__init__(message) + + +class UnknownArgumentError(Exception): + def __init__(self, message=None): + super(UnknownArgumentError, self).__init__(message) + + +class ProcessExecutionError(Exception): + def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None, + description=None): + self.exit_code = exit_code + self.stderr = stderr + self.stdout = stdout + self.cmd = cmd + self.description = description + + if description is None: + description = "Unexpected error while running command." + if exit_code is None: + exit_code = '-' + message = ("%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" + % (description, cmd, exit_code, stdout, stderr)) + super(ProcessExecutionError, self).__init__(message) + + +class NoRootWrapSpecified(Exception): + def __init__(self, message=None): + super(NoRootWrapSpecified, self).__init__(message) + + +def _subprocess_setup(): + # Python installs a SIGPIPE handler by default. This is usually not what + # non-Python subprocesses expect. + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + +def execute(*cmd, **kwargs): + """ + Helper method to shell out and execute a command through subprocess with + optional retry. + + :param cmd: Passed to subprocess.Popen. + :type cmd: string + :param process_input: Send to opened process. + :type proces_input: string + :param check_exit_code: Single bool, int, or list of allowed exit + codes. Defaults to [0]. Raise + :class:`ProcessExecutionError` unless + program exits with one of these code. + :type check_exit_code: boolean, int, or [int] + :param delay_on_retry: True | False. Defaults to True. If set to True, + wait a short amount of time before retrying. + :type delay_on_retry: boolean + :param attempts: How many times to retry cmd. + :type attempts: int + :param run_as_root: True | False. Defaults to False. If set to True, + the command is prefixed by the command specified + in the root_helper kwarg. + :type run_as_root: boolean + :param root_helper: command to prefix to commands called with + run_as_root=True + :type root_helper: string + :param shell: whether or not there should be a shell used to + execute this command. Defaults to false. + :type shell: boolean + :returns: (stdout, stderr) from process execution + :raises: :class:`UnknownArgumentError` on + receiving unknown arguments + :raises: :class:`ProcessExecutionError` + """ + + process_input = kwargs.pop('process_input', None) + check_exit_code = kwargs.pop('check_exit_code', [0]) + ignore_exit_code = False + delay_on_retry = kwargs.pop('delay_on_retry', True) + attempts = kwargs.pop('attempts', 1) + run_as_root = kwargs.pop('run_as_root', False) + root_helper = kwargs.pop('root_helper', '') + shell = kwargs.pop('shell', False) + + if isinstance(check_exit_code, bool): + ignore_exit_code = not check_exit_code + check_exit_code = [0] + elif isinstance(check_exit_code, int): + check_exit_code = [check_exit_code] + + if kwargs: + raise UnknownArgumentError(_('Got unknown keyword args ' + 'to utils.execute: %r') % kwargs) + + if run_as_root and os.geteuid() != 0: + if not root_helper: + raise NoRootWrapSpecified( + message=('Command requested root, but did not specify a root ' + 'helper.')) + cmd = shlex.split(root_helper) + list(cmd) + + cmd = map(str, cmd) + + while attempts > 0: + attempts -= 1 + try: + LOG.debug(_('Running cmd (subprocess): %s'), ' '.join(cmd)) + _PIPE = subprocess.PIPE # pylint: disable=E1101 + + if os.name == 'nt': + preexec_fn = None + close_fds = False + else: + preexec_fn = _subprocess_setup + close_fds = True + + obj = subprocess.Popen(cmd, + stdin=_PIPE, + stdout=_PIPE, + stderr=_PIPE, + close_fds=close_fds, + preexec_fn=preexec_fn, + shell=shell) + result = None + if process_input is not None: + result = obj.communicate(process_input) + else: + result = obj.communicate() + obj.stdin.close() # pylint: disable=E1101 + _returncode = obj.returncode # pylint: disable=E1101 + if _returncode: + LOG.debug(_('Result was %s') % _returncode) + if not ignore_exit_code and _returncode not in check_exit_code: + (stdout, stderr) = result + raise ProcessExecutionError(exit_code=_returncode, + stdout=stdout, + stderr=stderr, + cmd=' '.join(cmd)) + return result + except ProcessExecutionError: + if not attempts: + raise + else: + LOG.debug(_('%r failed. Retrying.'), cmd) + if delay_on_retry: + greenthread.sleep(random.randint(20, 200) / 100.0) + finally: + # NOTE(termie): this appears to be necessary to let the subprocess + # call clean something up in between calls, without + # it two execute calls in a row hangs the second one + greenthread.sleep(0) + + +def trycmd(*args, **kwargs): + """ + A wrapper around execute() to more easily handle warnings and errors. + + Returns an (out, err) tuple of strings containing the output of + the command's stdout and stderr. If 'err' is not empty then the + command can be considered to have failed. + + :discard_warnings True | False. Defaults to False. If set to True, + then for succeeding commands, stderr is cleared + + """ + discard_warnings = kwargs.pop('discard_warnings', False) + + try: + out, err = execute(*args, **kwargs) + failed = False + except ProcessExecutionError, exn: + out, err = '', str(exn) + failed = True + + if not failed and discard_warnings and err: + # Handle commands that output to stderr but otherwise succeed + err = '' + + return out, err + + +def ssh_execute(ssh, cmd, process_input=None, + addl_env=None, check_exit_code=True): + LOG.debug(_('Running cmd (SSH): %s'), cmd) + if addl_env: + raise InvalidArgumentError(_('Environment not supported over SSH')) + + if process_input: + # This is (probably) fixable if we need it... + raise InvalidArgumentError(_('process_input not supported over SSH')) + + stdin_stream, stdout_stream, stderr_stream = ssh.exec_command(cmd) + channel = stdout_stream.channel + + # NOTE(justinsb): This seems suspicious... + # ...other SSH clients have buffering issues with this approach + stdout = stdout_stream.read() + stderr = stderr_stream.read() + stdin_stream.close() + + exit_status = channel.recv_exit_status() + + # exit_status == -1 if no exit code was returned + if exit_status != -1: + LOG.debug(_('Result was %s') % exit_status) + if check_exit_code and exit_status != 0: + raise ProcessExecutionError(exit_code=exit_status, + stdout=stdout, + stderr=stderr, + cmd=cmd) + + return (stdout, stderr) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/__init__.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/__init__.py new file mode 100644 index 00000000..c0b12fbe --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/__init__.py @@ -0,0 +1,20 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/cmd.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/cmd.py new file mode 100755 index 00000000..4f104faf --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/cmd.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Root wrapper for OpenStack services + + Filters which commands a service is allowed to run as another user. + + To use this with sm_api, you should set the following in + sm_api.conf: + rootwrap_config=/etc/sm_api/rootwrap.conf + + You also need to let the sm_api user run sm_api-rootwrap + as root in sudoers: + sm_api ALL = (root) NOPASSWD: /usr/bin/sm_api-rootwrap + /etc/sm_api/rootwrap.conf * + + Service packaging should deploy .filters files only on nodes where + they are needed, to avoid allowing more than is necessary. +""" + +from __future__ import print_function + +import ConfigParser +import logging +import os +import pwd +import signal +import subprocess +import sys + + +RC_UNAUTHORIZED = 99 +RC_NOCOMMAND = 98 +RC_BADCONFIG = 97 +RC_NOEXECFOUND = 96 + + +def _subprocess_setup(): + # Python installs a SIGPIPE handler by default. This is usually not what + # non-Python subprocesses expect. + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + +def _exit_error(execname, message, errorcode, log=True): + print("%s: %s" % (execname, message)) + if log: + logging.error(message) + sys.exit(errorcode) + + +def main(): + # Split arguments, require at least a command + execname = sys.argv.pop(0) + if len(sys.argv) < 2: + _exit_error(execname, "No command specified", RC_NOCOMMAND, log=False) + + configfile = sys.argv.pop(0) + userargs = sys.argv[:] + + # Add ../ to sys.path to allow running from branch + possible_topdir = os.path.normpath(os.path.join(os.path.abspath(execname), + os.pardir, os.pardir)) + if os.path.exists(os.path.join(possible_topdir, "sm_api", "__init__.py")): + sys.path.insert(0, possible_topdir) + + from sm_api.openstack.common.rootwrap import wrapper + + # Load configuration + try: + rawconfig = ConfigParser.RawConfigParser() + rawconfig.read(configfile) + config = wrapper.RootwrapConfig(rawconfig) + except ValueError as exc: + msg = "Incorrect value in %s: %s" % (configfile, exc.message) + _exit_error(execname, msg, RC_BADCONFIG, log=False) + except ConfigParser.Error: + _exit_error(execname, "Incorrect configuration file: %s" % configfile, + RC_BADCONFIG, log=False) + + if config.use_syslog: + wrapper.setup_syslog(execname, + config.syslog_log_facility, + config.syslog_log_level) + + # Execute command if it matches any of the loaded filters + filters = wrapper.load_filters(config.filters_path) + try: + filtermatch = wrapper.match_filter(filters, userargs, + exec_dirs=config.exec_dirs) + if filtermatch: + command = filtermatch.get_command(userargs, + exec_dirs=config.exec_dirs) + if config.use_syslog: + logging.info("(%s > %s) Executing %s (filter match = %s)" % ( + os.getlogin(), pwd.getpwuid(os.getuid())[0], + command, filtermatch.name)) + + obj = subprocess.Popen(command, + stdin=sys.stdin, + stdout=sys.stdout, + stderr=sys.stderr, + preexec_fn=_subprocess_setup, + env=filtermatch.get_environment(userargs)) + obj.wait() + sys.exit(obj.returncode) + + except wrapper.FilterMatchNotExecutable as exc: + msg = ("Executable not found: %s (filter match = %s)" + % (exc.match.exec_path, exc.match.name)) + _exit_error(execname, msg, RC_NOEXECFOUND, log=config.use_syslog) + + except wrapper.NoFilterMatched: + msg = ("Unauthorized command: %s (no filter matched)" + % ' '.join(userargs)) + _exit_error(execname, msg, RC_UNAUTHORIZED, log=config.use_syslog) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/filters.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/filters.py new file mode 100644 index 00000000..4db09cdc --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/filters.py @@ -0,0 +1,232 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import os +import re + + +class CommandFilter(object): + """Command filter only checking that the 1st argument matches exec_path.""" + + def __init__(self, exec_path, run_as, *args): + self.name = '' + self.exec_path = exec_path + self.run_as = run_as + self.args = args + self.real_exec = None + + def get_exec(self, exec_dirs=[]): + """Returns existing executable, or empty string if none found.""" + if self.real_exec is not None: + return self.real_exec + self.real_exec = "" + if self.exec_path.startswith('/'): + if os.access(self.exec_path, os.X_OK): + self.real_exec = self.exec_path + else: + for binary_path in exec_dirs: + expanded_path = os.path.join(binary_path, self.exec_path) + if os.access(expanded_path, os.X_OK): + self.real_exec = expanded_path + break + return self.real_exec + + def match(self, userargs): + """Only check that the first argument (command) matches exec_path.""" + return os.path.basename(self.exec_path) == userargs[0] + + def get_command(self, userargs, exec_dirs=[]): + """Returns command to execute (with sudo -u if run_as != root).""" + to_exec = self.get_exec(exec_dirs=exec_dirs) or self.exec_path + if (self.run_as != 'root'): + # Used to run commands at lesser privileges + return ['sudo', '-u', self.run_as, to_exec] + userargs[1:] + return [to_exec] + userargs[1:] + + def get_environment(self, userargs): + """Returns specific environment to set, None if none.""" + return None + + +class RegExpFilter(CommandFilter): + """Command filter doing regexp matching for every argument.""" + + def match(self, userargs): + # Early skip if command or number of args don't match + if (len(self.args) != len(userargs)): + # DENY: argument numbers don't match + return False + # Compare each arg (anchoring pattern explicitly at end of string) + for (pattern, arg) in zip(self.args, userargs): + try: + if not re.match(pattern + '$', arg): + break + except re.error: + # DENY: Badly-formed filter + return False + else: + # ALLOW: All arguments matched + return True + + # DENY: Some arguments did not match + return False + + +class PathFilter(CommandFilter): + """Command filter checking that path arguments are within given dirs + + One can specify the following constraints for command arguments: + 1) pass - pass an argument as is to the resulting command + 2) some_str - check if an argument is equal to the given string + 3) abs path - check if a path argument is within the given base dir + + A typical rootwrapper filter entry looks like this: + # cmdname: filter name, raw command, user, arg_i_constraint [, ...] + chown: PathFilter, /bin/chown, root, nova, /var/lib/images + + """ + + def match(self, userargs): + command, arguments = userargs[0], userargs[1:] + + equal_args_num = len(self.args) == len(arguments) + exec_is_valid = super(PathFilter, self).match(userargs) + args_equal_or_pass = all( + arg == 'pass' or arg == value + for arg, value in zip(self.args, arguments) + if not os.path.isabs(arg) # arguments not specifying abs paths + ) + paths_are_within_base_dirs = all( + os.path.commonprefix([arg, os.path.realpath(value)]) == arg + for arg, value in zip(self.args, arguments) + if os.path.isabs(arg) # arguments specifying abs paths + ) + + return (equal_args_num and + exec_is_valid and + args_equal_or_pass and + paths_are_within_base_dirs) + + def get_command(self, userargs, exec_dirs=[]): + command, arguments = userargs[0], userargs[1:] + + # convert path values to canonical ones; copy other args as is + args = [os.path.realpath(value) if os.path.isabs(arg) else value + for arg, value in zip(self.args, arguments)] + + return super(PathFilter, self).get_command([command] + args, + exec_dirs) + + +class DnsmasqFilter(CommandFilter): + """Specific filter for the dnsmasq call (which includes env).""" + + CONFIG_FILE_ARG = 'CONFIG_FILE' + + def match(self, userargs): + if (userargs[0] == 'env' and + userargs[1].startswith(self.CONFIG_FILE_ARG) and + userargs[2].startswith('NETWORK_ID=') and + userargs[3] == 'dnsmasq'): + return True + return False + + def get_command(self, userargs, exec_dirs=[]): + to_exec = self.get_exec(exec_dirs=exec_dirs) or self.exec_path + dnsmasq_pos = userargs.index('dnsmasq') + return [to_exec] + userargs[dnsmasq_pos + 1:] + + def get_environment(self, userargs): + env = os.environ.copy() + env[self.CONFIG_FILE_ARG] = userargs[1].split('=')[-1] + env['NETWORK_ID'] = userargs[2].split('=')[-1] + return env + + +class DeprecatedDnsmasqFilter(DnsmasqFilter): + """Variant of dnsmasq filter to support old-style FLAGFILE.""" + CONFIG_FILE_ARG = 'FLAGFILE' + + +class KillFilter(CommandFilter): + """Specific filter for the kill calls. + 1st argument is the user to run /bin/kill under + 2nd argument is the location of the affected executable + Subsequent arguments list the accepted signals (if any) + + This filter relies on /proc to accurately determine affected + executable, so it will only work on procfs-capable systems (not OSX). + """ + + def __init__(self, *args): + super(KillFilter, self).__init__("/bin/kill", *args) + + def match(self, userargs): + if userargs[0] != "kill": + return False + args = list(userargs) + if len(args) == 3: + # A specific signal is requested + signal = args.pop(1) + if signal not in self.args[1:]: + # Requested signal not in accepted list + return False + else: + if len(args) != 2: + # Incorrect number of arguments + return False + if len(self.args) > 1: + # No signal requested, but filter requires specific signal + return False + try: + command = os.readlink("/proc/%d/exe" % int(args[1])) + # NOTE(yufang521247): /proc/PID/exe may have '\0' on the + # end, because python doen't stop at '\0' when read the + # target path. + command = command.split('\0')[0] + # NOTE(dprince): /proc/PID/exe may have ' (deleted)' on + # the end if an executable is updated or deleted + if command.endswith(" (deleted)"): + command = command[:command.rindex(" ")] + if command != self.args[0]: + # Affected executable does not match + return False + except (ValueError, OSError): + # Incorrect PID + return False + return True + + +class ReadFileFilter(CommandFilter): + """Specific filter for the utils.read_file_as_root call.""" + + def __init__(self, file_path, *args): + self.file_path = file_path + super(ReadFileFilter, self).__init__("/bin/cat", "root", *args) + + def match(self, userargs): + if userargs[0] != 'cat': + return False + if userargs[1] != self.file_path: + return False + if len(userargs) != 2: + return False + return True diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/wrapper.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/wrapper.py new file mode 100644 index 00000000..2c807431 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rootwrap/wrapper.py @@ -0,0 +1,153 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + + +import ConfigParser +import logging +import logging.handlers +import os +import string + +from sm_api.openstack.common.rootwrap import filters + + +class NoFilterMatched(Exception): + """This exception is raised when no filter matched.""" + pass + + +class FilterMatchNotExecutable(Exception): + """ + This exception is raised when a filter matched but no executable was + found. + """ + def __init__(self, match=None, **kwargs): + self.match = match + + +class RootwrapConfig(object): + + def __init__(self, config): + # filters_path + self.filters_path = config.get("DEFAULT", "filters_path").split(",") + + # exec_dirs + if config.has_option("DEFAULT", "exec_dirs"): + self.exec_dirs = config.get("DEFAULT", "exec_dirs").split(",") + else: + # Use system PATH if exec_dirs is not specified + self.exec_dirs = os.environ["PATH"].split(':') + + # syslog_log_facility + if config.has_option("DEFAULT", "syslog_log_facility"): + v = config.get("DEFAULT", "syslog_log_facility") + facility_names = logging.handlers.SysLogHandler.facility_names + self.syslog_log_facility = getattr(logging.handlers.SysLogHandler, + v, None) + if self.syslog_log_facility is None and v in facility_names: + self.syslog_log_facility = facility_names.get(v) + if self.syslog_log_facility is None: + raise ValueError('Unexpected syslog_log_facility: %s' % v) + else: + default_facility = logging.handlers.SysLogHandler.LOG_SYSLOG + self.syslog_log_facility = default_facility + + # syslog_log_level + if config.has_option("DEFAULT", "syslog_log_level"): + v = config.get("DEFAULT", "syslog_log_level") + self.syslog_log_level = logging.getLevelName(v.upper()) + if (self.syslog_log_level == "Level %s" % v.upper()): + raise ValueError('Unexepected syslog_log_level: %s' % v) + else: + self.syslog_log_level = logging.ERROR + + # use_syslog + if config.has_option("DEFAULT", "use_syslog"): + self.use_syslog = config.getboolean("DEFAULT", "use_syslog") + else: + self.use_syslog = False + + +def setup_syslog(execname, facility, level): + rootwrap_logger = logging.getLogger() + rootwrap_logger.setLevel(level) + handler = logging.handlers.SysLogHandler(address='/dev/log', + facility=facility) + handler.setFormatter(logging.Formatter( + os.path.basename(execname) + ': %(message)s')) + rootwrap_logger.addHandler(handler) + + +def build_filter(class_name, *args): + """Returns a filter object of class class_name.""" + if not hasattr(filters, class_name): + logging.warning("Skipping unknown filter class (%s) specified " + "in filter definitions" % class_name) + return None + filterclass = getattr(filters, class_name) + return filterclass(*args) + + +def load_filters(filters_path): + """Load filters from a list of directories.""" + filterlist = [] + for filterdir in filters_path: + if not os.path.isdir(filterdir): + continue + for filterfile in os.listdir(filterdir): + filterconfig = ConfigParser.RawConfigParser() + filterconfig.read(os.path.join(filterdir, filterfile)) + for (name, value) in filterconfig.items("Filters"): + filterdefinition = [string.strip(s) for s in value.split(',')] + newfilter = build_filter(*filterdefinition) + if newfilter is None: + continue + newfilter.name = name + filterlist.append(newfilter) + return filterlist + + +def match_filter(filter_list, userargs, exec_dirs=[]): + """ + Checks user command and arguments through command filters and + returns the first matching filter. + Raises NoFilterMatched if no filter matched. + Raises FilterMatchNotExecutable if no executable was found for the + best filter match. + """ + first_not_executable_filter = None + + for f in filter_list: + if f.match(userargs): + # Try other filters if executable is absent + if not f.get_exec(exec_dirs=exec_dirs): + if not first_not_executable_filter: + first_not_executable_filter = f + continue + # Otherwise return matching filter for execution + return f + + if first_not_executable_filter: + # A filter matched, but no executable was found for it + raise FilterMatchNotExecutable(match=first_not_executable_filter) + + # No filter matched + raise NoFilterMatched() diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/__init__.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/__init__.py new file mode 100644 index 00000000..0ffc0716 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/__init__.py @@ -0,0 +1,311 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# Copyright 2011 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +A remote procedure call (rpc) abstraction. + +For some wrappers that add message versioning to rpc, see: + rpc.dispatcher + rpc.proxy +""" + +import inspect + +from oslo_config import cfg + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import importutils +from sm_api.openstack.common import local +from sm_api.openstack.common import log as logging + + +LOG = logging.getLogger(__name__) + + +rpc_opts = [ + cfg.StrOpt('rpc_backend', + default='%s.impl_kombu' % __package__, + help="The messaging module to use, defaults to kombu."), + cfg.IntOpt('rpc_thread_pool_size', + default=64, + help='Size of RPC thread pool'), + cfg.IntOpt('rpc_conn_pool_size', + default=30, + help='Size of RPC connection pool'), + cfg.IntOpt('rpc_response_timeout', + default=60, + help='Seconds to wait for a response from call or multicall'), + cfg.IntOpt('rpc_cast_timeout', + default=30, + help='Seconds to wait before a cast expires (TTL). ' + 'Only supported by impl_zmq.'), + cfg.ListOpt('allowed_rpc_exception_modules', + default=['sm_api.openstack.common.exception', + 'nova.exception', + 'cinder.exception', + 'exceptions', + ], + help='Modules of exceptions that are permitted to be recreated' + 'upon receiving exception data from an rpc call.'), + cfg.BoolOpt('fake_rabbit', + default=False, + help='If passed, use a fake RabbitMQ provider'), + cfg.StrOpt('control_exchange', + default='openstack', + help='AMQP exchange to connect to if using RabbitMQ or Qpid'), +] + +CONF = cfg.CONF +CONF.register_opts(rpc_opts) + + +def set_defaults(control_exchange): + cfg.set_defaults(rpc_opts, + control_exchange=control_exchange) + + +def create_connection(new=True): + """Create a connection to the message bus used for rpc. + + For some example usage of creating a connection and some consumers on that + connection, see nova.service. + + :param new: Whether or not to create a new connection. A new connection + will be created by default. If new is False, the + implementation is free to return an existing connection from a + pool. + + :returns: An instance of openstack.common.rpc.common.Connection + """ + return _get_impl().create_connection(CONF, new=new) + + +def _check_for_lock(): + if not CONF.debug: + return None + + if ((hasattr(local.strong_store, 'locks_held') + and local.strong_store.locks_held)): + stack = ' :: '.join([frame[3] for frame in inspect.stack()]) + LOG.warn(_('A RPC is being made while holding a lock. The locks ' + 'currently held are %(locks)s. This is probably a bug. ' + 'Please report it. Include the following: [%(stack)s].'), + {'locks': local.strong_store.locks_held, + 'stack': stack}) + return True + + return False + + +def call(context, topic, msg, timeout=None, check_for_lock=False): + """Invoke a remote method that returns something. + + :param context: Information that identifies the user that has made this + request. + :param topic: The topic to send the rpc message to. This correlates to the + topic argument of + openstack.common.rpc.common.Connection.create_consumer() + and only applies when the consumer was created with + fanout=False. + :param msg: This is a dict in the form { "method" : "method_to_invoke", + "args" : dict_of_kwargs } + :param timeout: int, number of seconds to use for a response timeout. + If set, this overrides the rpc_response_timeout option. + :param check_for_lock: if True, a warning is emitted if a RPC call is made + with a lock held. + + :returns: A dict from the remote method. + + :raises: openstack.common.rpc.common.Timeout if a complete response + is not received before the timeout is reached. + """ + if check_for_lock: + _check_for_lock() + return _get_impl().call(CONF, context, topic, msg, timeout) + + +def cast(context, topic, msg): + """Invoke a remote method that does not return anything. + + :param context: Information that identifies the user that has made this + request. + :param topic: The topic to send the rpc message to. This correlates to the + topic argument of + openstack.common.rpc.common.Connection.create_consumer() + and only applies when the consumer was created with + fanout=False. + :param msg: This is a dict in the form { "method" : "method_to_invoke", + "args" : dict_of_kwargs } + + :returns: None + """ + return _get_impl().cast(CONF, context, topic, msg) + + +def fanout_cast(context, topic, msg): + """Broadcast a remote method invocation with no return. + + This method will get invoked on all consumers that were set up with this + topic name and fanout=True. + + :param context: Information that identifies the user that has made this + request. + :param topic: The topic to send the rpc message to. This correlates to the + topic argument of + openstack.common.rpc.common.Connection.create_consumer() + and only applies when the consumer was created with + fanout=True. + :param msg: This is a dict in the form { "method" : "method_to_invoke", + "args" : dict_of_kwargs } + + :returns: None + """ + return _get_impl().fanout_cast(CONF, context, topic, msg) + + +def multicall(context, topic, msg, timeout=None, check_for_lock=False): + """Invoke a remote method and get back an iterator. + + In this case, the remote method will be returning multiple values in + separate messages, so the return values can be processed as the come in via + an iterator. + + :param context: Information that identifies the user that has made this + request. + :param topic: The topic to send the rpc message to. This correlates to the + topic argument of + openstack.common.rpc.common.Connection.create_consumer() + and only applies when the consumer was created with + fanout=False. + :param msg: This is a dict in the form { "method" : "method_to_invoke", + "args" : dict_of_kwargs } + :param timeout: int, number of seconds to use for a response timeout. + If set, this overrides the rpc_response_timeout option. + :param check_for_lock: if True, a warning is emitted if a RPC call is made + with a lock held. + + :returns: An iterator. The iterator will yield a tuple (N, X) where N is + an index that starts at 0 and increases by one for each value + returned and X is the Nth value that was returned by the remote + method. + + :raises: openstack.common.rpc.common.Timeout if a complete response + is not received before the timeout is reached. + """ + if check_for_lock: + _check_for_lock() + return _get_impl().multicall(CONF, context, topic, msg, timeout) + + +def notify(context, topic, msg, envelope=False): + """Send notification event. + + :param context: Information that identifies the user that has made this + request. + :param topic: The topic to send the notification to. + :param msg: This is a dict of content of event. + :param envelope: Set to True to enable message envelope for notifications. + + :returns: None + """ + return _get_impl().notify(cfg.CONF, context, topic, msg, envelope) + + +def cleanup(): + """Clean up resoruces in use by implementation. + + Clean up any resources that have been allocated by the RPC implementation. + This is typically open connections to a messaging service. This function + would get called before an application using this API exits to allow + connections to get torn down cleanly. + + :returns: None + """ + return _get_impl().cleanup() + + +def cast_to_server(context, server_params, topic, msg): + """Invoke a remote method that does not return anything. + + :param context: Information that identifies the user that has made this + request. + :param server_params: Connection information + :param topic: The topic to send the notification to. + :param msg: This is a dict in the form { "method" : "method_to_invoke", + "args" : dict_of_kwargs } + + :returns: None + """ + return _get_impl().cast_to_server(CONF, context, server_params, topic, + msg) + + +def fanout_cast_to_server(context, server_params, topic, msg): + """Broadcast to a remote method invocation with no return. + + :param context: Information that identifies the user that has made this + request. + :param server_params: Connection information + :param topic: The topic to send the notification to. + :param msg: This is a dict in the form { "method" : "method_to_invoke", + "args" : dict_of_kwargs } + + :returns: None + """ + return _get_impl().fanout_cast_to_server(CONF, context, server_params, + topic, msg) + + +def queue_get_for(context, topic, host): + """Get a queue name for a given topic + host. + + This function only works if this naming convention is followed on the + consumer side, as well. For example, in nova, every instance of the + nova-foo service calls create_consumer() for two topics: + + foo + foo. + + Messages sent to the 'foo' topic are distributed to exactly one instance of + the nova-foo service. The services are chosen in a round-robin fashion. + Messages sent to the 'foo.' topic are sent to the nova-foo service on + . + """ + return '%s.%s' % (topic, host) if host else topic + + +_RPCIMPL = None + + +def _get_impl(): + """Delay import of rpc_backend until configuration is loaded.""" + global _RPCIMPL + if _RPCIMPL is None: + try: + _RPCIMPL = importutils.import_module(CONF.rpc_backend) + except ImportError: + # For backwards compatibility with older nova config. + impl = CONF.rpc_backend.replace('nova.rpc', + 'nova.openstack.common.rpc') + _RPCIMPL = importutils.import_module(impl) + return _RPCIMPL diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/amqp.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/amqp.py new file mode 100644 index 00000000..f928c3d1 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/amqp.py @@ -0,0 +1,682 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# Copyright 2011 - 2012, Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Shared code between AMQP based openstack.common.rpc implementations. + +The code in this module is shared between the rpc implemenations based on AMQP. +Specifically, this includes impl_kombu and impl_qpid. impl_carrot also uses +AMQP, but is deprecated and predates this code. +""" + +import collections +import inspect +import sys +import uuid + +from eventlet import greenpool +from eventlet import pools +from eventlet import queue +from eventlet import semaphore +# TODO(pekowsk): Remove import cfg and below comment in Havana. +# This import should no longer be needed when the amqp_rpc_single_reply_queue +# option is removed. +from oslo_config import cfg + +from sm_api.openstack.common import excutils +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import local +from sm_api.openstack.common import log as logging +from sm_api.openstack.common.rpc import common as rpc_common + + +# TODO(pekowski): Remove this option in Havana. +amqp_opts = [ + cfg.BoolOpt('amqp_rpc_single_reply_queue', + default=False, + help='Enable a fast single reply queue if using AMQP based ' + 'RPC like RabbitMQ or Qpid.'), +] + +cfg.CONF.register_opts(amqp_opts) + +UNIQUE_ID = '_unique_id' +LOG = logging.getLogger(__name__) + + +class Pool(pools.Pool): + """Class that implements a Pool of Connections.""" + def __init__(self, conf, connection_cls, *args, **kwargs): + self.connection_cls = connection_cls + self.conf = conf + kwargs.setdefault("max_size", self.conf.rpc_conn_pool_size) + kwargs.setdefault("order_as_stack", True) + super(Pool, self).__init__(*args, **kwargs) + self.reply_proxy = None + + # TODO(comstud): Timeout connections not used in a while + def create(self): + LOG.debug(_('Pool creating new connection')) + return self.connection_cls(self.conf) + + def empty(self): + while self.free_items: + self.get().close() + # Force a new connection pool to be created. + # Note that this was added due to failing unit test cases. The issue + # is the above "while loop" gets all the cached connections from the + # pool and closes them, but never returns them to the pool, a pool + # leak. The unit tests hang waiting for an item to be returned to the + # pool. The unit tests get here via the teatDown() method. In the run + # time code, it gets here via cleanup() and only appears in service.py + # just before doing a sys.exit(), so cleanup() only happens once and + # the leakage is not a problem. + self.connection_cls.pool = None + + +_pool_create_sem = semaphore.Semaphore() + + +def get_connection_pool(conf, connection_cls): + with _pool_create_sem: + # Make sure only one thread tries to create the connection pool. + if not connection_cls.pool: + connection_cls.pool = Pool(conf, connection_cls) + return connection_cls.pool + + +class ConnectionContext(rpc_common.Connection): + """The class that is actually returned to the caller of + create_connection(). This is essentially a wrapper around + Connection that supports 'with'. It can also return a new + Connection, or one from a pool. The function will also catch + when an instance of this class is to be deleted. With that + we can return Connections to the pool on exceptions and so + forth without making the caller be responsible for catching + them. If possible the function makes sure to return a + connection to the pool. + """ + + def __init__(self, conf, connection_pool, pooled=True, server_params=None): + """Create a new connection, or get one from the pool""" + self.connection = None + self.conf = conf + self.connection_pool = connection_pool + if pooled: + self.connection = connection_pool.get() + else: + self.connection = connection_pool.connection_cls( + conf, + server_params=server_params) + self.pooled = pooled + + def __enter__(self): + """When with ConnectionContext() is used, return self""" + return self + + def _done(self): + """If the connection came from a pool, clean it up and put it back. + If it did not come from a pool, close it. + """ + if self.connection: + if self.pooled: + # Reset the connection so it's ready for the next caller + # to grab from the pool + self.connection.reset() + self.connection_pool.put(self.connection) + else: + try: + self.connection.close() + except Exception: + pass + self.connection = None + + def __exit__(self, exc_type, exc_value, tb): + """End of 'with' statement. We're done here.""" + self._done() + + def __del__(self): + """Caller is done with this connection. Make sure we cleaned up.""" + self._done() + + def close(self): + """Caller is done with this connection.""" + self._done() + + def create_consumer(self, topic, proxy, fanout=False): + self.connection.create_consumer(topic, proxy, fanout) + + def create_worker(self, topic, proxy, pool_name): + self.connection.create_worker(topic, proxy, pool_name) + + def join_consumer_pool(self, callback, pool_name, topic, exchange_name): + self.connection.join_consumer_pool(callback, + pool_name, + topic, + exchange_name) + + def consume_in_thread(self): + self.connection.consume_in_thread() + + def __getattr__(self, key): + """Proxy all other calls to the Connection instance""" + if self.connection: + return getattr(self.connection, key) + else: + raise rpc_common.InvalidRPCConnectionReuse() + + +class ReplyProxy(ConnectionContext): + """ Connection class for RPC replies / callbacks """ + def __init__(self, conf, connection_pool): + self._call_waiters = {} + self._num_call_waiters = 0 + self._num_call_waiters_wrn_threshhold = 10 + self._reply_q = 'reply_' + uuid.uuid4().hex + super(ReplyProxy, self).__init__(conf, connection_pool, pooled=False) + self.declare_direct_consumer(self._reply_q, self._process_data) + self.consume_in_thread() + + def _process_data(self, message_data): + msg_id = message_data.pop('_msg_id', None) + waiter = self._call_waiters.get(msg_id) + if not waiter: + LOG.warn(_('no calling threads waiting for msg_id : %(msg_id)s' + ', message : %(data)s'), {'msg_id': msg_id, + 'data': message_data}) + else: + waiter.put(message_data) + + def add_call_waiter(self, waiter, msg_id): + self._num_call_waiters += 1 + if self._num_call_waiters > self._num_call_waiters_wrn_threshhold: + LOG.warn(_('Number of call waiters is greater than warning ' + 'threshhold: %d. There could be a MulticallProxyWaiter ' + 'leak.') % self._num_call_waiters_wrn_threshhold) + self._num_call_waiters_wrn_threshhold *= 2 + self._call_waiters[msg_id] = waiter + + def del_call_waiter(self, msg_id): + self._num_call_waiters -= 1 + del self._call_waiters[msg_id] + + def get_reply_q(self): + return self._reply_q + + +def msg_reply(conf, msg_id, reply_q, connection_pool, reply=None, + failure=None, ending=False, log_failure=True): + """Sends a reply or an error on the channel signified by msg_id. + + Failure should be a sys.exc_info() tuple. + + """ + with ConnectionContext(conf, connection_pool) as conn: + if failure: + failure = rpc_common.serialize_remote_exception(failure, + log_failure) + + try: + msg = {'result': reply, 'failure': failure} + except TypeError: + msg = {'result': dict((k, repr(v)) + for k, v in reply.__dict__.iteritems()), + 'failure': failure} + if ending: + msg['ending'] = True + _add_unique_id(msg) + # If a reply_q exists, add the msg_id to the reply and pass the + # reply_q to direct_send() to use it as the response queue. + # Otherwise use the msg_id for backward compatibilty. + if reply_q: + msg['_msg_id'] = msg_id + conn.direct_send(reply_q, rpc_common.serialize_msg(msg)) + else: + conn.direct_send(msg_id, rpc_common.serialize_msg(msg)) + + +class RpcContext(rpc_common.CommonRpcContext): + """Context that supports replying to a rpc.call""" + def __init__(self, **kwargs): + self.msg_id = kwargs.pop('msg_id', None) + self.reply_q = kwargs.pop('reply_q', None) + self.conf = kwargs.pop('conf') + super(RpcContext, self).__init__(**kwargs) + + def deepcopy(self): + values = self.to_dict() + values['conf'] = self.conf + values['msg_id'] = self.msg_id + values['reply_q'] = self.reply_q + return self.__class__(**values) + + def reply(self, reply=None, failure=None, ending=False, + connection_pool=None, log_failure=True): + if self.msg_id: + msg_reply(self.conf, self.msg_id, self.reply_q, connection_pool, + reply, failure, ending, log_failure) + if ending: + self.msg_id = None + + +def unpack_context(conf, msg): + """Unpack context from msg.""" + context_dict = {} + for key in list(msg.keys()): + # NOTE(vish): Some versions of python don't like unicode keys + # in kwargs. + key = str(key) + if key.startswith('_context_'): + value = msg.pop(key) + context_dict[key[9:]] = value + context_dict['msg_id'] = msg.pop('_msg_id', None) + context_dict['reply_q'] = msg.pop('_reply_q', None) + context_dict['conf'] = conf + ctx = RpcContext.from_dict(context_dict) + rpc_common._safe_log(LOG.debug, _('unpacked context: %s'), ctx.to_dict()) + return ctx + + +def pack_context(msg, context): + """Pack context into msg. + + Values for message keys need to be less than 255 chars, so we pull + context out into a bunch of separate keys. If we want to support + more arguments in rabbit messages, we may want to do the same + for args at some point. + + """ + context_d = dict([('_context_%s' % key, value) + for (key, value) in context.to_dict().iteritems()]) + msg.update(context_d) + + +class _MsgIdCache(object): + """This class checks any duplicate messages.""" + + # NOTE: This value is considered can be a configuration item, but + # it is not necessary to change its value in most cases, + # so let this value as static for now. + DUP_MSG_CHECK_SIZE = 16 + + def __init__(self, **kwargs): + self.prev_msgids = collections.deque([], + maxlen=self.DUP_MSG_CHECK_SIZE) + + def check_duplicate_message(self, message_data): + """AMQP consumers may read same message twice when exceptions occur + before ack is returned. This method prevents doing it. + """ + if UNIQUE_ID in message_data: + msg_id = message_data[UNIQUE_ID] + if msg_id not in self.prev_msgids: + self.prev_msgids.append(msg_id) + else: + raise rpc_common.DuplicateMessageError(msg_id=msg_id) + + +def _add_unique_id(msg): + """Add unique_id for checking duplicate messages.""" + unique_id = uuid.uuid4().hex + msg.update({UNIQUE_ID: unique_id}) + LOG.debug(_('UNIQUE_ID is %s.') % (unique_id)) + + +class _ThreadPoolWithWait(object): + """Base class for a delayed invocation manager used by + the Connection class to start up green threads + to handle incoming messages. + """ + + def __init__(self, conf, connection_pool): + self.pool = greenpool.GreenPool(conf.rpc_thread_pool_size) + self.connection_pool = connection_pool + self.conf = conf + + def wait(self): + """Wait for all callback threads to exit.""" + self.pool.waitall() + + +class CallbackWrapper(_ThreadPoolWithWait): + """Wraps a straight callback to allow it to be invoked in a green + thread. + """ + + def __init__(self, conf, callback, connection_pool): + """ + :param conf: cfg.CONF instance + :param callback: a callable (probably a function) + :param connection_pool: connection pool as returned by + get_connection_pool() + """ + super(CallbackWrapper, self).__init__( + conf=conf, + connection_pool=connection_pool, + ) + self.callback = callback + + def __call__(self, message_data): + self.pool.spawn_n(self.callback, message_data) + + +class ProxyCallback(_ThreadPoolWithWait): + """Calls methods on a proxy object based on method and args.""" + + def __init__(self, conf, proxy, connection_pool): + super(ProxyCallback, self).__init__( + conf=conf, + connection_pool=connection_pool, + ) + self.proxy = proxy + self.msg_id_cache = _MsgIdCache() + + def __call__(self, message_data): + """Consumer callback to call a method on a proxy object. + + Parses the message for validity and fires off a thread to call the + proxy object method. + + Message data should be a dictionary with two keys: + method: string representing the method to call + args: dictionary of arg: value + + Example: {'method': 'echo', 'args': {'value': 42}} + + """ + # It is important to clear the context here, because at this point + # the previous context is stored in local.store.context + if hasattr(local.store, 'context'): + del local.store.context + rpc_common._safe_log(LOG.debug, _('received %s'), message_data) + self.msg_id_cache.check_duplicate_message(message_data) + ctxt = unpack_context(self.conf, message_data) + method = message_data.get('method') + args = message_data.get('args', {}) + version = message_data.get('version') + namespace = message_data.get('namespace') + if not method: + LOG.warn(_('no method for message: %s') % message_data) + ctxt.reply(_('No method for message: %s') % message_data, + connection_pool=self.connection_pool) + return + self.pool.spawn_n(self._process_data, ctxt, version, method, + namespace, args) + + def _process_data(self, ctxt, version, method, namespace, args): + """Process a message in a new thread. + + If the proxy object we have has a dispatch method + (see rpc.dispatcher.RpcDispatcher), pass it the version, + method, and args and let it dispatch as appropriate. If not, use + the old behavior of magically calling the specified method on the + proxy we have here. + """ + ctxt.update_store() + try: + rval = self.proxy.dispatch(ctxt, version, method, namespace, + **args) + # Check if the result was a generator + if inspect.isgenerator(rval): + for x in rval: + ctxt.reply(x, None, connection_pool=self.connection_pool) + else: + ctxt.reply(rval, None, connection_pool=self.connection_pool) + # This final None tells multicall that it is done. + ctxt.reply(ending=True, connection_pool=self.connection_pool) + except rpc_common.ClientException as e: + LOG.debug(_('Expected exception during message handling (%s)') % + e._exc_info[1]) + ctxt.reply(None, e._exc_info, + connection_pool=self.connection_pool, + log_failure=False) + except Exception: + # sys.exc_info() is deleted by LOG.exception(). + exc_info = sys.exc_info() + LOG.error(_('Exception during message handling'), + exc_info=exc_info) + ctxt.reply(None, exc_info, connection_pool=self.connection_pool) + + +class MulticallProxyWaiter(object): + def __init__(self, conf, msg_id, timeout, connection_pool): + self._msg_id = msg_id + self._timeout = timeout or conf.rpc_response_timeout + self._reply_proxy = connection_pool.reply_proxy + self._done = False + self._got_ending = False + self._conf = conf + self._dataqueue = queue.LightQueue() + # Add this caller to the reply proxy's call_waiters + self._reply_proxy.add_call_waiter(self, self._msg_id) + self.msg_id_cache = _MsgIdCache() + + def put(self, data): + self._dataqueue.put(data) + + def done(self): + if self._done: + return + self._done = True + # Remove this caller from reply proxy's call_waiters + self._reply_proxy.del_call_waiter(self._msg_id) + + def _process_data(self, data): + result = None + self.msg_id_cache.check_duplicate_message(data) + if data['failure']: + failure = data['failure'] + result = rpc_common.deserialize_remote_exception(self._conf, + failure) + elif data.get('ending', False): + self._got_ending = True + else: + result = data['result'] + return result + + def __iter__(self): + """Return a result until we get a reply with an 'ending" flag""" + if self._done: + raise StopIteration + while True: + try: + data = self._dataqueue.get(timeout=self._timeout) + result = self._process_data(data) + except queue.Empty: + self.done() + raise rpc_common.Timeout() + except Exception: + with excutils.save_and_reraise_exception(): + self.done() + if self._got_ending: + self.done() + raise StopIteration + if isinstance(result, Exception): + self.done() + raise result + yield result + + +#TODO(pekowski): Remove MulticallWaiter() in Havana. +class MulticallWaiter(object): + def __init__(self, conf, connection, timeout): + self._connection = connection + self._iterator = connection.iterconsume(timeout=timeout or + conf.rpc_response_timeout) + self._result = None + self._done = False + self._got_ending = False + self._conf = conf + self.msg_id_cache = _MsgIdCache() + + def done(self): + if self._done: + return + self._done = True + self._iterator.close() + self._iterator = None + self._connection.close() + + def __call__(self, data): + """The consume() callback will call this. Store the result.""" + self.msg_id_cache.check_duplicate_message(data) + if data['failure']: + failure = data['failure'] + self._result = rpc_common.deserialize_remote_exception(self._conf, + failure) + + elif data.get('ending', False): + self._got_ending = True + else: + self._result = data['result'] + + def __iter__(self): + """Return a result until we get a 'None' response from consumer""" + if self._done: + raise StopIteration + while True: + try: + self._iterator.next() + except Exception: + with excutils.save_and_reraise_exception(): + self.done() + if self._got_ending: + self.done() + raise StopIteration + result = self._result + if isinstance(result, Exception): + self.done() + raise result + yield result + + +def create_connection(conf, new, connection_pool): + """Create a connection""" + return ConnectionContext(conf, connection_pool, pooled=not new) + + +_reply_proxy_create_sem = semaphore.Semaphore() + + +def multicall(conf, context, topic, msg, timeout, connection_pool): + """Make a call that returns multiple times.""" + # TODO(pekowski): Remove all these comments in Havana. + # For amqp_rpc_single_reply_queue = False, + # Can't use 'with' for multicall, as it returns an iterator + # that will continue to use the connection. When it's done, + # connection.close() will get called which will put it back into + # the pool + # For amqp_rpc_single_reply_queue = True, + # The 'with' statement is mandatory for closing the connection + LOG.debug(_('Making synchronous call on %s ...'), topic) + msg_id = uuid.uuid4().hex + msg.update({'_msg_id': msg_id}) + LOG.debug(_('MSG_ID is %s') % (msg_id)) + _add_unique_id(msg) + pack_context(msg, context) + + # TODO(pekowski): Remove this flag and the code under the if clause + # in Havana. + if not conf.amqp_rpc_single_reply_queue: + conn = ConnectionContext(conf, connection_pool) + wait_msg = MulticallWaiter(conf, conn, timeout) + conn.declare_direct_consumer(msg_id, wait_msg) + conn.topic_send(topic, rpc_common.serialize_msg(msg), timeout) + else: + with _reply_proxy_create_sem: + if not connection_pool.reply_proxy: + connection_pool.reply_proxy = ReplyProxy(conf, connection_pool) + msg.update({'_reply_q': connection_pool.reply_proxy.get_reply_q()}) + wait_msg = MulticallProxyWaiter(conf, msg_id, timeout, connection_pool) + with ConnectionContext(conf, connection_pool) as conn: + conn.topic_send(topic, rpc_common.serialize_msg(msg), timeout) + return wait_msg + + +def call(conf, context, topic, msg, timeout, connection_pool): + """Sends a message on a topic and wait for a response.""" + rv = multicall(conf, context, topic, msg, timeout, connection_pool) + # NOTE(vish): return the last result from the multicall + rv = list(rv) + if not rv: + return + return rv[-1] + + +def cast(conf, context, topic, msg, connection_pool): + """Sends a message on a topic without waiting for a response.""" + LOG.debug(_('Making asynchronous cast on %s...'), topic) + _add_unique_id(msg) + pack_context(msg, context) + with ConnectionContext(conf, connection_pool) as conn: + conn.topic_send(topic, rpc_common.serialize_msg(msg)) + + +def fanout_cast(conf, context, topic, msg, connection_pool): + """Sends a message on a fanout exchange without waiting for a response.""" + LOG.debug(_('Making asynchronous fanout cast...')) + _add_unique_id(msg) + pack_context(msg, context) + with ConnectionContext(conf, connection_pool) as conn: + conn.fanout_send(topic, rpc_common.serialize_msg(msg)) + + +def cast_to_server(conf, context, server_params, topic, msg, connection_pool): + """Sends a message on a topic to a specific server.""" + _add_unique_id(msg) + pack_context(msg, context) + with ConnectionContext(conf, connection_pool, pooled=False, + server_params=server_params) as conn: + conn.topic_send(topic, rpc_common.serialize_msg(msg)) + + +def fanout_cast_to_server(conf, context, server_params, topic, msg, + connection_pool): + """Sends a message on a fanout exchange to a specific server.""" + _add_unique_id(msg) + pack_context(msg, context) + with ConnectionContext(conf, connection_pool, pooled=False, + server_params=server_params) as conn: + conn.fanout_send(topic, rpc_common.serialize_msg(msg)) + + +def notify(conf, context, topic, msg, connection_pool, envelope): + """Sends a notification event on a topic.""" + LOG.debug(_('Sending %(event_type)s on %(topic)s'), + dict(event_type=msg.get('event_type'), + topic=topic)) + _add_unique_id(msg) + pack_context(msg, context) + with ConnectionContext(conf, connection_pool) as conn: + if envelope: + msg = rpc_common.serialize_msg(msg) + conn.notify_send(topic, msg) + + +def cleanup(connection_pool): + if connection_pool: + connection_pool.empty() + + +def get_control_exchange(conf): + return conf.control_exchange diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/common.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/common.py new file mode 100644 index 00000000..697c5e90 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/common.py @@ -0,0 +1,518 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# Copyright 2011 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import copy +import sys +import traceback + +from oslo_config import cfg +import six + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import importutils +from sm_api.openstack.common import jsonutils +from sm_api.openstack.common import local +from sm_api.openstack.common import log as logging + + +CONF = cfg.CONF +LOG = logging.getLogger(__name__) + + +'''RPC Envelope Version. + +This version number applies to the top level structure of messages sent out. +It does *not* apply to the message payload, which must be versioned +independently. For example, when using rpc APIs, a version number is applied +for changes to the API being exposed over rpc. This version number is handled +in the rpc proxy and dispatcher modules. + +This version number applies to the message envelope that is used in the +serialization done inside the rpc layer. See serialize_msg() and +deserialize_msg(). + +The current message format (version 2.0) is very simple. It is: + + { + 'oslo.version': , + 'oslo.message': + } + +Message format version '1.0' is just considered to be the messages we sent +without a message envelope. + +So, the current message envelope just includes the envelope version. It may +eventually contain additional information, such as a signature for the message +payload. + +We will JSON encode the application message payload. The message envelope, +which includes the JSON encoded application message body, will be passed down +to the messaging libraries as a dict. +''' +_RPC_ENVELOPE_VERSION = '2.0' + +_VERSION_KEY = 'oslo.version' +_MESSAGE_KEY = 'oslo.message' + + +class RPCException(Exception): + message = _("An unknown RPC related exception occurred.") + + def __init__(self, message=None, **kwargs): + self.kwargs = kwargs + + if not message: + try: + message = self.message % kwargs + + except Exception: + # kwargs doesn't match a variable in the message + # log the issue and the kwargs + LOG.exception(_('Exception in string format operation')) + for name, value in kwargs.iteritems(): + LOG.error("%s: %s" % (name, value)) + # at least get the core message out if something happened + message = self.message + + super(RPCException, self).__init__(message) + + +class RemoteError(RPCException): + """Signifies that a remote class has raised an exception. + + Contains a string representation of the type of the original exception, + the value of the original exception, and the traceback. These are + sent to the parent as a joined string so printing the exception + contains all of the relevant info. + + """ + message = _("Remote error: %(exc_type)s %(value)s\n%(traceback)s.") + + def __init__(self, exc_type=None, value=None, traceback=None): + self.exc_type = exc_type + self.value = value + self.traceback = traceback + super(RemoteError, self).__init__(exc_type=exc_type, + value=value, + traceback=traceback) + + +class Timeout(RPCException): + """Signifies that a timeout has occurred. + + This exception is raised if the rpc_response_timeout is reached while + waiting for a response from the remote side. + """ + message = _('Timeout while waiting on RPC response - ' + 'topic: "%(topic)s", RPC method: "%(method)s" ' + 'info: "%(info)s"') + + def __init__(self, info=None, topic=None, method=None): + """ + :param info: Extra info to convey to the user + :param topic: The topic that the rpc call was sent to + :param rpc_method_name: The name of the rpc method being + called + """ + self.info = info + self.topic = topic + self.method = method + super(Timeout, self).__init__( + None, + info=info or _(''), + topic=topic or _(''), + method=method or _('')) + + +class DuplicateMessageError(RPCException): + message = _("Found duplicate message(%(msg_id)s). Skipping it.") + + +class InvalidRPCConnectionReuse(RPCException): + message = _("Invalid reuse of an RPC connection.") + + +class UnsupportedRpcVersion(RPCException): + message = _("Specified RPC version, %(version)s, not supported by " + "this endpoint.") + + +class UnsupportedRpcEnvelopeVersion(RPCException): + message = _("Specified RPC envelope version, %(version)s, " + "not supported by this endpoint.") + + +class RpcVersionCapError(RPCException): + message = _("Specified RPC version cap, %(version_cap)s, is too low") + + +class Connection(object): + """A connection, returned by rpc.create_connection(). + + This class represents a connection to the message bus used for rpc. + An instance of this class should never be created by users of the rpc API. + Use rpc.create_connection() instead. + """ + def close(self): + """Close the connection. + + This method must be called when the connection will no longer be used. + It will ensure that any resources associated with the connection, such + as a network connection, and cleaned up. + """ + raise NotImplementedError() + + def create_consumer(self, topic, proxy, fanout=False): + """Create a consumer on this connection. + + A consumer is associated with a message queue on the backend message + bus. The consumer will read messages from the queue, unpack them, and + dispatch them to the proxy object. The contents of the message pulled + off of the queue will determine which method gets called on the proxy + object. + + :param topic: This is a name associated with what to consume from. + Multiple instances of a service may consume from the same + topic. For example, all instances of nova-compute consume + from a queue called "compute". In that case, the + messages will get distributed amongst the consumers in a + round-robin fashion if fanout=False. If fanout=True, + every consumer associated with this topic will get a + copy of every message. + :param proxy: The object that will handle all incoming messages. + :param fanout: Whether or not this is a fanout topic. See the + documentation for the topic parameter for some + additional comments on this. + """ + raise NotImplementedError() + + def create_worker(self, topic, proxy, pool_name): + """Create a worker on this connection. + + A worker is like a regular consumer of messages directed to a + topic, except that it is part of a set of such consumers (the + "pool") which may run in parallel. Every pool of workers will + receive a given message, but only one worker in the pool will + be asked to process it. Load is distributed across the members + of the pool in round-robin fashion. + + :param topic: This is a name associated with what to consume from. + Multiple instances of a service may consume from the same + topic. + :param proxy: The object that will handle all incoming messages. + :param pool_name: String containing the name of the pool of workers + """ + raise NotImplementedError() + + def join_consumer_pool(self, callback, pool_name, topic, exchange_name): + """Register as a member of a group of consumers for a given topic from + the specified exchange. + + Exactly one member of a given pool will receive each message. + + A message will be delivered to multiple pools, if more than + one is created. + + :param callback: Callable to be invoked for each message. + :type callback: callable accepting one argument + :param pool_name: The name of the consumer pool. + :type pool_name: str + :param topic: The routing topic for desired messages. + :type topic: str + :param exchange_name: The name of the message exchange where + the client should attach. Defaults to + the configured exchange. + :type exchange_name: str + """ + raise NotImplementedError() + + def consume_in_thread(self): + """Spawn a thread to handle incoming messages. + + Spawn a thread that will be responsible for handling all incoming + messages for consumers that were set up on this connection. + + Message dispatching inside of this is expected to be implemented in a + non-blocking manner. An example implementation would be having this + thread pull messages in for all of the consumers, but utilize a thread + pool for dispatching the messages to the proxy objects. + """ + raise NotImplementedError() + + +def _safe_log(log_func, msg, msg_data): + """Sanitizes the msg_data field before logging.""" + SANITIZE = {'set_admin_password': [('args', 'new_pass')], + 'run_instance': [('args', 'admin_password')], + 'route_message': [('args', 'message', 'args', 'method_info', + 'method_kwargs', 'password'), + ('args', 'message', 'args', 'method_info', + 'method_kwargs', 'admin_password')]} + + has_method = 'method' in msg_data and msg_data['method'] in SANITIZE + has_context_token = '_context_auth_token' in msg_data + has_token = 'auth_token' in msg_data + + if not any([has_method, has_context_token, has_token]): + return log_func(msg, msg_data) + + msg_data = copy.deepcopy(msg_data) + + if has_method: + for arg in SANITIZE.get(msg_data['method'], []): + try: + d = msg_data + for elem in arg[:-1]: + d = d[elem] + d[arg[-1]] = '' + except KeyError as e: + LOG.info(_('Failed to sanitize %(item)s. Key error %(err)s'), + {'item': arg, + 'err': e}) + + if has_context_token: + msg_data['_context_auth_token'] = '' + + if has_token: + msg_data['auth_token'] = '' + + return log_func(msg, msg_data) + + +def serialize_remote_exception(failure_info, log_failure=True): + """Prepares exception data to be sent over rpc. + + Failure_info should be a sys.exc_info() tuple. + + """ + tb = traceback.format_exception(*failure_info) + failure = failure_info[1] + if log_failure: + LOG.error(_("Returning exception %s to caller"), + six.text_type(failure)) + LOG.error(tb) + + kwargs = {} + if hasattr(failure, 'kwargs'): + kwargs = failure.kwargs + + data = { + 'class': str(failure.__class__.__name__), + 'module': str(failure.__class__.__module__), + 'message': six.text_type(failure), + 'tb': tb, + 'args': failure.args, + 'kwargs': kwargs + } + + json_data = jsonutils.dumps(data) + + return json_data + + +def deserialize_remote_exception(conf, data): + failure = jsonutils.loads(str(data)) + + trace = failure.get('tb', []) + message = failure.get('message', "") + "\n" + "\n".join(trace) + name = failure.get('class') + module = failure.get('module') + + # NOTE(ameade): We DO NOT want to allow just any module to be imported, in + # order to prevent arbitrary code execution. + if module not in conf.allowed_rpc_exception_modules: + return RemoteError(name, failure.get('message'), trace) + + try: + mod = importutils.import_module(module) + klass = getattr(mod, name) + if not issubclass(klass, Exception): + raise TypeError("Can only deserialize Exceptions") + + failure = klass(*failure.get('args', []), **failure.get('kwargs', {})) + except (AttributeError, TypeError, ImportError): + return RemoteError(name, failure.get('message'), trace) + + ex_type = type(failure) + str_override = lambda self: message + new_ex_type = type(ex_type.__name__ + "_Remote", (ex_type,), + {'__str__': str_override, '__unicode__': str_override}) + try: + # NOTE(ameade): Dynamically create a new exception type and swap it in + # as the new type for the exception. This only works on user defined + # Exceptions and not core python exceptions. This is important because + # we cannot necessarily change an exception message so we must override + # the __str__ method. + failure.__class__ = new_ex_type + except TypeError: + # NOTE(ameade): If a core exception then just add the traceback to the + # first exception argument. + failure.args = (message,) + failure.args[1:] + return failure + + +class CommonRpcContext(object): + def __init__(self, **kwargs): + self.values = kwargs + + def __getattr__(self, key): + try: + return self.values[key] + except KeyError: + raise AttributeError(key) + + def to_dict(self): + return copy.deepcopy(self.values) + + @classmethod + def from_dict(cls, values): + return cls(**values) + + def deepcopy(self): + return self.from_dict(self.to_dict()) + + def update_store(self): + local.store.context = self + + def elevated(self, read_deleted=None, overwrite=False): + """Return a version of this context with admin flag set.""" + # TODO(russellb) This method is a bit of a nova-ism. It makes + # some assumptions about the data in the request context sent + # across rpc, while the rest of this class does not. We could get + # rid of this if we changed the nova code that uses this to + # convert the RpcContext back to its native RequestContext doing + # something like nova.context.RequestContext.from_dict(ctxt.to_dict()) + + context = self.deepcopy() + context.values['is_admin'] = True + + context.values.setdefault('roles', []) + + if 'admin' not in context.values['roles']: + context.values['roles'].append('admin') + + if read_deleted is not None: + context.values['read_deleted'] = read_deleted + + return context + + +class ClientException(Exception): + """This encapsulates some actual exception that is expected to be + hit by an RPC proxy object. Merely instantiating it records the + current exception information, which will be passed back to the + RPC client without exceptional logging.""" + def __init__(self): + self._exc_info = sys.exc_info() + + +def catch_client_exception(exceptions, func, *args, **kwargs): + try: + return func(*args, **kwargs) + except Exception as e: + if type(e) in exceptions: + raise ClientException() + else: + raise + + +def client_exceptions(*exceptions): + """Decorator for manager methods that raise expected exceptions. + Marking a Manager method with this decorator allows the declaration + of expected exceptions that the RPC layer should not consider fatal, + and not log as if they were generated in a real error scenario. Note + that this will cause listed exceptions to be wrapped in a + ClientException, which is used internally by the RPC layer.""" + def outer(func): + def inner(*args, **kwargs): + return catch_client_exception(exceptions, func, *args, **kwargs) + return inner + return outer + + +def version_is_compatible(imp_version, version): + """Determine whether versions are compatible. + + :param imp_version: The version implemented + :param version: The version requested by an incoming message. + """ + version_parts = version.split('.') + imp_version_parts = imp_version.split('.') + if int(version_parts[0]) != int(imp_version_parts[0]): # Major + return False + if int(version_parts[1]) > int(imp_version_parts[1]): # Minor + return False + return True + + +def serialize_msg(raw_msg): + # NOTE(russellb) See the docstring for _RPC_ENVELOPE_VERSION for more + # information about this format. + msg = {_VERSION_KEY: _RPC_ENVELOPE_VERSION, + _MESSAGE_KEY: jsonutils.dumps(raw_msg)} + + return msg + + +def deserialize_msg(msg): + # NOTE(russellb): Hang on to your hats, this road is about to + # get a little bumpy. + # + # Robustness Principle: + # "Be strict in what you send, liberal in what you accept." + # + # At this point we have to do a bit of guessing about what it + # is we just received. Here is the set of possibilities: + # + # 1) We received a dict. This could be 2 things: + # + # a) Inspect it to see if it looks like a standard message envelope. + # If so, great! + # + # b) If it doesn't look like a standard message envelope, it could either + # be a notification, or a message from before we added a message + # envelope (referred to as version 1.0). + # Just return the message as-is. + # + # 2) It's any other non-dict type. Just return it and hope for the best. + # This case covers return values from rpc.call() from before message + # envelopes were used. (messages to call a method were always a dict) + + if not isinstance(msg, dict): + # See #2 above. + return msg + + base_envelope_keys = (_VERSION_KEY, _MESSAGE_KEY) + if not all(map(lambda key: key in msg, base_envelope_keys)): + # See #1.b above. + return msg + + # At this point we think we have the message envelope + # format we were expecting. (#1.a above) + + if not version_is_compatible(_RPC_ENVELOPE_VERSION, msg[_VERSION_KEY]): + raise UnsupportedRpcEnvelopeVersion(version=msg[_VERSION_KEY]) + + raw_msg = jsonutils.loads(msg[_MESSAGE_KEY]) + + return raw_msg diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/dispatcher.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/dispatcher.py new file mode 100644 index 00000000..8520ab7a --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/dispatcher.py @@ -0,0 +1,182 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Code for rpc message dispatching. + +Messages that come in have a version number associated with them. RPC API +version numbers are in the form: + + Major.Minor + +For a given message with version X.Y, the receiver must be marked as able to +handle messages of version A.B, where: + + A = X + + B >= Y + +The Major version number would be incremented for an almost completely new API. +The Minor version number would be incremented for backwards compatible changes +to an existing API. A backwards compatible change could be something like +adding a new method, adding an argument to an existing method (but not +requiring it), or changing the type for an existing argument (but still +handling the old type as well). + +The conversion over to a versioned API must be done on both the client side and +server side of the API at the same time. However, as the code stands today, +there can be both versioned and unversioned APIs implemented in the same code +base. + +EXAMPLES +======== + +Nova was the first project to use versioned rpc APIs. Consider the compute rpc +API as an example. The client side is in nova/compute/rpcapi.py and the server +side is in nova/compute/manager.py. + + +Example 1) Adding a new method. +------------------------------- + +Adding a new method is a backwards compatible change. It should be added to +nova/compute/manager.py, and RPC_API_VERSION should be bumped from X.Y to +X.Y+1. On the client side, the new method in nova/compute/rpcapi.py should +have a specific version specified to indicate the minimum API version that must +be implemented for the method to be supported. For example:: + + def get_host_uptime(self, ctxt, host): + topic = _compute_topic(self.topic, ctxt, host, None) + return self.call(ctxt, self.make_msg('get_host_uptime'), topic, + version='1.1') + +In this case, version '1.1' is the first version that supported the +get_host_uptime() method. + + +Example 2) Adding a new parameter. +---------------------------------- + +Adding a new parameter to an rpc method can be made backwards compatible. The +RPC_API_VERSION on the server side (nova/compute/manager.py) should be bumped. +The implementation of the method must not expect the parameter to be present.:: + + def some_remote_method(self, arg1, arg2, newarg=None): + # The code needs to deal with newarg=None for cases + # where an older client sends a message without it. + pass + +On the client side, the same changes should be made as in example 1. The +minimum version that supports the new parameter should be specified. +""" + +from sm_api.openstack.common.rpc import common as rpc_common +from sm_api.openstack.common.rpc import serializer as rpc_serializer + + +class RpcDispatcher(object): + """Dispatch rpc messages according to the requested API version. + + This class can be used as the top level 'manager' for a service. It + contains a list of underlying managers that have an API_VERSION attribute. + """ + + def __init__(self, callbacks, serializer=None): + """Initialize the rpc dispatcher. + + :param callbacks: List of proxy objects that are an instance + of a class with rpc methods exposed. Each proxy + object should have an RPC_API_VERSION attribute. + :param serializer: The Serializer object that will be used to + deserialize arguments before the method call and + to serialize the result after it returns. + """ + self.callbacks = callbacks + if serializer is None: + serializer = rpc_serializer.NoOpSerializer() + self.serializer = serializer + super(RpcDispatcher, self).__init__() + + def _deserialize_args(self, context, kwargs): + """Helper method called to deserialize args before dispatch. + + This calls our serializer on each argument, returning a new set of + args that have been deserialized. + + :param context: The request context + :param kwargs: The arguments to be deserialized + :returns: A new set of deserialized args + """ + new_kwargs = dict() + for argname, arg in kwargs.iteritems(): + new_kwargs[argname] = self.serializer.deserialize_entity(context, + arg) + return new_kwargs + + def dispatch(self, ctxt, version, method, namespace, **kwargs): + """Dispatch a message based on a requested version. + + :param ctxt: The request context + :param version: The requested API version from the incoming message + :param method: The method requested to be called by the incoming + message. + :param namespace: The namespace for the requested method. If None, + the dispatcher will look for a method on a callback + object with no namespace set. + :param kwargs: A dict of keyword arguments to be passed to the method. + + :returns: Whatever is returned by the underlying method that gets + called. + """ + if not version: + version = '1.0' + + had_compatible = False + for proxyobj in self.callbacks: + # Check for namespace compatibility + try: + cb_namespace = proxyobj.RPC_API_NAMESPACE + except AttributeError: + cb_namespace = None + + if namespace != cb_namespace: + continue + + # Check for version compatibility + try: + rpc_api_version = proxyobj.RPC_API_VERSION + except AttributeError: + rpc_api_version = '1.0' + + is_compatible = rpc_common.version_is_compatible(rpc_api_version, + version) + had_compatible = had_compatible or is_compatible + + if not hasattr(proxyobj, method): + continue + if is_compatible: + kwargs = self._deserialize_args(ctxt, kwargs) + result = getattr(proxyobj, method)(ctxt, **kwargs) + return self.serializer.serialize_entity(ctxt, result) + + if had_compatible: + raise AttributeError("No such RPC function '%s'" % method) + else: + raise rpc_common.UnsupportedRpcVersion(version=version) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_fake.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_fake.py new file mode 100644 index 00000000..331bd28b --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_fake.py @@ -0,0 +1,199 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +"""Fake RPC implementation which calls proxy methods directly with no +queues. Casts will block, but this is very useful for tests. +""" + +import inspect +# NOTE(russellb): We specifically want to use json, not our own jsonutils. +# jsonutils has some extra logic to automatically convert objects to primitive +# types so that they can be serialized. We want to catch all cases where +# non-primitive types make it into this code and treat it as an error. +import json +import time + +import eventlet + +from sm_api.openstack.common.rpc import common as rpc_common + +CONSUMERS = {} + + +class RpcContext(rpc_common.CommonRpcContext): + def __init__(self, **kwargs): + super(RpcContext, self).__init__(**kwargs) + self._response = [] + self._done = False + + def deepcopy(self): + values = self.to_dict() + new_inst = self.__class__(**values) + new_inst._response = self._response + new_inst._done = self._done + return new_inst + + def reply(self, reply=None, failure=None, ending=False): + if ending: + self._done = True + if not self._done: + self._response.append((reply, failure)) + + +class Consumer(object): + def __init__(self, topic, proxy): + self.topic = topic + self.proxy = proxy + + def call(self, context, version, method, namespace, args, timeout): + done = eventlet.event.Event() + + def _inner(): + ctxt = RpcContext.from_dict(context.to_dict()) + try: + rval = self.proxy.dispatch(context, version, method, + namespace, **args) + res = [] + # Caller might have called ctxt.reply() manually + for (reply, failure) in ctxt._response: + if failure: + raise failure[0], failure[1], failure[2] + res.append(reply) + # if ending not 'sent'...we might have more data to + # return from the function itself + if not ctxt._done: + if inspect.isgenerator(rval): + for val in rval: + res.append(val) + else: + res.append(rval) + done.send(res) + except rpc_common.ClientException as e: + done.send_exception(e._exc_info[1]) + except Exception as e: + done.send_exception(e) + + thread = eventlet.greenthread.spawn(_inner) + + if timeout: + start_time = time.time() + while not done.ready(): + eventlet.greenthread.sleep(1) + cur_time = time.time() + if (cur_time - start_time) > timeout: + thread.kill() + raise rpc_common.Timeout() + + return done.wait() + + +class Connection(object): + """Connection object.""" + + def __init__(self): + self.consumers = [] + + def create_consumer(self, topic, proxy, fanout=False): + consumer = Consumer(topic, proxy) + self.consumers.append(consumer) + if topic not in CONSUMERS: + CONSUMERS[topic] = [] + CONSUMERS[topic].append(consumer) + + def close(self): + for consumer in self.consumers: + CONSUMERS[consumer.topic].remove(consumer) + self.consumers = [] + + def consume_in_thread(self): + pass + + +def create_connection(conf, new=True): + """Create a connection""" + return Connection() + + +def check_serialize(msg): + """Make sure a message intended for rpc can be serialized.""" + json.dumps(msg) + + +def multicall(conf, context, topic, msg, timeout=None): + """Make a call that returns multiple times.""" + + check_serialize(msg) + + method = msg.get('method') + if not method: + return + args = msg.get('args', {}) + version = msg.get('version', None) + namespace = msg.get('namespace', None) + + try: + consumer = CONSUMERS[topic][0] + except (KeyError, IndexError): + return iter([None]) + else: + return consumer.call(context, version, method, namespace, args, + timeout) + + +def call(conf, context, topic, msg, timeout=None): + """Sends a message on a topic and wait for a response.""" + rv = multicall(conf, context, topic, msg, timeout) + # NOTE(vish): return the last result from the multicall + rv = list(rv) + if not rv: + return + return rv[-1] + + +def cast(conf, context, topic, msg): + check_serialize(msg) + try: + call(conf, context, topic, msg) + except Exception: + pass + + +def notify(conf, context, topic, msg, envelope): + check_serialize(msg) + + +def cleanup(): + pass + + +def fanout_cast(conf, context, topic, msg): + """Cast to all consumers of a topic""" + check_serialize(msg) + method = msg.get('method') + if not method: + return + args = msg.get('args', {}) + version = msg.get('version', None) + namespace = msg.get('namespace', None) + + for consumer in CONSUMERS.get(topic, []): + try: + consumer.call(context, version, method, namespace, args, None) + except Exception: + pass diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_kombu.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_kombu.py new file mode 100644 index 00000000..da546afd --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_kombu.py @@ -0,0 +1,843 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import functools +import itertools +import socket +import ssl +import sys +import time +import uuid + +import eventlet +import greenlet +import kombu +import kombu.connection +import kombu.entity +import kombu.messaging +from oslo_config import cfg + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import network_utils +from sm_api.openstack.common.rpc import amqp as rpc_amqp +from sm_api.openstack.common.rpc import common as rpc_common + +kombu_opts = [ + cfg.StrOpt('kombu_ssl_version', + default='', + help='SSL version to use (valid only if SSL enabled)'), + cfg.StrOpt('kombu_ssl_keyfile', + default='', + help='SSL key file (valid only if SSL enabled)'), + cfg.StrOpt('kombu_ssl_certfile', + default='', + help='SSL cert file (valid only if SSL enabled)'), + cfg.StrOpt('kombu_ssl_ca_certs', + default='', + help=('SSL certification authority file ' + '(valid only if SSL enabled)')), + cfg.StrOpt('rabbit_host', + default='localhost', + help='The RabbitMQ broker address where a single node is used'), + cfg.IntOpt('rabbit_port', + default=5672, + help='The RabbitMQ broker port where a single node is used'), + cfg.ListOpt('rabbit_hosts', + default=['$rabbit_host:$rabbit_port'], + help='RabbitMQ HA cluster host:port pairs'), + cfg.BoolOpt('rabbit_use_ssl', + default=False, + help='connect over SSL for RabbitMQ'), + cfg.StrOpt('rabbit_userid', + default='guest', + help='the RabbitMQ userid'), + cfg.StrOpt('rabbit_password', + default='guest', + help='the RabbitMQ password', + secret=True), + cfg.StrOpt('rabbit_virtual_host', + default='/', + help='the RabbitMQ virtual host'), + cfg.IntOpt('rabbit_retry_interval', + default=1, + help='how frequently to retry connecting with RabbitMQ'), + cfg.IntOpt('rabbit_retry_backoff', + default=2, + help='how long to backoff for between retries when connecting ' + 'to RabbitMQ'), + cfg.IntOpt('rabbit_max_retries', + default=0, + help='maximum retries with trying to connect to RabbitMQ ' + '(the default of 0 implies an infinite retry count)'), + cfg.BoolOpt('rabbit_durable_queues', + default=False, + help='use durable queues in RabbitMQ'), + cfg.BoolOpt('rabbit_ha_queues', + default=False, + help='use H/A queues in RabbitMQ (x-ha-policy: all).' + 'You need to wipe RabbitMQ database when ' + 'changing this option.'), + +] + +cfg.CONF.register_opts(kombu_opts) + +LOG = rpc_common.LOG + + +def _get_queue_arguments(conf): + """Construct the arguments for declaring a queue. + + If the rabbit_ha_queues option is set, we declare a mirrored queue + as described here: + + http://www.rabbitmq.com/ha.html + + Setting x-ha-policy to all means that the queue will be mirrored + to all nodes in the cluster. + """ + return {'x-ha-policy': 'all'} if conf.rabbit_ha_queues else {} + + +class ConsumerBase(object): + """Consumer base class.""" + + def __init__(self, channel, callback, tag, **kwargs): + """Declare a queue on an amqp channel. + + 'channel' is the amqp channel to use + 'callback' is the callback to call when messages are received + 'tag' is a unique ID for the consumer on the channel + + queue name, exchange name, and other kombu options are + passed in here as a dictionary. + """ + self.callback = callback + self.tag = str(tag) + self.kwargs = kwargs + self.queue = None + self.reconnect(channel) + + def reconnect(self, channel): + """Re-declare the queue after a rabbit reconnect""" + self.channel = channel + self.kwargs['channel'] = channel + self.queue = kombu.entity.Queue(**self.kwargs) + self.queue.declare() + + def consume(self, *args, **kwargs): + """Actually declare the consumer on the amqp channel. This will + start the flow of messages from the queue. Using the + Connection.iterconsume() iterator will process the messages, + calling the appropriate callback. + + If a callback is specified in kwargs, use that. Otherwise, + use the callback passed during __init__() + + If kwargs['nowait'] is True, then this call will block until + a message is read. + + Messages will automatically be acked if the callback doesn't + raise an exception + """ + + options = {'consumer_tag': self.tag} + options['nowait'] = kwargs.get('nowait', False) + callback = kwargs.get('callback', self.callback) + if not callback: + raise ValueError("No callback defined") + + def _callback(raw_message): + message = self.channel.message_to_python(raw_message) + try: + msg = rpc_common.deserialize_msg(message.payload) + callback(msg) + except Exception: + LOG.exception(_("Failed to process message... skipping it.")) + finally: + message.ack() + + self.queue.consume(*args, callback=_callback, **options) + + def cancel(self): + """Cancel the consuming from the queue, if it has started""" + try: + self.queue.cancel(self.tag) + except KeyError as e: + # NOTE(comstud): Kludge to get around a amqplib bug + if str(e) != "u'%s'" % self.tag: + raise + self.queue = None + + +class DirectConsumer(ConsumerBase): + """Queue/consumer class for 'direct'""" + + def __init__(self, conf, channel, msg_id, callback, tag, **kwargs): + """Init a 'direct' queue. + + 'channel' is the amqp channel to use + 'msg_id' is the msg_id to listen on + 'callback' is the callback to call when messages are received + 'tag' is a unique ID for the consumer on the channel + + Other kombu options may be passed + """ + # Default options + options = {'durable': False, + 'queue_arguments': _get_queue_arguments(conf), + 'auto_delete': True, + 'exclusive': False} + options.update(kwargs) + exchange = kombu.entity.Exchange(name=msg_id, + type='direct', + durable=options['durable'], + auto_delete=options['auto_delete']) + super(DirectConsumer, self).__init__(channel, + callback, + tag, + name=msg_id, + exchange=exchange, + routing_key=msg_id, + **options) + + +class TopicConsumer(ConsumerBase): + """Consumer class for 'topic'""" + + def __init__(self, conf, channel, topic, callback, tag, name=None, + exchange_name=None, **kwargs): + """Init a 'topic' queue. + + :param channel: the amqp channel to use + :param topic: the topic to listen on + :paramtype topic: str + :param callback: the callback to call when messages are received + :param tag: a unique ID for the consumer on the channel + :param name: optional queue name, defaults to topic + :paramtype name: str + + Other kombu options may be passed as keyword arguments + """ + # Default options + options = {'durable': conf.rabbit_durable_queues, + 'queue_arguments': _get_queue_arguments(conf), + 'auto_delete': False, + 'exclusive': False} + options.update(kwargs) + exchange_name = exchange_name or rpc_amqp.get_control_exchange(conf) + exchange = kombu.entity.Exchange(name=exchange_name, + type='topic', + durable=options['durable'], + auto_delete=options['auto_delete']) + super(TopicConsumer, self).__init__(channel, + callback, + tag, + name=name or topic, + exchange=exchange, + routing_key=topic, + **options) + + +class FanoutConsumer(ConsumerBase): + """Consumer class for 'fanout'""" + + def __init__(self, conf, channel, topic, callback, tag, **kwargs): + """Init a 'fanout' queue. + + 'channel' is the amqp channel to use + 'topic' is the topic to listen on + 'callback' is the callback to call when messages are received + 'tag' is a unique ID for the consumer on the channel + + Other kombu options may be passed + """ + unique = uuid.uuid4().hex + exchange_name = '%s_fanout' % topic + queue_name = '%s_fanout_%s' % (topic, unique) + + # Default options + options = {'durable': False, + 'queue_arguments': _get_queue_arguments(conf), + 'auto_delete': True, + 'exclusive': False} + options.update(kwargs) + exchange = kombu.entity.Exchange(name=exchange_name, type='fanout', + durable=options['durable'], + auto_delete=options['auto_delete']) + super(FanoutConsumer, self).__init__(channel, callback, tag, + name=queue_name, + exchange=exchange, + routing_key=topic, + **options) + + +class Publisher(object): + """Base Publisher class""" + + def __init__(self, channel, exchange_name, routing_key, **kwargs): + """Init the Publisher class with the exchange_name, routing_key, + and other options + """ + self.exchange_name = exchange_name + self.routing_key = routing_key + self.kwargs = kwargs + self.reconnect(channel) + + def reconnect(self, channel): + """Re-establish the Producer after a rabbit reconnection""" + self.exchange = kombu.entity.Exchange(name=self.exchange_name, + **self.kwargs) + self.producer = kombu.messaging.Producer(exchange=self.exchange, + channel=channel, + routing_key=self.routing_key) + + def send(self, msg, timeout=None): + """Send a message""" + if timeout: + # + # AMQP TTL is in milliseconds when set in the header. + # + self.producer.publish(msg, headers={'ttl': (timeout * 1000)}) + else: + self.producer.publish(msg) + + +class DirectPublisher(Publisher): + """Publisher class for 'direct'""" + def __init__(self, conf, channel, msg_id, **kwargs): + """init a 'direct' publisher. + + Kombu options may be passed as keyword args to override defaults + """ + + options = {'durable': False, + 'auto_delete': True, + 'exclusive': False} + options.update(kwargs) + super(DirectPublisher, self).__init__(channel, msg_id, msg_id, + type='direct', **options) + + +class TopicPublisher(Publisher): + """Publisher class for 'topic'""" + def __init__(self, conf, channel, topic, **kwargs): + """init a 'topic' publisher. + + Kombu options may be passed as keyword args to override defaults + """ + options = {'durable': conf.rabbit_durable_queues, + 'auto_delete': False, + 'exclusive': False} + options.update(kwargs) + exchange_name = rpc_amqp.get_control_exchange(conf) + super(TopicPublisher, self).__init__(channel, + exchange_name, + topic, + type='topic', + **options) + + +class FanoutPublisher(Publisher): + """Publisher class for 'fanout'""" + def __init__(self, conf, channel, topic, **kwargs): + """init a 'fanout' publisher. + + Kombu options may be passed as keyword args to override defaults + """ + options = {'durable': False, + 'auto_delete': True, + 'exclusive': False} + options.update(kwargs) + super(FanoutPublisher, self).__init__(channel, '%s_fanout' % topic, + None, type='fanout', **options) + + +class NotifyPublisher(TopicPublisher): + """Publisher class for 'notify'""" + + def __init__(self, conf, channel, topic, **kwargs): + self.durable = kwargs.pop('durable', conf.rabbit_durable_queues) + self.queue_arguments = _get_queue_arguments(conf) + super(NotifyPublisher, self).__init__(conf, channel, topic, **kwargs) + + def reconnect(self, channel): + super(NotifyPublisher, self).reconnect(channel) + + # NOTE(jerdfelt): Normally the consumer would create the queue, but + # we do this to ensure that messages don't get dropped if the + # consumer is started after we do + queue = kombu.entity.Queue(channel=channel, + exchange=self.exchange, + durable=self.durable, + name=self.routing_key, + routing_key=self.routing_key, + queue_arguments=self.queue_arguments) + queue.declare() + + +class Connection(object): + """Connection object.""" + + pool = None + + def __init__(self, conf, server_params=None): + self.consumers = [] + self.consumer_thread = None + self.proxy_callbacks = [] + self.conf = conf + self.max_retries = self.conf.rabbit_max_retries + # Try forever? + if self.max_retries <= 0: + self.max_retries = None + self.interval_start = self.conf.rabbit_retry_interval + self.interval_stepping = self.conf.rabbit_retry_backoff + # max retry-interval = 30 seconds + self.interval_max = 30 + self.memory_transport = False + + if server_params is None: + server_params = {} + # Keys to translate from server_params to kombu params + server_params_to_kombu_params = {'username': 'userid'} + + ssl_params = self._fetch_ssl_params() + params_list = [] + for adr in self.conf.rabbit_hosts: + hostname, port = network_utils.parse_host_port( + adr, default_port=self.conf.rabbit_port) + + params = { + 'hostname': hostname, + 'port': port, + 'userid': self.conf.rabbit_userid, + 'password': self.conf.rabbit_password, + 'virtual_host': self.conf.rabbit_virtual_host, + } + + for sp_key, value in server_params.iteritems(): + p_key = server_params_to_kombu_params.get(sp_key, sp_key) + params[p_key] = value + + if self.conf.fake_rabbit: + params['transport'] = 'memory' + if self.conf.rabbit_use_ssl: + params['ssl'] = ssl_params + + params_list.append(params) + + self.params_list = params_list + + self.memory_transport = self.conf.fake_rabbit + + self.connection = None + self.reconnect() + + def _fetch_ssl_params(self): + """Handles fetching what ssl params + should be used for the connection (if any)""" + ssl_params = dict() + + # http://docs.python.org/library/ssl.html - ssl.wrap_socket + if self.conf.kombu_ssl_version: + ssl_params['ssl_version'] = self.conf.kombu_ssl_version + if self.conf.kombu_ssl_keyfile: + ssl_params['keyfile'] = self.conf.kombu_ssl_keyfile + if self.conf.kombu_ssl_certfile: + ssl_params['certfile'] = self.conf.kombu_ssl_certfile + if self.conf.kombu_ssl_ca_certs: + ssl_params['ca_certs'] = self.conf.kombu_ssl_ca_certs + # We might want to allow variations in the + # future with this? + ssl_params['cert_reqs'] = ssl.CERT_REQUIRED + + if not ssl_params: + # Just have the default behavior + return True + else: + # Return the extended behavior + return ssl_params + + def _connect(self, params): + """Connect to rabbit. Re-establish any queues that may have + been declared before if we are reconnecting. Exceptions should + be handled by the caller. + """ + if self.connection: + LOG.info(_("Reconnecting to AMQP server on " + "%(hostname)s:%(port)d") % params) + try: + self.connection.release() + except self.connection_errors: + pass + # Setting this in case the next statement fails, though + # it shouldn't be doing any network operations, yet. + self.connection = None + self.connection = kombu.connection.BrokerConnection(**params) + self.connection_errors = self.connection.connection_errors + self.channel_errors = self.connection.channel_errors + if self.memory_transport: + # Kludge to speed up tests. + self.connection.transport.polling_interval = 0.0 + self.consumer_num = itertools.count(1) + self.connection.connect() + self.channel = self.connection.channel() + # work around 'memory' transport bug in 1.1.3 + if self.memory_transport: + self.channel._new_queue('ae.undeliver') + for consumer in self.consumers: + consumer.reconnect(self.channel) + LOG.info(_('Connected to AMQP server on %(hostname)s:%(port)d') % + params) + + def reconnect(self): + """Handles reconnecting and re-establishing queues. + Will retry up to self.max_retries number of times. + self.max_retries = 0 means to retry forever. + Sleep between tries, starting at self.interval_start + seconds, backing off self.interval_stepping number of seconds + each attempt. + """ + + attempt = 0 + while True: + params = self.params_list[attempt % len(self.params_list)] + attempt += 1 + try: + self._connect(params) + return + except (IOError, self.connection_errors) as e: + pass + except Exception as e: + # NOTE(comstud): Unfortunately it's possible for amqplib + # to return an error not covered by its transport + # connection_errors in the case of a timeout waiting for + # a protocol response. (See paste link in LP888621) + # So, we check all exceptions for 'timeout' in them + # and try to reconnect in this case. + if 'timeout' not in str(e): + raise + + log_info = {} + log_info['err_str'] = str(e) + log_info['max_retries'] = self.max_retries + log_info.update(params) + + if self.max_retries and attempt == self.max_retries: + LOG.error(_('Unable to connect to AMQP server on ' + '%(hostname)s:%(port)d after %(max_retries)d ' + 'tries: %(err_str)s') % log_info) + # NOTE(comstud): Copied from original code. There's + # really no better recourse because if this was a queue we + # need to consume on, we have no way to consume anymore. + sys.exit(1) + + if attempt == 1: + sleep_time = self.interval_start or 1 + elif attempt > 1: + sleep_time += self.interval_stepping + if self.interval_max: + sleep_time = min(sleep_time, self.interval_max) + + log_info['sleep_time'] = sleep_time + LOG.error(_('AMQP server on %(hostname)s:%(port)d is ' + 'unreachable: %(err_str)s. Trying again in ' + '%(sleep_time)d seconds.') % log_info) + time.sleep(sleep_time) + + def ensure(self, error_callback, method, *args, **kwargs): + while True: + try: + return method(*args, **kwargs) + except (self.channel_errors, self.connection_errors, socket.timeout, IOError) as e: + if error_callback: + error_callback(e) + except Exception as e: + # NOTE(comstud): Unfortunately it's possible for amqplib + # to return an error not covered by its transport + # connection_errors in the case of a timeout waiting for + # a protocol response. (See paste link in LP888621) + # So, we check all exceptions for 'timeout' in them + # and try to reconnect in this case. + if 'timeout' not in str(e): + raise + if error_callback: + error_callback(e) + self.reconnect() + + def get_channel(self): + """Convenience call for bin/clear_rabbit_queues""" + return self.channel + + def close(self): + """Close/release this connection""" + self.cancel_consumer_thread() + self.wait_on_proxy_callbacks() + self.connection.release() + self.connection = None + + def reset(self): + """Reset a connection so it can be used again""" + self.cancel_consumer_thread() + self.wait_on_proxy_callbacks() + self.channel.close() + self.channel = self.connection.channel() + # work around 'memory' transport bug in 1.1.3 + if self.memory_transport: + self.channel._new_queue('ae.undeliver') + self.consumers = [] + + def declare_consumer(self, consumer_cls, topic, callback): + """Create a Consumer using the class that was passed in and + add it to our list of consumers + """ + + def _connect_error(exc): + log_info = {'topic': topic, 'err_str': str(exc)} + LOG.error(_("Failed to declare consumer for topic '%(topic)s': " + "%(err_str)s") % log_info) + + def _declare_consumer(): + consumer = consumer_cls(self.conf, self.channel, topic, callback, + self.consumer_num.next()) + self.consumers.append(consumer) + return consumer + + return self.ensure(_connect_error, _declare_consumer) + + def iterconsume(self, limit=None, timeout=None): + """Return an iterator that will consume from all queues/consumers""" + + info = {'do_consume': True} + + def _error_callback(exc): + if isinstance(exc, socket.timeout): + LOG.debug(_('Timed out waiting for RPC response: %s') % + str(exc)) + raise rpc_common.Timeout() + else: + LOG.exception(_('Failed to consume message from queue: %s') % + str(exc)) + info['do_consume'] = True + + def _consume(): + if info['do_consume']: + queues_head = self.consumers[:-1] + queues_tail = self.consumers[-1] + for queue in queues_head: + queue.consume(nowait=True) + queues_tail.consume(nowait=False) + info['do_consume'] = False + return self.connection.drain_events(timeout=timeout) + + for iteration in itertools.count(0): + if limit and iteration >= limit: + raise StopIteration + yield self.ensure(_error_callback, _consume) + + def cancel_consumer_thread(self): + """Cancel a consumer thread""" + if self.consumer_thread is not None: + self.consumer_thread.kill() + try: + self.consumer_thread.wait() + except greenlet.GreenletExit: + pass + self.consumer_thread = None + + def wait_on_proxy_callbacks(self): + """Wait for all proxy callback threads to exit.""" + for proxy_cb in self.proxy_callbacks: + proxy_cb.wait() + + def publisher_send(self, cls, topic, msg, timeout=None, **kwargs): + """Send to a publisher based on the publisher class""" + + def _error_callback(exc): + log_info = {'topic': topic, 'err_str': str(exc)} + LOG.exception(_("Failed to publish message to topic " + "'%(topic)s': %(err_str)s") % log_info) + + def _publish(): + publisher = cls(self.conf, self.channel, topic, **kwargs) + publisher.send(msg, timeout) + + self.ensure(_error_callback, _publish) + + def declare_direct_consumer(self, topic, callback): + """Create a 'direct' queue. + In nova's use, this is generally a msg_id queue used for + responses for call/multicall + """ + self.declare_consumer(DirectConsumer, topic, callback) + + def declare_topic_consumer(self, topic, callback=None, queue_name=None, + exchange_name=None): + """Create a 'topic' consumer.""" + self.declare_consumer(functools.partial(TopicConsumer, + name=queue_name, + exchange_name=exchange_name, + ), + topic, callback) + + def declare_fanout_consumer(self, topic, callback): + """Create a 'fanout' consumer""" + self.declare_consumer(FanoutConsumer, topic, callback) + + def direct_send(self, msg_id, msg): + """Send a 'direct' message""" + self.publisher_send(DirectPublisher, msg_id, msg) + + def topic_send(self, topic, msg, timeout=None): + """Send a 'topic' message""" + self.publisher_send(TopicPublisher, topic, msg, timeout) + + def fanout_send(self, topic, msg): + """Send a 'fanout' message""" + self.publisher_send(FanoutPublisher, topic, msg) + + def notify_send(self, topic, msg, **kwargs): + """Send a notify message on a topic""" + self.publisher_send(NotifyPublisher, topic, msg, None, **kwargs) + + def consume(self, limit=None): + """Consume from all queues/consumers""" + it = self.iterconsume(limit=limit) + while True: + try: + it.next() + except StopIteration: + return + + def consume_in_thread(self): + """Consumer from all queues/consumers in a greenthread""" + def _consumer_thread(): + try: + self.consume() + except greenlet.GreenletExit: + return + if self.consumer_thread is None: + self.consumer_thread = eventlet.spawn(_consumer_thread) + return self.consumer_thread + + def create_consumer(self, topic, proxy, fanout=False): + """Create a consumer that calls a method in a proxy object""" + proxy_cb = rpc_amqp.ProxyCallback( + self.conf, proxy, + rpc_amqp.get_connection_pool(self.conf, Connection)) + self.proxy_callbacks.append(proxy_cb) + + if fanout: + self.declare_fanout_consumer(topic, proxy_cb) + else: + self.declare_topic_consumer(topic, proxy_cb) + + def create_worker(self, topic, proxy, pool_name): + """Create a worker that calls a method in a proxy object""" + proxy_cb = rpc_amqp.ProxyCallback( + self.conf, proxy, + rpc_amqp.get_connection_pool(self.conf, Connection)) + self.proxy_callbacks.append(proxy_cb) + self.declare_topic_consumer(topic, proxy_cb, pool_name) + + def join_consumer_pool(self, callback, pool_name, topic, + exchange_name=None): + """Register as a member of a group of consumers for a given topic from + the specified exchange. + + Exactly one member of a given pool will receive each message. + + A message will be delivered to multiple pools, if more than + one is created. + """ + callback_wrapper = rpc_amqp.CallbackWrapper( + conf=self.conf, + callback=callback, + connection_pool=rpc_amqp.get_connection_pool(self.conf, + Connection), + ) + self.proxy_callbacks.append(callback_wrapper) + self.declare_topic_consumer( + queue_name=pool_name, + topic=topic, + exchange_name=exchange_name, + callback=callback_wrapper, + ) + + +def create_connection(conf, new=True): + """Create a connection""" + return rpc_amqp.create_connection( + conf, new, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def multicall(conf, context, topic, msg, timeout=None): + """Make a call that returns multiple times.""" + return rpc_amqp.multicall( + conf, context, topic, msg, timeout, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def call(conf, context, topic, msg, timeout=None): + """Sends a message on a topic and wait for a response.""" + return rpc_amqp.call( + conf, context, topic, msg, timeout, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def cast(conf, context, topic, msg): + """Sends a message on a topic without waiting for a response.""" + return rpc_amqp.cast( + conf, context, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def fanout_cast(conf, context, topic, msg): + """Sends a message on a fanout exchange without waiting for a response.""" + return rpc_amqp.fanout_cast( + conf, context, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def cast_to_server(conf, context, server_params, topic, msg): + """Sends a message on a topic to a specific server.""" + return rpc_amqp.cast_to_server( + conf, context, server_params, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def fanout_cast_to_server(conf, context, server_params, topic, msg): + """Sends a message on a fanout exchange to a specific server.""" + return rpc_amqp.fanout_cast_to_server( + conf, context, server_params, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def notify(conf, context, topic, msg, envelope): + """Sends a notification event on a topic.""" + return rpc_amqp.notify( + conf, context, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection), + envelope) + + +def cleanup(): + return rpc_amqp.cleanup(Connection.pool) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_qpid.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_qpid.py new file mode 100644 index 00000000..ecc4d95d --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_qpid.py @@ -0,0 +1,654 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation +# Copyright 2011 - 2012, Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import functools +import itertools +import time +import uuid + +import eventlet +import greenlet +from oslo_config import cfg + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import importutils +from sm_api.openstack.common import jsonutils +from sm_api.openstack.common import log as logging +from sm_api.openstack.common.rpc import amqp as rpc_amqp +from sm_api.openstack.common.rpc import common as rpc_common + +qpid_messaging = importutils.try_import("qpid.messaging") +qpid_exceptions = importutils.try_import("qpid.messaging.exceptions") + +LOG = logging.getLogger(__name__) + +qpid_opts = [ + cfg.StrOpt('qpid_hostname', + default='localhost', + help='Qpid broker hostname'), + cfg.IntOpt('qpid_port', + default=5672, + help='Qpid broker port'), + cfg.ListOpt('qpid_hosts', + default=['$qpid_hostname:$qpid_port'], + help='Qpid HA cluster host:port pairs'), + cfg.StrOpt('qpid_username', + default='', + help='Username for qpid connection'), + cfg.StrOpt('qpid_password', + default='', + help='Password for qpid connection', + secret=True), + cfg.StrOpt('qpid_sasl_mechanisms', + default='', + help='Space separated list of SASL mechanisms to use for auth'), + cfg.IntOpt('qpid_heartbeat', + default=60, + help='Seconds between connection keepalive heartbeats'), + cfg.StrOpt('qpid_protocol', + default='tcp', + help="Transport to use, either 'tcp' or 'ssl'"), + cfg.BoolOpt('qpid_tcp_nodelay', + default=True, + help='Disable Nagle algorithm'), +] + +cfg.CONF.register_opts(qpid_opts) + + +class ConsumerBase(object): + """Consumer base class.""" + + def __init__(self, session, callback, node_name, node_opts, + link_name, link_opts): + """Declare a queue on an amqp session. + + 'session' is the amqp session to use + 'callback' is the callback to call when messages are received + 'node_name' is the first part of the Qpid address string, before ';' + 'node_opts' will be applied to the "x-declare" section of "node" + in the address string. + 'link_name' goes into the "name" field of the "link" in the address + string + 'link_opts' will be applied to the "x-declare" section of "link" + in the address string. + """ + self.callback = callback + self.receiver = None + self.session = None + + addr_opts = { + "create": "always", + "node": { + "type": "topic", + "x-declare": { + "durable": True, + "auto-delete": True, + }, + }, + "link": { + "name": link_name, + "durable": True, + "x-declare": { + "durable": False, + "auto-delete": True, + "exclusive": False, + }, + }, + } + addr_opts["node"]["x-declare"].update(node_opts) + addr_opts["link"]["x-declare"].update(link_opts) + + self.address = "%s ; %s" % (node_name, jsonutils.dumps(addr_opts)) + + self.reconnect(session) + + def reconnect(self, session): + """Re-declare the receiver after a qpid reconnect""" + self.session = session + self.receiver = session.receiver(self.address) + self.receiver.capacity = 1 + + def consume(self): + """Fetch the message and pass it to the callback object""" + message = self.receiver.fetch() + try: + msg = rpc_common.deserialize_msg(message.content) + self.callback(msg) + except Exception: + LOG.exception(_("Failed to process message... skipping it.")) + finally: + self.session.acknowledge(message) + + def get_receiver(self): + return self.receiver + + +class DirectConsumer(ConsumerBase): + """Queue/consumer class for 'direct'""" + + def __init__(self, conf, session, msg_id, callback): + """Init a 'direct' queue. + + 'session' is the amqp session to use + 'msg_id' is the msg_id to listen on + 'callback' is the callback to call when messages are received + """ + + super(DirectConsumer, self).__init__(session, callback, + "%s/%s" % (msg_id, msg_id), + {"type": "direct"}, + msg_id, + {"exclusive": True}) + + +class TopicConsumer(ConsumerBase): + """Consumer class for 'topic'""" + + def __init__(self, conf, session, topic, callback, name=None, + exchange_name=None): + """Init a 'topic' queue. + + :param session: the amqp session to use + :param topic: is the topic to listen on + :paramtype topic: str + :param callback: the callback to call when messages are received + :param name: optional queue name, defaults to topic + """ + + exchange_name = exchange_name or rpc_amqp.get_control_exchange(conf) + super(TopicConsumer, self).__init__(session, callback, + "%s/%s" % (exchange_name, topic), + {}, name or topic, {}) + + +class FanoutConsumer(ConsumerBase): + """Consumer class for 'fanout'""" + + def __init__(self, conf, session, topic, callback): + """Init a 'fanout' queue. + + 'session' is the amqp session to use + 'topic' is the topic to listen on + 'callback' is the callback to call when messages are received + """ + + super(FanoutConsumer, self).__init__( + session, callback, + "%s_fanout" % topic, + {"durable": False, "type": "fanout"}, + "%s_fanout_%s" % (topic, uuid.uuid4().hex), + {"exclusive": True}) + + +class Publisher(object): + """Base Publisher class""" + + def __init__(self, session, node_name, node_opts=None): + """Init the Publisher class with the exchange_name, routing_key, + and other options + """ + self.sender = None + self.session = session + + addr_opts = { + "create": "always", + "node": { + "type": "topic", + "x-declare": { + "durable": False, + # auto-delete isn't implemented for exchanges in qpid, + # but put in here anyway + "auto-delete": True, + }, + }, + } + if node_opts: + addr_opts["node"]["x-declare"].update(node_opts) + + self.address = "%s ; %s" % (node_name, jsonutils.dumps(addr_opts)) + + self.reconnect(session) + + def reconnect(self, session): + """Re-establish the Sender after a reconnection""" + self.sender = session.sender(self.address) + + def send(self, msg): + """Send a message""" + self.sender.send(msg) + + +class DirectPublisher(Publisher): + """Publisher class for 'direct'""" + def __init__(self, conf, session, msg_id): + """Init a 'direct' publisher.""" + super(DirectPublisher, self).__init__(session, msg_id, + {"type": "Direct"}) + + +class TopicPublisher(Publisher): + """Publisher class for 'topic'""" + def __init__(self, conf, session, topic): + """init a 'topic' publisher. + """ + exchange_name = rpc_amqp.get_control_exchange(conf) + super(TopicPublisher, self).__init__(session, + "%s/%s" % (exchange_name, topic)) + + +class FanoutPublisher(Publisher): + """Publisher class for 'fanout'""" + def __init__(self, conf, session, topic): + """init a 'fanout' publisher. + """ + super(FanoutPublisher, self).__init__( + session, + "%s_fanout" % topic, {"type": "fanout"}) + + +class NotifyPublisher(Publisher): + """Publisher class for notifications""" + def __init__(self, conf, session, topic): + """init a 'topic' publisher. + """ + exchange_name = rpc_amqp.get_control_exchange(conf) + super(NotifyPublisher, self).__init__(session, + "%s/%s" % (exchange_name, topic), + {"durable": True}) + + +class Connection(object): + """Connection object.""" + + pool = None + + def __init__(self, conf, server_params=None): + if not qpid_messaging: + raise ImportError("Failed to import qpid.messaging") + + self.session = None + self.consumers = {} + self.consumer_thread = None + self.proxy_callbacks = [] + self.conf = conf + + if server_params and 'hostname' in server_params: + # NOTE(russellb) This enables support for cast_to_server. + server_params['qpid_hosts'] = [ + '%s:%d' % (server_params['hostname'], + server_params.get('port', 5672)) + ] + + params = { + 'qpid_hosts': self.conf.qpid_hosts, + 'username': self.conf.qpid_username, + 'password': self.conf.qpid_password, + } + params.update(server_params or {}) + + self.brokers = params['qpid_hosts'] + self.username = params['username'] + self.password = params['password'] + self.connection_create(self.brokers[0]) + self.reconnect() + + def connection_create(self, broker): + # Create the connection - this does not open the connection + self.connection = qpid_messaging.Connection(broker) + + # Check if flags are set and if so set them for the connection + # before we call open + self.connection.username = self.username + self.connection.password = self.password + + self.connection.sasl_mechanisms = self.conf.qpid_sasl_mechanisms + # Reconnection is done by self.reconnect() + self.connection.reconnect = False + self.connection.heartbeat = self.conf.qpid_heartbeat + self.connection.transport = self.conf.qpid_protocol + self.connection.tcp_nodelay = self.conf.qpid_tcp_nodelay + + def _register_consumer(self, consumer): + self.consumers[str(consumer.get_receiver())] = consumer + + def _lookup_consumer(self, receiver): + return self.consumers[str(receiver)] + + def reconnect(self): + """Handles reconnecting and re-establishing sessions and queues""" + attempt = 0 + delay = 1 + while True: + # Close the session if necessary + if self.connection.opened(): + try: + self.connection.close() + except qpid_exceptions.ConnectionError: + pass + + broker = self.brokers[attempt % len(self.brokers)] + attempt += 1 + + try: + self.connection_create(broker) + self.connection.open() + except qpid_exceptions.ConnectionError as e: + msg_dict = dict(e=e, delay=delay) + msg = _("Unable to connect to AMQP server: %(e)s. " + "Sleeping %(delay)s seconds") % msg_dict + LOG.error(msg) + time.sleep(delay) + delay = min(2 * delay, 60) + else: + LOG.info(_('Connected to AMQP server on %s'), broker) + break + + self.session = self.connection.session() + + if self.consumers: + consumers = self.consumers + self.consumers = {} + + for consumer in consumers.itervalues(): + consumer.reconnect(self.session) + self._register_consumer(consumer) + + LOG.debug(_("Re-established AMQP queues")) + + def ensure(self, error_callback, method, *args, **kwargs): + while True: + try: + return method(*args, **kwargs) + except (qpid_exceptions.Empty, + qpid_exceptions.ConnectionError) as e: + if error_callback: + error_callback(e) + self.reconnect() + + def close(self): + """Close/release this connection""" + self.cancel_consumer_thread() + self.wait_on_proxy_callbacks() + self.connection.close() + self.connection = None + + def reset(self): + """Reset a connection so it can be used again""" + self.cancel_consumer_thread() + self.wait_on_proxy_callbacks() + self.session.close() + self.session = self.connection.session() + self.consumers = {} + + def declare_consumer(self, consumer_cls, topic, callback): + """Create a Consumer using the class that was passed in and + add it to our list of consumers + """ + def _connect_error(exc): + log_info = {'topic': topic, 'err_str': str(exc)} + LOG.error(_("Failed to declare consumer for topic '%(topic)s': " + "%(err_str)s") % log_info) + + def _declare_consumer(): + consumer = consumer_cls(self.conf, self.session, topic, callback) + self._register_consumer(consumer) + return consumer + + return self.ensure(_connect_error, _declare_consumer) + + def iterconsume(self, limit=None, timeout=None): + """Return an iterator that will consume from all queues/consumers""" + + def _error_callback(exc): + if isinstance(exc, qpid_exceptions.Empty): + LOG.debug(_('Timed out waiting for RPC response: %s') % + str(exc)) + raise rpc_common.Timeout() + else: + LOG.exception(_('Failed to consume message from queue: %s') % + str(exc)) + + def _consume(): + nxt_receiver = self.session.next_receiver(timeout=timeout) + try: + self._lookup_consumer(nxt_receiver).consume() + except Exception: + LOG.exception(_("Error processing message. Skipping it.")) + + for iteration in itertools.count(0): + if limit and iteration >= limit: + raise StopIteration + yield self.ensure(_error_callback, _consume) + + def cancel_consumer_thread(self): + """Cancel a consumer thread""" + if self.consumer_thread is not None: + self.consumer_thread.kill() + try: + self.consumer_thread.wait() + except greenlet.GreenletExit: + pass + self.consumer_thread = None + + def wait_on_proxy_callbacks(self): + """Wait for all proxy callback threads to exit.""" + for proxy_cb in self.proxy_callbacks: + proxy_cb.wait() + + def publisher_send(self, cls, topic, msg): + """Send to a publisher based on the publisher class""" + + def _connect_error(exc): + log_info = {'topic': topic, 'err_str': str(exc)} + LOG.exception(_("Failed to publish message to topic " + "'%(topic)s': %(err_str)s") % log_info) + + def _publisher_send(): + publisher = cls(self.conf, self.session, topic) + publisher.send(msg) + + return self.ensure(_connect_error, _publisher_send) + + def declare_direct_consumer(self, topic, callback): + """Create a 'direct' queue. + In nova's use, this is generally a msg_id queue used for + responses for call/multicall + """ + self.declare_consumer(DirectConsumer, topic, callback) + + def declare_topic_consumer(self, topic, callback=None, queue_name=None, + exchange_name=None): + """Create a 'topic' consumer.""" + self.declare_consumer(functools.partial(TopicConsumer, + name=queue_name, + exchange_name=exchange_name, + ), + topic, callback) + + def declare_fanout_consumer(self, topic, callback): + """Create a 'fanout' consumer""" + self.declare_consumer(FanoutConsumer, topic, callback) + + def direct_send(self, msg_id, msg): + """Send a 'direct' message""" + self.publisher_send(DirectPublisher, msg_id, msg) + + def topic_send(self, topic, msg, timeout=None): + """Send a 'topic' message""" + # + # We want to create a message with attributes, e.g. a TTL. We + # don't really need to keep 'msg' in its JSON format any longer + # so let's create an actual qpid message here and get some + # value-add on the go. + # + # WARNING: Request timeout happens to be in the same units as + # qpid's TTL (seconds). If this changes in the future, then this + # will need to be altered accordingly. + # + qpid_message = qpid_messaging.Message(content=msg, ttl=timeout) + self.publisher_send(TopicPublisher, topic, qpid_message) + + def fanout_send(self, topic, msg): + """Send a 'fanout' message""" + self.publisher_send(FanoutPublisher, topic, msg) + + def notify_send(self, topic, msg, **kwargs): + """Send a notify message on a topic""" + self.publisher_send(NotifyPublisher, topic, msg) + + def consume(self, limit=None): + """Consume from all queues/consumers""" + it = self.iterconsume(limit=limit) + while True: + try: + it.next() + except StopIteration: + return + + def consume_in_thread(self): + """Consumer from all queues/consumers in a greenthread""" + def _consumer_thread(): + try: + self.consume() + except greenlet.GreenletExit: + return + if self.consumer_thread is None: + self.consumer_thread = eventlet.spawn(_consumer_thread) + return self.consumer_thread + + def create_consumer(self, topic, proxy, fanout=False): + """Create a consumer that calls a method in a proxy object""" + proxy_cb = rpc_amqp.ProxyCallback( + self.conf, proxy, + rpc_amqp.get_connection_pool(self.conf, Connection)) + self.proxy_callbacks.append(proxy_cb) + + if fanout: + consumer = FanoutConsumer(self.conf, self.session, topic, proxy_cb) + else: + consumer = TopicConsumer(self.conf, self.session, topic, proxy_cb) + + self._register_consumer(consumer) + + return consumer + + def create_worker(self, topic, proxy, pool_name): + """Create a worker that calls a method in a proxy object""" + proxy_cb = rpc_amqp.ProxyCallback( + self.conf, proxy, + rpc_amqp.get_connection_pool(self.conf, Connection)) + self.proxy_callbacks.append(proxy_cb) + + consumer = TopicConsumer(self.conf, self.session, topic, proxy_cb, + name=pool_name) + + self._register_consumer(consumer) + + return consumer + + def join_consumer_pool(self, callback, pool_name, topic, + exchange_name=None): + """Register as a member of a group of consumers for a given topic from + the specified exchange. + + Exactly one member of a given pool will receive each message. + + A message will be delivered to multiple pools, if more than + one is created. + """ + callback_wrapper = rpc_amqp.CallbackWrapper( + conf=self.conf, + callback=callback, + connection_pool=rpc_amqp.get_connection_pool(self.conf, + Connection), + ) + self.proxy_callbacks.append(callback_wrapper) + + consumer = TopicConsumer(conf=self.conf, + session=self.session, + topic=topic, + callback=callback_wrapper, + name=pool_name, + exchange_name=exchange_name) + + self._register_consumer(consumer) + return consumer + + +def create_connection(conf, new=True): + """Create a connection""" + return rpc_amqp.create_connection( + conf, new, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def multicall(conf, context, topic, msg, timeout=None): + """Make a call that returns multiple times.""" + return rpc_amqp.multicall( + conf, context, topic, msg, timeout, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def call(conf, context, topic, msg, timeout=None): + """Sends a message on a topic and wait for a response.""" + return rpc_amqp.call( + conf, context, topic, msg, timeout, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def cast(conf, context, topic, msg): + """Sends a message on a topic without waiting for a response.""" + return rpc_amqp.cast( + conf, context, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def fanout_cast(conf, context, topic, msg): + """Sends a message on a fanout exchange without waiting for a response.""" + return rpc_amqp.fanout_cast( + conf, context, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def cast_to_server(conf, context, server_params, topic, msg): + """Sends a message on a topic to a specific server.""" + return rpc_amqp.cast_to_server( + conf, context, server_params, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def fanout_cast_to_server(conf, context, server_params, topic, msg): + """Sends a message on a fanout exchange to a specific server.""" + return rpc_amqp.fanout_cast_to_server( + conf, context, server_params, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection)) + + +def notify(conf, context, topic, msg, envelope): + """Sends a notification event on a topic.""" + return rpc_amqp.notify(conf, context, topic, msg, + rpc_amqp.get_connection_pool(conf, Connection), + envelope) + + +def cleanup(): + return rpc_amqp.cleanup(Connection.pool) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_zmq.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_zmq.py new file mode 100644 index 00000000..cf3f40ae --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/impl_zmq.py @@ -0,0 +1,860 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Cloudscaling Group, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import os +import pprint +import re +import socket +import sys +import types +import uuid + +import eventlet +import greenlet +from oslo_config import cfg + +from sm_api.openstack.common import excutils +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import importutils +from sm_api.openstack.common import jsonutils +from sm_api.openstack.common import processutils as utils +from sm_api.openstack.common.rpc import common as rpc_common + +zmq = importutils.try_import('eventlet.green.zmq') + +# for convenience, are not modified. +pformat = pprint.pformat +Timeout = eventlet.timeout.Timeout +LOG = rpc_common.LOG +RemoteError = rpc_common.RemoteError +RPCException = rpc_common.RPCException + +zmq_opts = [ + cfg.StrOpt('rpc_zmq_bind_address', default='*', + help='ZeroMQ bind address. Should be a wildcard (*), ' + 'an ethernet interface, or IP. ' + 'The "host" option should point or resolve to this ' + 'address.'), + + # The module.Class to use for matchmaking. + cfg.StrOpt( + 'rpc_zmq_matchmaker', + default=('sm_api.openstack.common.rpc.' + 'matchmaker.MatchMakerLocalhost'), + help='MatchMaker driver', + ), + + # The following port is unassigned by IANA as of 2012-05-21 + cfg.IntOpt('rpc_zmq_port', default=9501, + help='ZeroMQ receiver listening port'), + + cfg.IntOpt('rpc_zmq_contexts', default=1, + help='Number of ZeroMQ contexts, defaults to 1'), + + cfg.IntOpt('rpc_zmq_topic_backlog', default=None, + help='Maximum number of ingress messages to locally buffer ' + 'per topic. Default is unlimited.'), + + cfg.StrOpt('rpc_zmq_ipc_dir', default='/var/run/openstack', + help='Directory for holding IPC sockets'), + + cfg.StrOpt('rpc_zmq_host', default=socket.gethostname(), + help='Name of this node. Must be a valid hostname, FQDN, or ' + 'IP address. Must match "host" option, if running Nova.') +] + + +CONF = cfg.CONF +CONF.register_opts(zmq_opts) + +ZMQ_CTX = None # ZeroMQ Context, must be global. +matchmaker = None # memoized matchmaker object + + +def _serialize(data): + """ + Serialization wrapper + We prefer using JSON, but it cannot encode all types. + Error if a developer passes us bad data. + """ + try: + return jsonutils.dumps(data, ensure_ascii=True) + except TypeError: + with excutils.save_and_reraise_exception(): + LOG.error(_("JSON serialization failed.")) + + +def _deserialize(data): + """ + Deserialization wrapper + """ + LOG.debug(_("Deserializing: %s"), data) + return jsonutils.loads(data) + + +class ZmqSocket(object): + """ + A tiny wrapper around ZeroMQ to simplify the send/recv protocol + and connection management. + + Can be used as a Context (supports the 'with' statement). + """ + + def __init__(self, addr, zmq_type, bind=True, subscribe=None): + self.sock = _get_ctxt().socket(zmq_type) + self.addr = addr + self.type = zmq_type + self.subscriptions = [] + + # Support failures on sending/receiving on wrong socket type. + self.can_recv = zmq_type in (zmq.PULL, zmq.SUB) + self.can_send = zmq_type in (zmq.PUSH, zmq.PUB) + self.can_sub = zmq_type in (zmq.SUB, ) + + # Support list, str, & None for subscribe arg (cast to list) + do_sub = { + list: subscribe, + str: [subscribe], + type(None): [] + }[type(subscribe)] + + for f in do_sub: + self.subscribe(f) + + str_data = {'addr': addr, 'type': self.socket_s(), + 'subscribe': subscribe, 'bind': bind} + + LOG.debug(_("Connecting to %(addr)s with %(type)s"), str_data) + LOG.debug(_("-> Subscribed to %(subscribe)s"), str_data) + LOG.debug(_("-> bind: %(bind)s"), str_data) + + try: + if bind: + self.sock.bind(addr) + else: + self.sock.connect(addr) + except Exception: + raise RPCException(_("Could not open socket.")) + + def socket_s(self): + """Get socket type as string.""" + t_enum = ('PUSH', 'PULL', 'PUB', 'SUB', 'REP', 'REQ', 'ROUTER', + 'DEALER') + return dict(map(lambda t: (getattr(zmq, t), t), t_enum))[self.type] + + def subscribe(self, msg_filter): + """Subscribe.""" + if not self.can_sub: + raise RPCException("Cannot subscribe on this socket.") + LOG.debug(_("Subscribing to %s"), msg_filter) + + try: + self.sock.setsockopt(zmq.SUBSCRIBE, msg_filter) + except Exception: + return + + self.subscriptions.append(msg_filter) + + def unsubscribe(self, msg_filter): + """Unsubscribe.""" + if msg_filter not in self.subscriptions: + return + self.sock.setsockopt(zmq.UNSUBSCRIBE, msg_filter) + self.subscriptions.remove(msg_filter) + + def close(self): + if self.sock is None or self.sock.closed: + return + + # We must unsubscribe, or we'll leak descriptors. + if self.subscriptions: + for f in self.subscriptions: + try: + self.sock.setsockopt(zmq.UNSUBSCRIBE, f) + except Exception: + pass + self.subscriptions = [] + + try: + # Default is to linger + self.sock.close() + except Exception: + # While this is a bad thing to happen, + # it would be much worse if some of the code calling this + # were to fail. For now, lets log, and later evaluate + # if we can safely raise here. + LOG.error("ZeroMQ socket could not be closed.") + self.sock = None + + def recv(self): + if not self.can_recv: + raise RPCException(_("You cannot recv on this socket.")) + return self.sock.recv_multipart() + + def send(self, data): + if not self.can_send: + raise RPCException(_("You cannot send on this socket.")) + self.sock.send_multipart(data) + + +class ZmqClient(object): + """Client for ZMQ sockets.""" + + def __init__(self, addr, socket_type=None, bind=False): + if socket_type is None: + socket_type = zmq.PUSH + self.outq = ZmqSocket(addr, socket_type, bind=bind) + + def cast(self, msg_id, topic, data, envelope=False): + msg_id = msg_id or 0 + + if not envelope: + self.outq.send(map(bytes, + (msg_id, topic, 'cast', _serialize(data)))) + return + + rpc_envelope = rpc_common.serialize_msg(data[1], envelope) + zmq_msg = reduce(lambda x, y: x + y, rpc_envelope.items()) + self.outq.send(map(bytes, + (msg_id, topic, 'impl_zmq_v2', data[0]) + zmq_msg)) + + def close(self): + self.outq.close() + + +class RpcContext(rpc_common.CommonRpcContext): + """Context that supports replying to a rpc.call.""" + def __init__(self, **kwargs): + self.replies = [] + super(RpcContext, self).__init__(**kwargs) + + def deepcopy(self): + values = self.to_dict() + values['replies'] = self.replies + return self.__class__(**values) + + def reply(self, reply=None, failure=None, ending=False): + if ending: + return + self.replies.append(reply) + + @classmethod + def marshal(self, ctx): + ctx_data = ctx.to_dict() + return _serialize(ctx_data) + + @classmethod + def unmarshal(self, data): + return RpcContext.from_dict(_deserialize(data)) + + +class InternalContext(object): + """Used by ConsumerBase as a private context for - methods.""" + + def __init__(self, proxy): + self.proxy = proxy + self.msg_waiter = None + + def _get_response(self, ctx, proxy, topic, data): + """Process a curried message and cast the result to topic.""" + LOG.debug(_("Running func with context: %s"), ctx.to_dict()) + data.setdefault('version', None) + data.setdefault('args', {}) + + try: + result = proxy.dispatch( + ctx, data['version'], data['method'], + data.get('namespace'), **data['args']) + return ConsumerBase.normalize_reply(result, ctx.replies) + except greenlet.GreenletExit: + # ignore these since they are just from shutdowns + pass + except rpc_common.ClientException as e: + LOG.debug(_("Expected exception during message handling (%s)") % + e._exc_info[1]) + return {'exc': + rpc_common.serialize_remote_exception(e._exc_info, + log_failure=False)} + except Exception: + LOG.error(_("Exception during message handling")) + return {'exc': + rpc_common.serialize_remote_exception(sys.exc_info())} + + def reply(self, ctx, proxy, + msg_id=None, context=None, topic=None, msg=None): + """Reply to a casted call.""" + # NOTE(ewindisch): context kwarg exists for Grizzly compat. + # this may be able to be removed earlier than + # 'I' if ConsumerBase.process were refactored. + if type(msg) is list: + payload = msg[-1] + else: + payload = msg + + response = ConsumerBase.normalize_reply( + self._get_response(ctx, proxy, topic, payload), + ctx.replies) + + LOG.debug(_("Sending reply")) + _multi_send(_cast, ctx, topic, { + 'method': '-process_reply', + 'args': { + 'msg_id': msg_id, # Include for Folsom compat. + 'response': response + } + }, _msg_id=msg_id) + + +class ConsumerBase(object): + """Base Consumer.""" + + def __init__(self): + self.private_ctx = InternalContext(None) + + @classmethod + def normalize_reply(self, result, replies): + #TODO(ewindisch): re-evaluate and document this method. + if isinstance(result, types.GeneratorType): + return list(result) + elif replies: + return replies + else: + return [result] + + def process(self, proxy, ctx, data): + data.setdefault('version', None) + data.setdefault('args', {}) + + # Method starting with - are + # processed internally. (non-valid method name) + method = data.get('method') + if not method: + LOG.error(_("RPC message did not include method.")) + return + + # Internal method + # uses internal context for safety. + if method == '-reply': + self.private_ctx.reply(ctx, proxy, **data['args']) + return + + proxy.dispatch(ctx, data['version'], + data['method'], data.get('namespace'), **data['args']) + + +class ZmqBaseReactor(ConsumerBase): + """ + A consumer class implementing a + centralized casting broker (PULL-PUSH) + for RoundRobin requests. + """ + + def __init__(self, conf): + super(ZmqBaseReactor, self).__init__() + + self.mapping = {} + self.proxies = {} + self.threads = [] + self.sockets = [] + self.subscribe = {} + + self.pool = eventlet.greenpool.GreenPool(conf.rpc_thread_pool_size) + + def register(self, proxy, in_addr, zmq_type_in, out_addr=None, + zmq_type_out=None, in_bind=True, out_bind=True, + subscribe=None): + + LOG.info(_("Registering reactor")) + + if zmq_type_in not in (zmq.PULL, zmq.SUB): + raise RPCException("Bad input socktype") + + # Items push in. + inq = ZmqSocket(in_addr, zmq_type_in, bind=in_bind, + subscribe=subscribe) + + self.proxies[inq] = proxy + self.sockets.append(inq) + + LOG.info(_("In reactor registered")) + + if not out_addr: + return + + if zmq_type_out not in (zmq.PUSH, zmq.PUB): + raise RPCException("Bad output socktype") + + # Items push out. + outq = ZmqSocket(out_addr, zmq_type_out, bind=out_bind) + + self.mapping[inq] = outq + self.mapping[outq] = inq + self.sockets.append(outq) + + LOG.info(_("Out reactor registered")) + + def consume_in_thread(self): + def _consume(sock): + LOG.info(_("Consuming socket")) + while True: + self.consume(sock) + + for k in self.proxies.keys(): + self.threads.append( + self.pool.spawn(_consume, k) + ) + + def wait(self): + for t in self.threads: + t.wait() + + def close(self): + for s in self.sockets: + s.close() + + for t in self.threads: + t.kill() + + +class ZmqProxy(ZmqBaseReactor): + """ + A consumer class implementing a + topic-based proxy, forwarding to + IPC sockets. + """ + + def __init__(self, conf): + super(ZmqProxy, self).__init__(conf) + pathsep = set((os.path.sep or '', os.path.altsep or '', '/', '\\')) + self.badchars = re.compile(r'[%s]' % re.escape(''.join(pathsep))) + + self.topic_proxy = {} + + def consume(self, sock): + ipc_dir = CONF.rpc_zmq_ipc_dir + + #TODO(ewindisch): use zero-copy (i.e. references, not copying) + data = sock.recv() + topic = data[1] + + LOG.debug(_("CONSUMER GOT %s"), ' '.join(map(pformat, data))) + + if topic.startswith('fanout~'): + sock_type = zmq.PUB + topic = topic.split('.', 1)[0] + elif topic.startswith('zmq_replies'): + sock_type = zmq.PUB + else: + sock_type = zmq.PUSH + + if topic not in self.topic_proxy: + def publisher(waiter): + LOG.info(_("Creating proxy for topic: %s"), topic) + + try: + # The topic is received over the network, + # don't trust this input. + if self.badchars.search(topic) is not None: + emsg = _("Topic contained dangerous characters.") + LOG.warn(emsg) + raise RPCException(emsg) + + out_sock = ZmqSocket("ipc://%s/zmq_topic_%s" % + (ipc_dir, topic), + sock_type, bind=True) + except RPCException: + waiter.send_exception(*sys.exc_info()) + return + + self.topic_proxy[topic] = eventlet.queue.LightQueue( + CONF.rpc_zmq_topic_backlog) + self.sockets.append(out_sock) + + # It takes some time for a pub socket to open, + # before we can have any faith in doing a send() to it. + if sock_type == zmq.PUB: + eventlet.sleep(.5) + + waiter.send(True) + + while(True): + data = self.topic_proxy[topic].get() + out_sock.send(data) + LOG.debug(_("ROUTER RELAY-OUT SUCCEEDED %(data)s") % + {'data': data}) + + wait_sock_creation = eventlet.event.Event() + eventlet.spawn(publisher, wait_sock_creation) + + try: + wait_sock_creation.wait() + except RPCException: + LOG.error(_("Topic socket file creation failed.")) + return + + try: + self.topic_proxy[topic].put_nowait(data) + LOG.debug(_("ROUTER RELAY-OUT QUEUED %(data)s") % + {'data': data}) + except eventlet.queue.Full: + LOG.error(_("Local per-topic backlog buffer full for topic " + "%(topic)s. Dropping message.") % {'topic': topic}) + + def consume_in_thread(self): + """Runs the ZmqProxy service""" + ipc_dir = CONF.rpc_zmq_ipc_dir + consume_in = "tcp://%s:%s" % \ + (CONF.rpc_zmq_bind_address, + CONF.rpc_zmq_port) + consumption_proxy = InternalContext(None) + + if not os.path.isdir(ipc_dir): + try: + utils.execute('mkdir', '-p', ipc_dir, run_as_root=True) + utils.execute('chown', "%s:%s" % (os.getuid(), os.getgid()), + ipc_dir, run_as_root=True) + utils.execute('chmod', '750', ipc_dir, run_as_root=True) + except utils.ProcessExecutionError: + with excutils.save_and_reraise_exception(): + LOG.error(_("Could not create IPC directory %s") % + (ipc_dir, )) + + try: + self.register(consumption_proxy, + consume_in, + zmq.PULL, + out_bind=True) + except zmq.ZMQError: + with excutils.save_and_reraise_exception(): + LOG.error(_("Could not create ZeroMQ receiver daemon. " + "Socket may already be in use.")) + + super(ZmqProxy, self).consume_in_thread() + + +def unflatten_envelope(packenv): + """Unflattens the RPC envelope. + Takes a list and returns a dictionary. + i.e. [1,2,3,4] => {1: 2, 3: 4} + """ + i = iter(packenv) + h = {} + try: + while True: + k = i.next() + h[k] = i.next() + except StopIteration: + return h + + +class ZmqReactor(ZmqBaseReactor): + """ + A consumer class implementing a + consumer for messages. Can also be + used as a 1:1 proxy + """ + + def __init__(self, conf): + super(ZmqReactor, self).__init__(conf) + + def consume(self, sock): + #TODO(ewindisch): use zero-copy (i.e. references, not copying) + data = sock.recv() + LOG.debug(_("CONSUMER RECEIVED DATA: %s"), data) + if sock in self.mapping: + LOG.debug(_("ROUTER RELAY-OUT %(data)s") % { + 'data': data}) + self.mapping[sock].send(data) + return + + proxy = self.proxies[sock] + + if data[2] == 'cast': # Legacy protocol + packenv = data[3] + + ctx, msg = _deserialize(packenv) + request = rpc_common.deserialize_msg(msg) + ctx = RpcContext.unmarshal(ctx) + elif data[2] == 'impl_zmq_v2': + packenv = data[4:] + + msg = unflatten_envelope(packenv) + request = rpc_common.deserialize_msg(msg) + + # Unmarshal only after verifying the message. + ctx = RpcContext.unmarshal(data[3]) + else: + LOG.error(_("ZMQ Envelope version unsupported or unknown.")) + return + + self.pool.spawn_n(self.process, proxy, ctx, request) + + +class Connection(rpc_common.Connection): + """Manages connections and threads.""" + + def __init__(self, conf): + self.topics = [] + self.reactor = ZmqReactor(conf) + + def create_consumer(self, topic, proxy, fanout=False): + # Register with matchmaker. + _get_matchmaker().register(topic, CONF.rpc_zmq_host) + + # Subscription scenarios + if fanout: + sock_type = zmq.SUB + subscribe = ('', fanout)[type(fanout) == str] + topic = 'fanout~' + topic.split('.', 1)[0] + else: + sock_type = zmq.PULL + subscribe = None + topic = '.'.join((topic.split('.', 1)[0], CONF.rpc_zmq_host)) + + if topic in self.topics: + LOG.info(_("Skipping topic registration. Already registered.")) + return + + # Receive messages from (local) proxy + inaddr = "ipc://%s/zmq_topic_%s" % \ + (CONF.rpc_zmq_ipc_dir, topic) + + LOG.debug(_("Consumer is a zmq.%s"), + ['PULL', 'SUB'][sock_type == zmq.SUB]) + + self.reactor.register(proxy, inaddr, sock_type, + subscribe=subscribe, in_bind=False) + self.topics.append(topic) + + def close(self): + _get_matchmaker().stop_heartbeat() + for topic in self.topics: + _get_matchmaker().unregister(topic, CONF.rpc_zmq_host) + + self.reactor.close() + self.topics = [] + + def wait(self): + self.reactor.wait() + + def consume_in_thread(self): + _get_matchmaker().start_heartbeat() + self.reactor.consume_in_thread() + + +def _cast(addr, context, topic, msg, timeout=None, envelope=False, + _msg_id=None): + timeout_cast = timeout or CONF.rpc_cast_timeout + payload = [RpcContext.marshal(context), msg] + + with Timeout(timeout_cast, exception=rpc_common.Timeout): + try: + conn = ZmqClient(addr) + + # assumes cast can't return an exception + conn.cast(_msg_id, topic, payload, envelope) + except zmq.ZMQError: + raise RPCException("Cast failed. ZMQ Socket Exception") + finally: + if 'conn' in vars(): + conn.close() + + +def _call(addr, context, topic, msg, timeout=None, + envelope=False): + # timeout_response is how long we wait for a response + timeout = timeout or CONF.rpc_response_timeout + + # The msg_id is used to track replies. + msg_id = uuid.uuid4().hex + + # Replies always come into the reply service. + reply_topic = "zmq_replies.%s" % CONF.rpc_zmq_host + + LOG.debug(_("Creating payload")) + # Curry the original request into a reply method. + mcontext = RpcContext.marshal(context) + payload = { + 'method': '-reply', + 'args': { + 'msg_id': msg_id, + 'topic': reply_topic, + # TODO(ewindisch): safe to remove mcontext in I. + 'msg': [mcontext, msg] + } + } + + LOG.debug(_("Creating queue socket for reply waiter")) + + # Messages arriving async. + # TODO(ewindisch): have reply consumer with dynamic subscription mgmt + with Timeout(timeout, exception=rpc_common.Timeout): + try: + msg_waiter = ZmqSocket( + "ipc://%s/zmq_topic_zmq_replies.%s" % + (CONF.rpc_zmq_ipc_dir, + CONF.rpc_zmq_host), + zmq.SUB, subscribe=msg_id, bind=False + ) + + LOG.debug(_("Sending cast")) + _cast(addr, context, topic, payload, envelope) + + LOG.debug(_("Cast sent; Waiting reply")) + # Blocks until receives reply + msg = msg_waiter.recv() + LOG.debug(_("Received message: %s"), msg) + LOG.debug(_("Unpacking response")) + + if msg[2] == 'cast': # Legacy version + raw_msg = _deserialize(msg[-1])[-1] + elif msg[2] == 'impl_zmq_v2': + rpc_envelope = unflatten_envelope(msg[4:]) + raw_msg = rpc_common.deserialize_msg(rpc_envelope) + else: + raise rpc_common.UnsupportedRpcEnvelopeVersion( + _("Unsupported or unknown ZMQ envelope returned.")) + + responses = raw_msg['args']['response'] + # ZMQError trumps the Timeout error. + except zmq.ZMQError: + raise RPCException("ZMQ Socket Error") + except (IndexError, KeyError): + raise RPCException(_("RPC Message Invalid.")) + finally: + if 'msg_waiter' in vars(): + msg_waiter.close() + + # It seems we don't need to do all of the following, + # but perhaps it would be useful for multicall? + # One effect of this is that we're checking all + # responses for Exceptions. + for resp in responses: + if isinstance(resp, types.DictType) and 'exc' in resp: + raise rpc_common.deserialize_remote_exception(CONF, resp['exc']) + + return responses[-1] + + +def _multi_send(method, context, topic, msg, timeout=None, + envelope=False, _msg_id=None): + """ + Wraps the sending of messages, + dispatches to the matchmaker and sends + message to all relevant hosts. + """ + conf = CONF + LOG.debug(_("%(msg)s") % {'msg': ' '.join(map(pformat, (topic, msg)))}) + + queues = _get_matchmaker().queues(topic) + LOG.debug(_("Sending message(s) to: %s"), queues) + + # Don't stack if we have no matchmaker results + if not queues: + LOG.warn(_("No matchmaker results. Not casting.")) + # While not strictly a timeout, callers know how to handle + # this exception and a timeout isn't too big a lie. + raise rpc_common.Timeout(_("No match from matchmaker.")) + + # This supports brokerless fanout (addresses > 1) + for queue in queues: + (_topic, ip_addr) = queue + _addr = "tcp://%s:%s" % (ip_addr, conf.rpc_zmq_port) + + if method.__name__ == '_cast': + eventlet.spawn_n(method, _addr, context, + _topic, msg, timeout, envelope, + _msg_id) + return + return method(_addr, context, _topic, msg, timeout, + envelope) + + +def create_connection(conf, new=True): + return Connection(conf) + + +def multicall(conf, *args, **kwargs): + """Multiple calls.""" + return _multi_send(_call, *args, **kwargs) + + +def call(conf, *args, **kwargs): + """Send a message, expect a response.""" + data = _multi_send(_call, *args, **kwargs) + return data[-1] + + +def cast(conf, *args, **kwargs): + """Send a message expecting no reply.""" + _multi_send(_cast, *args, **kwargs) + + +def fanout_cast(conf, context, topic, msg, **kwargs): + """Send a message to all listening and expect no reply.""" + # NOTE(ewindisch): fanout~ is used because it avoid splitting on . + # and acts as a non-subtle hint to the matchmaker and ZmqProxy. + _multi_send(_cast, context, 'fanout~' + str(topic), msg, **kwargs) + + +def notify(conf, context, topic, msg, envelope): + """ + Send notification event. + Notifications are sent to topic-priority. + This differs from the AMQP drivers which send to topic.priority. + """ + # NOTE(ewindisch): dot-priority in rpc notifier does not + # work with our assumptions. + topic = topic.replace('.', '-') + cast(conf, context, topic, msg, envelope=envelope) + + +def cleanup(): + """Clean up resources in use by implementation.""" + global ZMQ_CTX + if ZMQ_CTX: + ZMQ_CTX.term() + ZMQ_CTX = None + + global matchmaker + matchmaker = None + + +def _get_ctxt(): + if not zmq: + raise ImportError("Failed to import eventlet.green.zmq") + + global ZMQ_CTX + if not ZMQ_CTX: + ZMQ_CTX = zmq.Context(CONF.rpc_zmq_contexts) + return ZMQ_CTX + + +def _get_matchmaker(*args, **kwargs): + global matchmaker + if not matchmaker: + mm = CONF.rpc_zmq_matchmaker + if mm.endswith('matchmaker.MatchMakerRing'): + mm.replace('matchmaker', 'matchmaker_ring') + LOG.warn(_('rpc_zmq_matchmaker = %(orig)s is deprecated; use' + ' %(new)s instead') % dict( + orig=CONF.rpc_zmq_matchmaker, new=mm)) + matchmaker = importutils.import_object(mm, *args, **kwargs) + return matchmaker diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker.py new file mode 100644 index 00000000..e3b56e3c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker.py @@ -0,0 +1,352 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 Cloudscaling Group, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +""" +The MatchMaker classes should except a Topic or Fanout exchange key and +return keys for direct exchanges, per (approximate) AMQP parlance. +""" + +import contextlib + +import eventlet +from oslo_config import cfg + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging + + +matchmaker_opts = [ + cfg.IntOpt('matchmaker_heartbeat_freq', + default=300, + help='Heartbeat frequency'), + cfg.IntOpt('matchmaker_heartbeat_ttl', + default=600, + help='Heartbeat time-to-live.'), +] + +CONF = cfg.CONF +CONF.register_opts(matchmaker_opts) +LOG = logging.getLogger(__name__) +contextmanager = contextlib.contextmanager + + +class MatchMakerException(Exception): + """Signified a match could not be found.""" + message = _("Match not found by MatchMaker.") + + +class Exchange(object): + """ + Implements lookups. + Subclass this to support hashtables, dns, etc. + """ + def __init__(self): + pass + + def run(self, key): + raise NotImplementedError() + + +class Binding(object): + """ + A binding on which to perform a lookup. + """ + def __init__(self): + pass + + def test(self, key): + raise NotImplementedError() + + +class MatchMakerBase(object): + """ + Match Maker Base Class. + Build off HeartbeatMatchMakerBase if building a + heartbeat-capable MatchMaker. + """ + def __init__(self): + # Array of tuples. Index [2] toggles negation, [3] is last-if-true + self.bindings = [] + + self.no_heartbeat_msg = _('Matchmaker does not implement ' + 'registration or heartbeat.') + + def register(self, key, host): + """ + Register a host on a backend. + Heartbeats, if applicable, may keepalive registration. + """ + pass + + def ack_alive(self, key, host): + """ + Acknowledge that a key.host is alive. + Used internally for updating heartbeats, + but may also be used publically to acknowledge + a system is alive (i.e. rpc message successfully + sent to host) + """ + pass + + def is_alive(self, topic, host): + """ + Checks if a host is alive. + """ + pass + + def expire(self, topic, host): + """ + Explicitly expire a host's registration. + """ + pass + + def send_heartbeats(self): + """ + Send all heartbeats. + Use start_heartbeat to spawn a heartbeat greenthread, + which loops this method. + """ + pass + + def unregister(self, key, host): + """ + Unregister a topic. + """ + pass + + def start_heartbeat(self): + """ + Spawn heartbeat greenthread. + """ + pass + + def stop_heartbeat(self): + """ + Destroys the heartbeat greenthread. + """ + pass + + def add_binding(self, binding, rule, last=True): + self.bindings.append((binding, rule, False, last)) + + #NOTE(ewindisch): kept the following method in case we implement the + # underlying support. + #def add_negate_binding(self, binding, rule, last=True): + # self.bindings.append((binding, rule, True, last)) + + def queues(self, key): + workers = [] + + # bit is for negate bindings - if we choose to implement it. + # last stops processing rules if this matches. + for (binding, exchange, bit, last) in self.bindings: + if binding.test(key): + workers.extend(exchange.run(key)) + + # Support last. + if last: + return workers + return workers + + +class HeartbeatMatchMakerBase(MatchMakerBase): + """ + Base for a heart-beat capable MatchMaker. + Provides common methods for registering, + unregistering, and maintaining heartbeats. + """ + def __init__(self): + self.hosts = set() + self._heart = None + self.host_topic = {} + + super(HeartbeatMatchMakerBase, self).__init__() + + def send_heartbeats(self): + """ + Send all heartbeats. + Use start_heartbeat to spawn a heartbeat greenthread, + which loops this method. + """ + for key, host in self.host_topic: + self.ack_alive(key, host) + + def ack_alive(self, key, host): + """ + Acknowledge that a host.topic is alive. + Used internally for updating heartbeats, + but may also be used publically to acknowledge + a system is alive (i.e. rpc message successfully + sent to host) + """ + raise NotImplementedError("Must implement ack_alive") + + def backend_register(self, key, host): + """ + Implements registration logic. + Called by register(self,key,host) + """ + raise NotImplementedError("Must implement backend_register") + + def backend_unregister(self, key, key_host): + """ + Implements de-registration logic. + Called by unregister(self,key,host) + """ + raise NotImplementedError("Must implement backend_unregister") + + def register(self, key, host): + """ + Register a host on a backend. + Heartbeats, if applicable, may keepalive registration. + """ + self.hosts.add(host) + self.host_topic[(key, host)] = host + key_host = '.'.join((key, host)) + + self.backend_register(key, key_host) + + self.ack_alive(key, host) + + def unregister(self, key, host): + """ + Unregister a topic. + """ + if (key, host) in self.host_topic: + del self.host_topic[(key, host)] + + self.hosts.discard(host) + self.backend_unregister(key, '.'.join((key, host))) + + LOG.info(_("Matchmaker unregistered: %(key)s, %(host)s"), + {'key': key, 'host': host}) + + def start_heartbeat(self): + """ + Implementation of MatchMakerBase.start_heartbeat + Launches greenthread looping send_heartbeats(), + yielding for CONF.matchmaker_heartbeat_freq seconds + between iterations. + """ + if not self.hosts: + raise MatchMakerException( + _("Register before starting heartbeat.")) + + def do_heartbeat(): + while True: + self.send_heartbeats() + eventlet.sleep(CONF.matchmaker_heartbeat_freq) + + self._heart = eventlet.spawn(do_heartbeat) + + def stop_heartbeat(self): + """ + Destroys the heartbeat greenthread. + """ + if self._heart: + self._heart.kill() + + +class DirectBinding(Binding): + """ + Specifies a host in the key via a '.' character + Although dots are used in the key, the behavior here is + that it maps directly to a host, thus direct. + """ + def test(self, key): + if '.' in key: + return True + return False + + +class TopicBinding(Binding): + """ + Where a 'bare' key without dots. + AMQP generally considers topic exchanges to be those *with* dots, + but we deviate here in terminology as the behavior here matches + that of a topic exchange (whereas where there are dots, behavior + matches that of a direct exchange. + """ + def test(self, key): + if '.' not in key: + return True + return False + + +class FanoutBinding(Binding): + """Match on fanout keys, where key starts with 'fanout.' string.""" + def test(self, key): + if key.startswith('fanout~'): + return True + return False + + +class StubExchange(Exchange): + """Exchange that does nothing.""" + def run(self, key): + return [(key, None)] + + +class LocalhostExchange(Exchange): + """Exchange where all direct topics are local.""" + def __init__(self, host='localhost'): + self.host = host + super(Exchange, self).__init__() + + def run(self, key): + return [('.'.join((key.split('.')[0], self.host)), self.host)] + + +class DirectExchange(Exchange): + """ + Exchange where all topic keys are split, sending to second half. + i.e. "compute.host" sends a message to "compute.host" running on "host" + """ + def __init__(self): + super(Exchange, self).__init__() + + def run(self, key): + e = key.split('.', 1)[1] + return [(key, e)] + + +class MatchMakerLocalhost(MatchMakerBase): + """ + Match Maker where all bare topics resolve to localhost. + Useful for testing. + """ + def __init__(self, host='localhost'): + super(MatchMakerLocalhost, self).__init__() + self.add_binding(FanoutBinding(), LocalhostExchange(host)) + self.add_binding(DirectBinding(), DirectExchange()) + self.add_binding(TopicBinding(), LocalhostExchange(host)) + + +class MatchMakerStub(MatchMakerBase): + """ + Match Maker where topics are untouched. + Useful for testing, or for AMQP/brokered queues. + Will not work where knowledge of hosts is known (i.e. zeromq) + """ + def __init__(self): + super(MatchMakerLocalhost, self).__init__() + + self.add_binding(FanoutBinding(), StubExchange()) + self.add_binding(DirectBinding(), StubExchange()) + self.add_binding(TopicBinding(), StubExchange()) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker_redis.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker_redis.py new file mode 100644 index 00000000..42e64072 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker_redis.py @@ -0,0 +1,153 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Cloudscaling Group, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +""" +The MatchMaker classes should accept a Topic or Fanout exchange key and +return keys for direct exchanges, per (approximate) AMQP parlance. +""" + +from oslo_config import cfg + +from sm_api.openstack.common import importutils +from sm_api.openstack.common import log as logging +from sm_api.openstack.common.rpc import matchmaker as mm_common + +redis = importutils.try_import('redis') + + +matchmaker_redis_opts = [ + cfg.StrOpt('host', + default='127.0.0.1', + help='Host to locate redis'), + cfg.IntOpt('port', + default=6379, + help='Use this port to connect to redis host.'), + cfg.StrOpt('password', + default=None, + help='Password for Redis server. (optional)'), +] + +CONF = cfg.CONF +opt_group = cfg.OptGroup(name='matchmaker_redis', + title='Options for Redis-based MatchMaker') +CONF.register_group(opt_group) +CONF.register_opts(matchmaker_redis_opts, opt_group) +LOG = logging.getLogger(__name__) + + +class RedisExchange(mm_common.Exchange): + def __init__(self, matchmaker): + self.matchmaker = matchmaker + self.redis = matchmaker.redis + super(RedisExchange, self).__init__() + + +class RedisTopicExchange(RedisExchange): + """ + Exchange where all topic keys are split, sending to second half. + i.e. "compute.host" sends a message to "compute" running on "host" + """ + def run(self, topic): + while True: + member_name = self.redis.srandmember(topic) + + if not member_name: + # If this happens, there are no + # longer any members. + break + + if not self.matchmaker.is_alive(topic, member_name): + continue + + host = member_name.split('.', 1)[1] + return [(member_name, host)] + return [] + + +class RedisFanoutExchange(RedisExchange): + """ + Return a list of all hosts. + """ + def run(self, topic): + topic = topic.split('~', 1)[1] + hosts = self.redis.smembers(topic) + good_hosts = filter( + lambda host: self.matchmaker.is_alive(topic, host), hosts) + + return [(x, x.split('.', 1)[1]) for x in good_hosts] + + +class MatchMakerRedis(mm_common.HeartbeatMatchMakerBase): + """ + MatchMaker registering and looking-up hosts with a Redis server. + """ + def __init__(self): + super(MatchMakerRedis, self).__init__() + + if not redis: + raise ImportError("Failed to import module redis.") + + self.redis = redis.StrictRedis( + host=CONF.matchmaker_redis.host, + port=CONF.matchmaker_redis.port, + password=CONF.matchmaker_redis.password) + + self.add_binding(mm_common.FanoutBinding(), RedisFanoutExchange(self)) + self.add_binding(mm_common.DirectBinding(), mm_common.DirectExchange()) + self.add_binding(mm_common.TopicBinding(), RedisTopicExchange(self)) + + def ack_alive(self, key, host): + topic = "%s.%s" % (key, host) + if not self.redis.expire(topic, CONF.matchmaker_heartbeat_ttl): + # If we could not update the expiration, the key + # might have been pruned. Re-register, creating a new + # key in Redis. + self.register(self.topic_host[host], host) + + def is_alive(self, topic, host): + if self.redis.ttl(host) == -1: + self.expire(topic, host) + return False + return True + + def expire(self, topic, host): + with self.redis.pipeline() as pipe: + pipe.multi() + pipe.delete(host) + pipe.srem(topic, host) + pipe.execute() + + def backend_register(self, key, key_host): + with self.redis.pipeline() as pipe: + pipe.multi() + pipe.sadd(key, key_host) + + # No value is needed, we just + # care if it exists. Sets aren't viable + # because only keys can expire. + pipe.set(key_host, '') + + pipe.execute() + + def backend_unregister(self, key, key_host): + with self.redis.pipeline() as pipe: + pipe.multi() + pipe.srem(key, key_host) + pipe.delete(key_host) + pipe.execute() diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker_ring.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker_ring.py new file mode 100644 index 00000000..d92ac044 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/matchmaker_ring.py @@ -0,0 +1,118 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011-2013 Cloudscaling Group, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +""" +The MatchMaker classes should except a Topic or Fanout exchange key and +return keys for direct exchanges, per (approximate) AMQP parlance. +""" + +import itertools +import json + +from oslo_config import cfg + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging +from sm_api.openstack.common.rpc import matchmaker as mm + + +matchmaker_opts = [ + # Matchmaker ring file + cfg.StrOpt('ringfile', + deprecated_name='matchmaker_ringfile', + deprecated_group='DEFAULT', + default='/etc/oslo/matchmaker_ring.json', + help='Matchmaker ring file (JSON)'), +] + +CONF = cfg.CONF +CONF.register_opts(matchmaker_opts, 'matchmaker_ring') +LOG = logging.getLogger(__name__) + + +class RingExchange(mm.Exchange): + """ + Match Maker where hosts are loaded from a static file containing + a hashmap (JSON formatted). + + __init__ takes optional ring dictionary argument, otherwise + loads the ringfile from CONF.mathcmaker_ringfile. + """ + def __init__(self, ring=None): + super(RingExchange, self).__init__() + + if ring: + self.ring = ring + else: + fh = open(CONF.matchmaker_ring.ringfile, 'r') + self.ring = json.load(fh) + fh.close() + + self.ring0 = {} + for k in self.ring.keys(): + self.ring0[k] = itertools.cycle(self.ring[k]) + + def _ring_has(self, key): + if key in self.ring0: + return True + return False + + +class RoundRobinRingExchange(RingExchange): + """A Topic Exchange based on a hashmap.""" + def __init__(self, ring=None): + super(RoundRobinRingExchange, self).__init__(ring) + + def run(self, key): + if not self._ring_has(key): + LOG.warn( + _("No key defining hosts for topic '%s', " + "see ringfile") % (key, ) + ) + return [] + host = next(self.ring0[key]) + return [(key + '.' + host, host)] + + +class FanoutRingExchange(RingExchange): + """Fanout Exchange based on a hashmap.""" + def __init__(self, ring=None): + super(FanoutRingExchange, self).__init__(ring) + + def run(self, key): + # Assume starts with "fanout~", strip it for lookup. + nkey = key.split('fanout~')[1:][0] + if not self._ring_has(nkey): + LOG.warn( + _("No key defining hosts for topic '%s', " + "see ringfile") % (nkey, ) + ) + return [] + return map(lambda x: (key + '.' + x, x), self.ring[nkey]) + + +class MatchMakerRing(mm.MatchMakerBase): + """ + Match Maker where hosts are loaded from a static hashmap. + """ + def __init__(self, ring=None): + super(MatchMakerRing, self).__init__() + self.add_binding(mm.FanoutBinding(), FanoutRingExchange(ring)) + self.add_binding(mm.DirectBinding(), mm.DirectExchange()) + self.add_binding(mm.TopicBinding(), RoundRobinRingExchange(ring)) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/proxy.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/proxy.py new file mode 100644 index 00000000..156728cc --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/proxy.py @@ -0,0 +1,227 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012-2013 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +A helper class for proxy objects to remote APIs. + +For more information about rpc API version numbers, see: + rpc/dispatcher.py +""" + + +from sm_api.openstack.common import rpc +from sm_api.openstack.common.rpc import common as rpc_common +from sm_api.openstack.common.rpc import serializer as rpc_serializer + + +class RpcProxy(object): + """A helper class for rpc clients. + + This class is a wrapper around the RPC client API. It allows you to + specify the topic and API version in a single place. This is intended to + be used as a base class for a class that implements the client side of an + rpc API. + """ + + # The default namespace, which can be overriden in a subclass. + RPC_API_NAMESPACE = None + + def __init__(self, topic, default_version, version_cap=None, + serializer=None): + """Initialize an RpcProxy. + + :param topic: The topic to use for all messages. + :param default_version: The default API version to request in all + outgoing messages. This can be overridden on a per-message + basis. + :param version_cap: Optionally cap the maximum version used for sent + messages. + :param serializer: Optionaly (de-)serialize entities with a + provided helper. + """ + self.topic = topic + self.default_version = default_version + self.version_cap = version_cap + if serializer is None: + serializer = rpc_serializer.NoOpSerializer() + self.serializer = serializer + super(RpcProxy, self).__init__() + + def _set_version(self, msg, vers): + """Helper method to set the version in a message. + + :param msg: The message having a version added to it. + :param vers: The version number to add to the message. + """ + v = vers if vers else self.default_version + if (self.version_cap and not + rpc_common.version_is_compatible(self.version_cap, v)): + raise rpc_common.RpcVersionCapError(version=self.version_cap) + msg['version'] = v + + def _get_topic(self, topic): + """Return the topic to use for a message.""" + return topic if topic else self.topic + + @staticmethod + def make_namespaced_msg(method, namespace, **kwargs): + return {'method': method, 'namespace': namespace, 'args': kwargs} + + def make_msg(self, method, **kwargs): + return self.make_namespaced_msg(method, self.RPC_API_NAMESPACE, + **kwargs) + + def _serialize_msg_args(self, context, kwargs): + """Helper method called to serialize message arguments. + + This calls our serializer on each argument, returning a new + set of args that have been serialized. + + :param context: The request context + :param kwargs: The arguments to serialize + :returns: A new set of serialized arguments + """ + new_kwargs = dict() + for argname, arg in kwargs.iteritems(): + new_kwargs[argname] = self.serializer.serialize_entity(context, + arg) + return new_kwargs + + def call(self, context, msg, topic=None, version=None, timeout=None): + """rpc.call() a remote method. + + :param context: The request context + :param msg: The message to send, including the method and args. + :param topic: Override the topic for this message. + :param version: (Optional) Override the requested API version in this + message. + :param timeout: (Optional) A timeout to use when waiting for the + response. If no timeout is specified, a default timeout will be + used that is usually sufficient. + + :returns: The return value from the remote method. + """ + self._set_version(msg, version) + msg['args'] = self._serialize_msg_args(context, msg['args']) + real_topic = self._get_topic(topic) + try: + result = rpc.call(context, real_topic, msg, timeout) + return self.serializer.deserialize_entity(context, result) + except rpc.common.Timeout as exc: + rpc.cleanup() + raise rpc.common.Timeout( + exc.info, real_topic, msg.get('method')) + + def multicall(self, context, msg, topic=None, version=None, timeout=None): + """rpc.multicall() a remote method. + + :param context: The request context + :param msg: The message to send, including the method and args. + :param topic: Override the topic for this message. + :param version: (Optional) Override the requested API version in this + message. + :param timeout: (Optional) A timeout to use when waiting for the + response. If no timeout is specified, a default timeout will be + used that is usually sufficient. + + :returns: An iterator that lets you process each of the returned values + from the remote method as they arrive. + """ + self._set_version(msg, version) + msg['args'] = self._serialize_msg_args(context, msg['args']) + real_topic = self._get_topic(topic) + try: + result = rpc.multicall(context, real_topic, msg, timeout) + return self.serializer.deserialize_entity(context, result) + except rpc.common.Timeout as exc: + rpc.cleanup() + raise rpc.common.Timeout( + exc.info, real_topic, msg.get('method')) + + def cast(self, context, msg, topic=None, version=None): + """rpc.cast() a remote method. + + :param context: The request context + :param msg: The message to send, including the method and args. + :param topic: Override the topic for this message. + :param version: (Optional) Override the requested API version in this + message. + + :returns: None. rpc.cast() does not wait on any return value from the + remote method. + """ + self._set_version(msg, version) + msg['args'] = self._serialize_msg_args(context, msg['args']) + rpc.cast(context, self._get_topic(topic), msg) + + def fanout_cast(self, context, msg, topic=None, version=None): + """rpc.fanout_cast() a remote method. + + :param context: The request context + :param msg: The message to send, including the method and args. + :param topic: Override the topic for this message. + :param version: (Optional) Override the requested API version in this + message. + + :returns: None. rpc.fanout_cast() does not wait on any return value + from the remote method. + """ + self._set_version(msg, version) + msg['args'] = self._serialize_msg_args(context, msg['args']) + rpc.fanout_cast(context, self._get_topic(topic), msg) + + def cast_to_server(self, context, server_params, msg, topic=None, + version=None): + """rpc.cast_to_server() a remote method. + + :param context: The request context + :param server_params: Server parameters. See rpc.cast_to_server() for + details. + :param msg: The message to send, including the method and args. + :param topic: Override the topic for this message. + :param version: (Optional) Override the requested API version in this + message. + + :returns: None. rpc.cast_to_server() does not wait on any + return values. + """ + self._set_version(msg, version) + msg['args'] = self._serialize_msg_args(context, msg['args']) + rpc.cast_to_server(context, server_params, self._get_topic(topic), msg) + + def fanout_cast_to_server(self, context, server_params, msg, topic=None, + version=None): + """rpc.fanout_cast_to_server() a remote method. + + :param context: The request context + :param server_params: Server parameters. See rpc.cast_to_server() for + details. + :param msg: The message to send, including the method and args. + :param topic: Override the topic for this message. + :param version: (Optional) Override the requested API version in this + message. + + :returns: None. rpc.fanout_cast_to_server() does not wait on any + return values. + """ + self._set_version(msg, version) + msg['args'] = self._serialize_msg_args(context, msg['args']) + rpc.fanout_cast_to_server(context, server_params, + self._get_topic(topic), msg) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/serializer.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/serializer.py new file mode 100644 index 00000000..3f23de2c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/serializer.py @@ -0,0 +1,56 @@ +# Copyright 2013 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Provides the definition of an RPC serialization handler""" + +import abc + + +class Serializer(object): + """Generic (de-)serialization definition base class""" + __metaclass__ = abc.ABCMeta + + @abc.abstractmethod + def serialize_entity(self, context, entity): + """Serialize something to primitive form. + + :param context: Security context + :param entity: Entity to be serialized + :returns: Serialized form of entity + """ + pass + + @abc.abstractmethod + def deserialize_entity(self, context, entity): + """Deserialize something from primitive form. + + :param context: Security context + :param entity: Primitive to be deserialized + :returns: Deserialized form of entity + """ + pass + + +class NoOpSerializer(Serializer): + """A serializer that does nothing""" + + def serialize_entity(self, context, entity): + return entity + + def deserialize_entity(self, context, entity): + return entity diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/service.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/service.py new file mode 100644 index 00000000..8052455c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/service.py @@ -0,0 +1,81 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# Copyright 2011 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_api.openstack.common.gettextutils import _ +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import rpc +from sm_api.openstack.common.rpc import dispatcher as rpc_dispatcher +from sm_api.openstack.common import service + + +LOG = logging.getLogger(__name__) + + +class Service(service.Service): + """Service object for binaries running on hosts. + + A service enables rpc by listening to queues based on topic and host.""" + def __init__(self, host, topic, manager=None, serializer=None): + super(Service, self).__init__() + self.host = host + self.topic = topic + self.serializer = serializer + if manager is None: + self.manager = self + else: + self.manager = manager + + def start(self): + super(Service, self).start() + + self.conn = rpc.create_connection(new=True) + LOG.debug(_("Creating Consumer connection for Service %s") % + self.topic) + + dispatcher = rpc_dispatcher.RpcDispatcher([self.manager], + self.serializer) + + # Share this same connection for these Consumers + self.conn.create_consumer(self.topic, dispatcher, fanout=False) + + node_topic = '%s.%s' % (self.topic, self.host) + self.conn.create_consumer(node_topic, dispatcher, fanout=False) + + self.conn.create_consumer(self.topic, dispatcher, fanout=True) + + # Hook to allow the manager to do other initializations after + # the rpc connection is created. + if callable(getattr(self.manager, 'initialize_service_hook', None)): + self.manager.initialize_service_hook(self) + + # Consume from all consumers in a thread + self.conn.consume_in_thread() + + def stop(self): + # Try to shut the connection down, but if we get any sort of + # errors, go ahead and ignore them.. as we're shutting down anyway + try: + self.conn.close() + except Exception: + pass + super(Service, self).stop() diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/zmq_receiver.py b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/zmq_receiver.py new file mode 100755 index 00000000..f6fdbc5e --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/rpc/zmq_receiver.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import eventlet +eventlet.monkey_patch() + +import contextlib +import sys + +from oslo_config import cfg + +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import rpc +from sm_api.openstack.common.rpc import impl_zmq + +CONF = cfg.CONF +CONF.register_opts(rpc.rpc_opts) +CONF.register_opts(impl_zmq.zmq_opts) + + +def main(): + CONF(sys.argv[1:], project='oslo') + logging.setup("oslo") + + with contextlib.closing(impl_zmq.ZmqProxy(CONF)) as reactor: + reactor.consume_in_thread() + reactor.wait() diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/service.py b/service-mgmt-api/sm-api/sm_api/openstack/common/service.py new file mode 100644 index 00000000..6518fc50 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/service.py @@ -0,0 +1,465 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2010 United States Government as represented by the +# Administrator of the National Aeronautics and Space Administration. +# Copyright 2011 Justin Santa Barbara +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Generic Node base class for all workers that run on hosts.""" + +import errno +import logging as std_logging +import os +import random +import signal +import sys +import time + +import eventlet +from eventlet import event +from oslo_config import cfg + +from sm_api.openstack.common import eventlet_backdoor +from sm_api.openstack.common.gettextutils import _ # noqa +from sm_api.openstack.common import importutils +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import threadgroup + + +rpc = importutils.try_import('sm_api.openstack.common.rpc') +CONF = cfg.CONF +LOG = logging.getLogger(__name__) + + +def _sighup_supported(): + return hasattr(signal, 'SIGHUP') + + +def _is_sighup(signo): + return _sighup_supported() and signo == signal.SIGHUP + + +def _signo_to_signame(signo): + signals = {signal.SIGTERM: 'SIGTERM', + signal.SIGINT: 'SIGINT'} + if _sighup_supported(): + signals[signal.SIGHUP] = 'SIGHUP' + return signals[signo] + + +def _set_signals_handler(handler): + signal.signal(signal.SIGTERM, handler) + signal.signal(signal.SIGINT, handler) + if _sighup_supported(): + signal.signal(signal.SIGHUP, handler) + + +class Launcher(object): + """Launch one or more services and wait for them to complete.""" + + def __init__(self): + """Initialize the service launcher. + + :returns: None + + """ + self.services = Services() + self.backdoor_port = eventlet_backdoor.initialize_if_enabled() + + def launch_service(self, service): + """Load and start the given service. + + :param service: The service you would like to start. + :returns: None + + """ + service.backdoor_port = self.backdoor_port + self.services.add(service) + + def stop(self): + """Stop all services which are currently running. + + :returns: None + + """ + self.services.stop() + + def wait(self): + """Waits until all services have been stopped, and then returns. + + :returns: None + + """ + self.services.wait() + + def restart(self): + """Reload config files and restart service. + + :returns: None + + """ + cfg.CONF.reload_config_files() + self.services.restart() + + +class SignalExit(SystemExit): + def __init__(self, signo, exccode=1): + super(SignalExit, self).__init__(exccode) + self.signo = signo + + +class ServiceLauncher(Launcher): + def _handle_signal(self, signo, frame): + # Allow the process to be killed again and die from natural causes + _set_signals_handler(signal.SIG_DFL) + raise SignalExit(signo) + + def handle_signal(self): + _set_signals_handler(self._handle_signal) + + def _wait_for_exit_or_signal(self, ready_callback=None): + status = None + signo = 0 + + LOG.debug(_('Full set of CONF:')) + CONF.log_opt_values(LOG, std_logging.DEBUG) + + try: + if ready_callback: + ready_callback() + super(ServiceLauncher, self).wait() + except SignalExit as exc: + signame = _signo_to_signame(exc.signo) + LOG.info(_('Caught %s, exiting'), signame) + status = exc.code + signo = exc.signo + except SystemExit as exc: + status = exc.code + finally: + self.stop() + if rpc: + try: + rpc.cleanup() + except Exception: + # We're shutting down, so it doesn't matter at this point. + LOG.exception(_('Exception during rpc cleanup.')) + + return status, signo + + def wait(self, ready_callback=None): + while True: + self.handle_signal() + status, signo = self._wait_for_exit_or_signal(ready_callback) + if not _is_sighup(signo): + return status + self.restart() + + +class ServiceWrapper(object): + def __init__(self, service, workers): + self.service = service + self.workers = workers + self.children = set() + self.forktimes = [] + + +class ProcessLauncher(object): + def __init__(self): + self.children = {} + self.sigcaught = None + self.running = True + rfd, self.writepipe = os.pipe() + self.readpipe = eventlet.greenio.GreenPipe(rfd, 'r') + self.handle_signal() + + def handle_signal(self): + _set_signals_handler(self._handle_signal) + + def _handle_signal(self, signo, frame): + self.sigcaught = signo + self.running = False + + # Allow the process to be killed again and die from natural causes + _set_signals_handler(signal.SIG_DFL) + + def _pipe_watcher(self): + # This will block until the write end is closed when the parent + # dies unexpectedly + self.readpipe.read() + + LOG.info(_('Parent process has died unexpectedly, exiting')) + + sys.exit(1) + + def _child_process_handle_signal(self): + # Setup child signal handlers differently + def _sigterm(*args): + signal.signal(signal.SIGTERM, signal.SIG_DFL) + raise SignalExit(signal.SIGTERM) + + def _sighup(*args): + signal.signal(signal.SIGHUP, signal.SIG_DFL) + raise SignalExit(signal.SIGHUP) + + signal.signal(signal.SIGTERM, _sigterm) + if _sighup_supported(): + signal.signal(signal.SIGHUP, _sighup) + # Block SIGINT and let the parent send us a SIGTERM + signal.signal(signal.SIGINT, signal.SIG_IGN) + + def _child_wait_for_exit_or_signal(self, launcher): + status = None + signo = 0 + + # NOTE(johannes): All exceptions are caught to ensure this + # doesn't fallback into the loop spawning children. It would + # be bad for a child to spawn more children. + try: + launcher.wait() + except SignalExit as exc: + signame = _signo_to_signame(exc.signo) + LOG.info(_('Caught %s, exiting'), signame) + status = exc.code + signo = exc.signo + except SystemExit as exc: + status = exc.code + except BaseException: + LOG.exception(_('Unhandled exception')) + status = 2 + finally: + launcher.stop() + + return status, signo + + def _child_process(self, service): + self._child_process_handle_signal() + + # Reopen the eventlet hub to make sure we don't share an epoll + # fd with parent and/or siblings, which would be bad + eventlet.hubs.use_hub() + + # Close write to ensure only parent has it open + os.close(self.writepipe) + # Create greenthread to watch for parent to close pipe + eventlet.spawn_n(self._pipe_watcher) + + # Reseed random number generator + random.seed() + + launcher = Launcher() + launcher.launch_service(service) + return launcher + + def _start_child(self, wrap): + if len(wrap.forktimes) > wrap.workers: + # Limit ourselves to one process a second (over the period of + # number of workers * 1 second). This will allow workers to + # start up quickly but ensure we don't fork off children that + # die instantly too quickly. + if time.time() - wrap.forktimes[0] < wrap.workers: + LOG.info(_('Forking too fast, sleeping')) + time.sleep(1) + + wrap.forktimes.pop(0) + + wrap.forktimes.append(time.time()) + + pid = os.fork() + if pid == 0: + launcher = self._child_process(wrap.service) + while True: + self._child_process_handle_signal() + status, signo = self._child_wait_for_exit_or_signal(launcher) + if not _is_sighup(signo): + break + launcher.restart() + + os._exit(status) + + LOG.info(_('Started child %d'), pid) + + wrap.children.add(pid) + self.children[pid] = wrap + + return pid + + def launch_service(self, service, workers=1): + wrap = ServiceWrapper(service, workers) + + LOG.info(_('Starting %d workers'), wrap.workers) + while self.running and len(wrap.children) < wrap.workers: + self._start_child(wrap) + + def _wait_child(self): + try: + # Don't block if no child processes have exited + pid, status = os.waitpid(0, os.WNOHANG) + if not pid: + return None + except OSError as exc: + if exc.errno not in (errno.EINTR, errno.ECHILD): + raise + return None + + if os.WIFSIGNALED(status): + sig = os.WTERMSIG(status) + LOG.info(_('Child %(pid)d killed by signal %(sig)d'), + dict(pid=pid, sig=sig)) + else: + code = os.WEXITSTATUS(status) + LOG.info(_('Child %(pid)s exited with status %(code)d'), + dict(pid=pid, code=code)) + + if pid not in self.children: + LOG.warning(_('pid %d not in child list'), pid) + return None + + wrap = self.children.pop(pid) + wrap.children.remove(pid) + return wrap + + def _respawn_children(self): + while self.running: + wrap = self._wait_child() + if not wrap: + # Yield to other threads if no children have exited + # Sleep for a short time to avoid excessive CPU usage + # (see bug #1095346) + eventlet.greenthread.sleep(.01) + continue + while self.running and len(wrap.children) < wrap.workers: + self._start_child(wrap) + + def wait(self): + """Loop waiting on children to die and respawning as necessary.""" + + LOG.debug(_('Full set of CONF:')) + CONF.log_opt_values(LOG, std_logging.DEBUG) + + while True: + self.handle_signal() + self._respawn_children() + if self.sigcaught: + signame = _signo_to_signame(self.sigcaught) + LOG.info(_('Caught %s, stopping children'), signame) + if not _is_sighup(self.sigcaught): + break + + for pid in self.children: + os.kill(pid, signal.SIGHUP) + self.running = True + self.sigcaught = None + + for pid in self.children: + try: + os.kill(pid, signal.SIGTERM) + except OSError as exc: + if exc.errno != errno.ESRCH: + raise + + # Wait for children to die + if self.children: + LOG.info(_('Waiting on %d children to exit'), len(self.children)) + while self.children: + self._wait_child() + + +class Service(object): + """Service object for binaries running on hosts.""" + + def __init__(self, threads=1000): + self.tg = threadgroup.ThreadGroup(threads) + + # signal that the service is done shutting itself down: + self._done = event.Event() + + def reset(self): + # NOTE(Fengqian): docs for Event.reset() recommend against using it + self._done = event.Event() + + def start(self): + pass + + def stop(self): + self.tg.stop() + self.tg.wait() + # Signal that service cleanup is done: + if not self._done.ready(): + self._done.send() + + def wait(self): + self._done.wait() + + +class Services(object): + + def __init__(self): + self.services = [] + self.tg = threadgroup.ThreadGroup() + self.done = event.Event() + + def add(self, service): + self.services.append(service) + self.tg.add_thread(self.run_service, service, self.done) + + def stop(self): + # wait for graceful shutdown of services: + for service in self.services: + service.stop() + service.wait() + + # Each service has performed cleanup, now signal that the run_service + # wrapper threads can now die: + if not self.done.ready(): + self.done.send() + + # reap threads: + self.tg.stop() + + def wait(self): + self.tg.wait() + + def restart(self): + self.stop() + self.done = event.Event() + for restart_service in self.services: + restart_service.reset() + self.tg.add_thread(self.run_service, restart_service, self.done) + + @staticmethod + def run_service(service, done): + """Service start wrapper. + + :param service: service to run + :param done: event to wait on until a shutdown is triggered + :returns: None + + """ + service.start() + done.wait() + + +def launch(service, workers=None): + if workers: + launcher = ProcessLauncher() + launcher.launch_service(service, workers=workers) + else: + launcher = ServiceLauncher() + launcher.launch_service(service) + return launcher diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/setup.py b/service-mgmt-api/sm-api/sm_api/openstack/common/setup.py new file mode 100644 index 00000000..137fa71f --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/setup.py @@ -0,0 +1,371 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# Copyright 2012-2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Utilities with minimum-depends for use in setup.py +""" + +from __future__ import print_function + +import email +import os +import re +import subprocess +import sys + +from setuptools.command import sdist + + +def parse_mailmap(mailmap='.mailmap'): + mapping = {} + if os.path.exists(mailmap): + with open(mailmap, 'r') as fp: + for l in fp: + try: + canonical_email, alias = re.match( + r'[^#]*?(<.+>).*(<.+>).*', l).groups() + except AttributeError: + continue + mapping[alias] = canonical_email + return mapping + + +def _parse_git_mailmap(git_dir, mailmap='.mailmap'): + mailmap = os.path.join(os.path.dirname(git_dir), mailmap) + return parse_mailmap(mailmap) + + +def canonicalize_emails(changelog, mapping): + """Takes in a string and an email alias mapping and replaces all + instances of the aliases in the string with their real email. + """ + for alias, email_address in mapping.iteritems(): + changelog = changelog.replace(alias, email_address) + return changelog + + +# Get requirements from the first file that exists +def get_reqs_from_files(requirements_files): + for requirements_file in requirements_files: + if os.path.exists(requirements_file): + with open(requirements_file, 'r') as fil: + return fil.read().split('\n') + return [] + + +def parse_requirements(requirements_files=['requirements.txt', + 'tools/pip-requires']): + requirements = [] + for line in get_reqs_from_files(requirements_files): + # For the requirements list, we need to inject only the portion + # after egg= so that distutils knows the package it's looking for + # such as: + # -e git://github.com/openstack/nova/master#egg=nova + if re.match(r'\s*-e\s+', line): + requirements.append(re.sub(r'\s*-e\s+.*#egg=(.*)$', r'\1', + line)) + # such as: + # http://github.com/openstack/nova/zipball/master#egg=nova + elif re.match(r'\s*https?:', line): + requirements.append(re.sub(r'\s*https?:.*#egg=(.*)$', r'\1', + line)) + # -f lines are for index locations, and don't get used here + elif re.match(r'\s*-f\s+', line): + pass + # argparse is part of the standard library starting with 2.7 + # adding it to the requirements list screws distro installs + elif line == 'argparse' and sys.version_info >= (2, 7): + pass + else: + requirements.append(line) + + return requirements + + +def parse_dependency_links(requirements_files=['requirements.txt', + 'tools/pip-requires']): + dependency_links = [] + # dependency_links inject alternate locations to find packages listed + # in requirements + for line in get_reqs_from_files(requirements_files): + # skip comments and blank lines + if re.match(r'(\s*#)|(\s*$)', line): + continue + # lines with -e or -f need the whole line, minus the flag + if re.match(r'\s*-[ef]\s+', line): + dependency_links.append(re.sub(r'\s*-[ef]\s+', '', line)) + # lines that are only urls can go in unmolested + elif re.match(r'\s*https?:', line): + dependency_links.append(line) + return dependency_links + + +def _run_shell_command(cmd, throw_on_error=False): + if os.name == 'nt': + output = subprocess.Popen(["cmd.exe", "/C", cmd], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + else: + output = subprocess.Popen(["/bin/sh", "-c", cmd], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + out = output.communicate() + if output.returncode and throw_on_error: + raise Exception("%s returned %d" % cmd, output.returncode) + if not out: + return None + return out[0].strip() or None + + +def _get_git_directory(): + parent_dir = os.path.dirname(__file__) + while True: + git_dir = os.path.join(parent_dir, '.git') + if os.path.exists(git_dir): + return git_dir + parent_dir, child = os.path.split(parent_dir) + if not child: # reached to root dir + return None + + +def write_git_changelog(): + """Write a changelog based on the git changelog.""" + new_changelog = 'ChangeLog' + git_dir = _get_git_directory() + if not os.getenv('SKIP_WRITE_GIT_CHANGELOG'): + if git_dir: + git_log_cmd = 'git --git-dir=%s log' % git_dir + changelog = _run_shell_command(git_log_cmd) + mailmap = _parse_git_mailmap(git_dir) + with open(new_changelog, "w") as changelog_file: + changelog_file.write(canonicalize_emails(changelog, mailmap)) + else: + open(new_changelog, 'w').close() + + +def generate_authors(): + """Create AUTHORS file using git commits.""" + jenkins_email = 'jenkins@review.(openstack|stackforge).org' + old_authors = 'AUTHORS.in' + new_authors = 'AUTHORS' + git_dir = _get_git_directory() + if not os.getenv('SKIP_GENERATE_AUTHORS'): + if git_dir: + # don't include jenkins email address in AUTHORS file + git_log_cmd = ("git --git-dir=" + git_dir + + " log --format='%aN <%aE>' | sort -u | " + "egrep -v '" + jenkins_email + "'") + changelog = _run_shell_command(git_log_cmd) + signed_cmd = ("git --git-dir=" + git_dir + + " log | grep -i Co-authored-by: | sort -u") + signed_entries = _run_shell_command(signed_cmd) + if signed_entries: + new_entries = "\n".join( + [signed.split(":", 1)[1].strip() + for signed in signed_entries.split("\n") if signed]) + changelog = "\n".join((changelog, new_entries)) + mailmap = _parse_git_mailmap(git_dir) + with open(new_authors, 'w') as new_authors_fh: + new_authors_fh.write(canonicalize_emails(changelog, mailmap)) + if os.path.exists(old_authors): + with open(old_authors, "r") as old_authors_fh: + new_authors_fh.write('\n' + old_authors_fh.read()) + else: + open(new_authors, 'w').close() + + +_rst_template = """%(heading)s +%(underline)s + +.. automodule:: %(module)s + :members: + :undoc-members: + :show-inheritance: +""" + + +def get_cmdclass(): + """Return dict of commands to run from setup.py.""" + + cmdclass = dict() + + def _find_modules(arg, dirname, files): + for filename in files: + if filename.endswith('.py') and filename != '__init__.py': + arg["%s.%s" % (dirname.replace('/', '.'), + filename[:-3])] = True + + class LocalSDist(sdist.sdist): + """Builds the ChangeLog and Authors files from VC first.""" + + def run(self): + write_git_changelog() + generate_authors() + # sdist.sdist is an old style class, can't use super() + sdist.sdist.run(self) + + cmdclass['sdist'] = LocalSDist + + # If Sphinx is installed on the box running setup.py, + # enable setup.py to build the documentation, otherwise, + # just ignore it + try: + from sphinx.setup_command import BuildDoc + + class LocalBuildDoc(BuildDoc): + + builders = ['html', 'man'] + + def generate_autoindex(self): + print("**Autodocumenting from %s" % os.path.abspath(os.curdir)) + modules = {} + option_dict = self.distribution.get_option_dict('build_sphinx') + source_dir = os.path.join(option_dict['source_dir'][1], 'api') + if not os.path.exists(source_dir): + os.makedirs(source_dir) + for pkg in self.distribution.packages: + if '.' not in pkg: + os.path.walk(pkg, _find_modules, modules) + module_list = modules.keys() + module_list.sort() + autoindex_filename = os.path.join(source_dir, 'autoindex.rst') + with open(autoindex_filename, 'w') as autoindex: + autoindex.write(""".. toctree:: + :maxdepth: 1 + +""") + for module in module_list: + output_filename = os.path.join(source_dir, + "%s.rst" % module) + heading = "The :mod:`%s` Module" % module + underline = "=" * len(heading) + values = dict(module=module, heading=heading, + underline=underline) + + print("Generating %s" % output_filename) + with open(output_filename, 'w') as output_file: + output_file.write(_rst_template % values) + autoindex.write(" %s.rst\n" % module) + + def run(self): + if not os.getenv('SPHINX_DEBUG'): + self.generate_autoindex() + + for builder in self.builders: + self.builder = builder + self.finalize_options() + self.project = self.distribution.get_name() + self.version = self.distribution.get_version() + self.release = self.distribution.get_version() + BuildDoc.run(self) + + class LocalBuildLatex(LocalBuildDoc): + builders = ['latex'] + + cmdclass['build_sphinx'] = LocalBuildDoc + cmdclass['build_sphinx_latex'] = LocalBuildLatex + except ImportError: + pass + + return cmdclass + + +def _get_revno(git_dir): + """Return the number of commits since the most recent tag. + + We use git-describe to find this out, but if there are no + tags then we fall back to counting commits since the beginning + of time. + """ + describe = _run_shell_command( + "git --git-dir=%s describe --always" % git_dir) + if "-" in describe: + return describe.rsplit("-", 2)[-2] + + # no tags found + revlist = _run_shell_command( + "git --git-dir=%s rev-list --abbrev-commit HEAD" % git_dir) + return len(revlist.splitlines()) + + +def _get_version_from_git(pre_version): + """Return a version which is equal to the tag that's on the current + revision if there is one, or tag plus number of additional revisions + if the current revision has no tag.""" + + git_dir = _get_git_directory() + if git_dir: + if pre_version: + try: + return _run_shell_command( + "git --git-dir=" + git_dir + " describe --exact-match", + throw_on_error=True).replace('-', '.') + except Exception: + sha = _run_shell_command( + "git --git-dir=" + git_dir + " log -n1 --pretty=format:%h") + return "%s.a%s.g%s" % (pre_version, _get_revno(git_dir), sha) + else: + return _run_shell_command( + "git --git-dir=" + git_dir + " describe --always").replace( + '-', '.') + return None + + +def _get_version_from_pkg_info(package_name): + """Get the version from PKG-INFO file if we can.""" + try: + pkg_info_file = open('PKG-INFO', 'r') + except (IOError, OSError): + return None + try: + pkg_info = email.message_from_file(pkg_info_file) + except email.MessageError: + return None + # Check to make sure we're in our own dir + if pkg_info.get('Name', None) != package_name: + return None + return pkg_info.get('Version', None) + + +def get_version(package_name, pre_version=None): + """Get the version of the project. First, try getting it from PKG-INFO, if + it exists. If it does, that means we're in a distribution tarball or that + install has happened. Otherwise, if there is no PKG-INFO file, pull the + version from git. + + We do not support setup.py version sanity in git archive tarballs, nor do + we support packagers directly sucking our git repo into theirs. We expect + that a source tarball be made from our git repo - or that if someone wants + to make a source tarball from a fork of our repo with additional tags in it + that they understand and desire the results of doing that. + """ + version = os.environ.get("OSLO_PACKAGE_VERSION", None) + if version: + return version + version = _get_version_from_pkg_info(package_name) + if version: + return version + version = _get_version_from_git(pre_version) + if version: + return version + raise Exception("Versioning for this project requires either an sdist" + " tarball, or access to an upstream git repository.") diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/strutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/strutils.py new file mode 100644 index 00000000..47bb9545 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/strutils.py @@ -0,0 +1,222 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +System-level utilities and helper functions. +""" + +import re +import sys +import unicodedata + +import six + +from sm_api.openstack.common.gettextutils import _ + + +# Used for looking up extensions of text +# to their 'multiplied' byte amount +BYTE_MULTIPLIERS = { + '': 1, + 't': 1024 ** 4, + 'g': 1024 ** 3, + 'm': 1024 ** 2, + 'k': 1024, +} +BYTE_REGEX = re.compile(r'(^-?\d+)(\D*)') + +TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes') +FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no') + +SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]") +SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+") + + +def int_from_bool_as_string(subject): + """Interpret a string as a boolean and return either 1 or 0. + + Any string value in: + + ('True', 'true', 'On', 'on', '1') + + is interpreted as a boolean True. + + Useful for JSON-decoded stuff and config file parsing + """ + return bool_from_string(subject) and 1 or 0 + + +def bool_from_string(subject, strict=False): + """Interpret a string as a boolean. + + A case-insensitive match is performed such that strings matching 't', + 'true', 'on', 'y', 'yes', or '1' are considered True and, when + `strict=False`, anything else is considered False. + + Useful for JSON-decoded stuff and config file parsing. + + If `strict=True`, unrecognized values, including None, will raise a + ValueError which is useful when parsing values passed in from an API call. + Strings yielding False are 'f', 'false', 'off', 'n', 'no', or '0'. + """ + if not isinstance(subject, six.string_types): + subject = str(subject) + + lowered = subject.strip().lower() + + if lowered in TRUE_STRINGS: + return True + elif lowered in FALSE_STRINGS: + return False + elif strict: + acceptable = ', '.join( + "'%s'" % s for s in sorted(TRUE_STRINGS + FALSE_STRINGS)) + msg = _("Unrecognized value '%(val)s', acceptable values are:" + " %(acceptable)s") % {'val': subject, + 'acceptable': acceptable} + raise ValueError(msg) + else: + return False + + +def safe_decode(text, incoming=None, errors='strict'): + """Decodes incoming str using `incoming` if they're not already unicode. + + :param incoming: Text's current encoding + :param errors: Errors handling policy. See here for valid + values http://docs.python.org/2/library/codecs.html + :returns: text or a unicode `incoming` encoded + representation of it. + :raises TypeError: If text is not an isntance of str + """ + if not isinstance(text, six.string_types): + raise TypeError("%s can't be decoded" % type(text)) + + if isinstance(text, six.text_type): + return text + + if not incoming: + incoming = (sys.stdin.encoding or + sys.getdefaultencoding()) + + try: + return text.decode(incoming, errors) + except UnicodeDecodeError: + # Note(flaper87) If we get here, it means that + # sys.stdin.encoding / sys.getdefaultencoding + # didn't return a suitable encoding to decode + # text. This happens mostly when global LANG + # var is not set correctly and there's no + # default encoding. In this case, most likely + # python will use ASCII or ANSI encoders as + # default encodings but they won't be capable + # of decoding non-ASCII characters. + # + # Also, UTF-8 is being used since it's an ASCII + # extension. + return text.decode('utf-8', errors) + + +def safe_encode(text, incoming=None, + encoding='utf-8', errors='strict'): + """Encodes incoming str/unicode using `encoding`. + + If incoming is not specified, text is expected to be encoded with + current python's default encoding. (`sys.getdefaultencoding`) + + :param incoming: Text's current encoding + :param encoding: Expected encoding for text (Default UTF-8) + :param errors: Errors handling policy. See here for valid + values http://docs.python.org/2/library/codecs.html + :returns: text or a bytestring `encoding` encoded + representation of it. + :raises TypeError: If text is not an isntance of str + """ + if not isinstance(text, six.string_types): + raise TypeError("%s can't be encoded" % type(text)) + + if not incoming: + incoming = (sys.stdin.encoding or + sys.getdefaultencoding()) + + if isinstance(text, six.text_type): + return text.encode(encoding, errors) + elif text and encoding != incoming: + # Decode text before encoding it with `encoding` + text = safe_decode(text, incoming, errors) + return text.encode(encoding, errors) + + return text + + +def to_bytes(text, default=0): + """Converts a string into an integer of bytes. + + Looks at the last characters of the text to determine + what conversion is needed to turn the input text into a byte number. + Supports "B, K(B), M(B), G(B), and T(B)". (case insensitive) + + :param text: String input for bytes size conversion. + :param default: Default return value when text is blank. + + """ + match = BYTE_REGEX.search(text) + if match: + magnitude = int(match.group(1)) + mult_key_org = match.group(2) + if not mult_key_org: + return magnitude + elif text: + msg = _('Invalid string format: %s') % text + raise TypeError(msg) + else: + return default + mult_key = mult_key_org.lower().replace('b', '', 1) + multiplier = BYTE_MULTIPLIERS.get(mult_key) + if multiplier is None: + msg = _('Unknown byte multiplier: %s') % mult_key_org + raise TypeError(msg) + return magnitude * multiplier + + +def to_slug(value, incoming=None, errors="strict"): + """Normalize string. + + Convert to lowercase, remove non-word characters, and convert spaces + to hyphens. + + Inspired by Django's `slugify` filter. + + :param value: Text to slugify + :param incoming: Text's current encoding + :param errors: Errors handling policy. See here for valid + values http://docs.python.org/2/library/codecs.html + :returns: slugified unicode representation of `value` + :raises TypeError: If text is not an instance of str + """ + value = safe_decode(value, incoming, errors) + # NOTE(aababilov): no need to use safe_(encode|decode) here: + # encodings are always "ascii", error handling is always "ignore" + # and types are always known (first: unicode; second: str) + value = unicodedata.normalize("NFKD", value).encode( + "ascii", "ignore").decode("ascii") + value = SLUGIFY_STRIP_RE.sub("", value).strip().lower() + return SLUGIFY_HYPHENATE_RE.sub("-", value) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/threadgroup.py b/service-mgmt-api/sm-api/sm_api/openstack/common/threadgroup.py new file mode 100644 index 00000000..e6d1c55c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/threadgroup.py @@ -0,0 +1,125 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from eventlet import greenlet +from eventlet import greenpool +from eventlet import greenthread + +from sm_api.openstack.common import log as logging +from sm_api.openstack.common import loopingcall + + +LOG = logging.getLogger(__name__) + + +def _thread_done(gt, *args, **kwargs): + """ Callback function to be passed to GreenThread.link() when we spawn() + Calls the :class:`ThreadGroup` to notify if. + + """ + kwargs['group'].thread_done(kwargs['thread']) + + +class Thread(object): + """ Wrapper around a greenthread, that holds a reference to the + :class:`ThreadGroup`. The Thread will notify the :class:`ThreadGroup` when + it has done so it can be removed from the threads list. + """ + def __init__(self, thread, group): + self.thread = thread + self.thread.link(_thread_done, group=group, thread=self) + + def stop(self): + self.thread.kill() + + def wait(self): + return self.thread.wait() + + +class ThreadGroup(object): + """ The point of the ThreadGroup classis to: + + * keep track of timers and greenthreads (making it easier to stop them + when need be). + * provide an easy API to add timers. + """ + def __init__(self, thread_pool_size=10): + self.pool = greenpool.GreenPool(thread_pool_size) + self.threads = [] + self.timers = [] + + def add_dynamic_timer(self, callback, initial_delay=None, + periodic_interval_max=None, *args, **kwargs): + timer = loopingcall.DynamicLoopingCall(callback, *args, **kwargs) + timer.start(initial_delay=initial_delay, + periodic_interval_max=periodic_interval_max) + self.timers.append(timer) + + def add_timer(self, interval, callback, initial_delay=None, + *args, **kwargs): + pulse = loopingcall.FixedIntervalLoopingCall(callback, *args, **kwargs) + pulse.start(interval=interval, + initial_delay=initial_delay) + self.timers.append(pulse) + + def add_thread(self, callback, *args, **kwargs): + gt = self.pool.spawn(callback, *args, **kwargs) + th = Thread(gt, self) + self.threads.append(th) + + def thread_done(self, thread): + self.threads.remove(thread) + + def stop(self): + current = greenthread.getcurrent() + for x in self.threads: + if x is current: + # don't kill the current thread. + continue + try: + x.stop() + except Exception as ex: + LOG.exception(ex) + + for x in self.timers: + try: + x.stop() + except Exception as ex: + LOG.exception(ex) + self.timers = [] + + def wait(self): + for x in self.timers: + try: + x.wait() + except greenlet.GreenletExit: + pass + except Exception as ex: + LOG.exception(ex) + current = greenthread.getcurrent() + for x in self.threads: + if x is current: + continue + try: + x.wait() + except greenlet.GreenletExit: + pass + except Exception as ex: + LOG.exception(ex) diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/timeutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/timeutils.py new file mode 100644 index 00000000..c420c2d7 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/timeutils.py @@ -0,0 +1,190 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Time related utilities and helper functions. +""" + +import calendar +import datetime + +import iso8601 + + +# ISO 8601 extended time format with microseconds +_ISO8601_TIME_FORMAT_SUBSECOND = '%Y-%m-%dT%H:%M:%S.%f' +_ISO8601_TIME_FORMAT = '%Y-%m-%dT%H:%M:%S' +PERFECT_TIME_FORMAT = _ISO8601_TIME_FORMAT_SUBSECOND + + +def isotime(at=None, subsecond=False): + """Stringify time in ISO 8601 format""" + if not at: + at = utcnow() + st = at.strftime(_ISO8601_TIME_FORMAT + if not subsecond + else _ISO8601_TIME_FORMAT_SUBSECOND) + tz = at.tzinfo.tzname(None) if at.tzinfo else 'UTC' + st += ('Z' if tz == 'UTC' else tz) + return st + + +def parse_isotime(timestr): + """Parse time from ISO 8601 format""" + try: + return iso8601.parse_date(timestr) + except iso8601.ParseError as e: + raise ValueError(e.message) + except TypeError as e: + raise ValueError(e.message) + + +def strtime(at=None, fmt=PERFECT_TIME_FORMAT): + """Returns formatted utcnow.""" + if not at: + at = utcnow() + return at.strftime(fmt) + + +def parse_strtime(timestr, fmt=PERFECT_TIME_FORMAT): + """Turn a formatted time back into a datetime.""" + return datetime.datetime.strptime(timestr, fmt) + + +def normalize_time(timestamp): + """Normalize time in arbitrary timezone to UTC naive object""" + offset = timestamp.utcoffset() + if offset is None: + return timestamp + return timestamp.replace(tzinfo=None) - offset + + +def is_older_than(before, seconds): + """Return True if before is older than seconds.""" + if isinstance(before, basestring): + before = parse_strtime(before).replace(tzinfo=None) + return utcnow() - before > datetime.timedelta(seconds=seconds) + + +def is_newer_than(after, seconds): + """Return True if after is newer than seconds.""" + if isinstance(after, basestring): + after = parse_strtime(after).replace(tzinfo=None) + return after - utcnow() > datetime.timedelta(seconds=seconds) + + +def utcnow_ts(): + """Timestamp version of our utcnow function.""" + return calendar.timegm(utcnow().timetuple()) + + +def utcnow(): + """Overridable version of utils.utcnow.""" + if utcnow.override_time: + try: + return utcnow.override_time.pop(0) + except AttributeError: + return utcnow.override_time + return datetime.datetime.utcnow() + + +def iso8601_from_timestamp(timestamp): + """Returns a iso8601 formated date from timestamp""" + return isotime(datetime.datetime.utcfromtimestamp(timestamp)) + + +utcnow.override_time = None + + +def set_time_override(override_time=datetime.datetime.utcnow()): + """ + Override utils.utcnow to return a constant time or a list thereof, + one at a time. + """ + utcnow.override_time = override_time + + +def advance_time_delta(timedelta): + """Advance overridden time using a datetime.timedelta.""" + assert(not utcnow.override_time is None) + try: + for dt in utcnow.override_time: + dt += timedelta + except TypeError: + utcnow.override_time += timedelta + + +def advance_time_seconds(seconds): + """Advance overridden time by seconds.""" + advance_time_delta(datetime.timedelta(0, seconds)) + + +def clear_time_override(): + """Remove the overridden time.""" + utcnow.override_time = None + + +def marshall_now(now=None): + """Make an rpc-safe datetime with microseconds. + + Note: tzinfo is stripped, but not required for relative times.""" + if not now: + now = utcnow() + return dict(day=now.day, month=now.month, year=now.year, hour=now.hour, + minute=now.minute, second=now.second, + microsecond=now.microsecond) + + +def unmarshall_time(tyme): + """Unmarshall a datetime dict.""" + return datetime.datetime(day=tyme['day'], + month=tyme['month'], + year=tyme['year'], + hour=tyme['hour'], + minute=tyme['minute'], + second=tyme['second'], + microsecond=tyme['microsecond']) + + +def delta_seconds(before, after): + """ + Compute the difference in seconds between two date, time, or + datetime objects (as a float, to microsecond resolution). + """ + delta = after - before + try: + return delta.total_seconds() + except AttributeError: + return ((delta.days * 24 * 3600) + delta.seconds + + float(delta.microseconds) / (10 ** 6)) + + +def is_soon(dt, window): + """ + Determines if time is going to happen in the next window seconds. + + :params dt: the time + :params window: minimum seconds to remain to consider the time not soon + + :return: True if expiration is within the given duration + """ + soon = (utcnow() + datetime.timedelta(seconds=window)) + return normalize_time(dt) <= soon diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/uuidutils.py b/service-mgmt-api/sm-api/sm_api/openstack/common/uuidutils.py new file mode 100644 index 00000000..803bb091 --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/uuidutils.py @@ -0,0 +1,43 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2012 Intel Corporation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +UUID related utilities and helper functions. +""" + +import uuid + + +def generate_uuid(): + return str(uuid.uuid4()) + + +def is_uuid_like(val): + """Returns validation of a value as a UUID. + + For our purposes, a UUID is a canonical form string: + aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa + + """ + try: + return str(uuid.UUID(val)) == val + except (TypeError, ValueError, AttributeError): + return False diff --git a/service-mgmt-api/sm-api/sm_api/openstack/common/version.py b/service-mgmt-api/sm-api/sm_api/openstack/common/version.py new file mode 100644 index 00000000..9b2e569c --- /dev/null +++ b/service-mgmt-api/sm-api/sm_api/openstack/common/version.py @@ -0,0 +1,98 @@ + +# Copyright 2012 OpenStack Foundation +# Copyright 2012-2013 Hewlett-Packard Development Company, L.P. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Utilities for consuming the version from pkg_resources. +""" + +import pkg_resources + + +class VersionInfo(object): + + def __init__(self, package): + """Object that understands versioning for a package + :param package: name of the python package, such as glance, or + python-glanceclient + """ + self.package = package + self.release = None + self.version = None + self._cached_version = None + + def __str__(self): + """Make the VersionInfo object behave like a string.""" + return self.version_string() + + def __repr__(self): + """Include the name.""" + return "VersionInfo(%s:%s)" % (self.package, self.version_string()) + + def _get_version_from_pkg_resources(self): + """Get the version of the package from the pkg_resources record + associated with the package.""" + try: + requirement = pkg_resources.Requirement.parse(self.package) + provider = pkg_resources.get_provider(requirement) + return provider.version + except pkg_resources.DistributionNotFound: + # The most likely cause for this is running tests in a tree + # produced from a tarball where the package itself has not been + # installed into anything. Revert to setup-time logic. + from sm_api.openstack.common import setup + return setup.get_version(self.package) + + def release_string(self): + """Return the full version of the package including suffixes indicating + VCS status. + """ + if self.release is None: + self.release = self._get_version_from_pkg_resources() + + return self.release + + def version_string(self): + """Return the short version minus any alpha/beta tags.""" + if self.version is None: + parts = [] + for part in self.release_string().split('.'): + if part[0].isdigit(): + parts.append(part) + else: + break + self.version = ".".join(parts) + + return self.version + + # Compatibility functions + canonical_version_string = version_string + version_string_with_vcs = release_string + + def cached_version_string(self, prefix=""): + """Generate an object which will expand in a string context to + the results of version_string(). We do this so that don't + call into pkg_resources every time we start up a program when + passing version information into the CONF constructor, but + rather only do the calculation when and if a version is requested + """ + if not self._cached_version: + self._cached_version = "%s%s" % (prefix, + self.version_string()) + return self._cached_version diff --git a/service-mgmt-client/LICENSE b/service-mgmt-client/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/service-mgmt-client/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/service-mgmt-client/centos/build_srpm.data b/service-mgmt-client/centos/build_srpm.data new file mode 100644 index 00000000..fbbec207 --- /dev/null +++ b/service-mgmt-client/centos/build_srpm.data @@ -0,0 +1,4 @@ +SRC_DIR=sm-client +TAR_NAME=sm-client +VERSION=1.0 +TIS_PATCH_VER=1 diff --git a/service-mgmt-client/centos/sm-client.spec b/service-mgmt-client/centos/sm-client.spec new file mode 100644 index 00000000..8e207155 --- /dev/null +++ b/service-mgmt-client/centos/sm-client.spec @@ -0,0 +1,55 @@ +Summary: Service Management Client and CLI +Name: sm-client +Version: 1.0 +Release: %{tis_patch_ver}%{?_tis_dist} +License: Apache-2.0 +Group: base +Packager: Wind River +URL: unknown +Source0: %{name}-%{version}.tar.gz + +%define debug_package %{nil} + +BuildRequires: python +BuildRequires: python-setuptools +Requires: python-libs + +%prep +%setup -q + +%build +%{__python2} setup.py build + +%install +%global _buildsubdir %{_builddir}/%{name}-%{version} +%{__python2} setup.py install -O1 --skip-build --root %{buildroot} + +%description +Service Management Client and CLI + +#%package -n sm-client-py-src-tar +#Summary: Service Management Client and CLI source tarball +#Group: base + +#%description -n sm-client-py-src-tar +#Service Management API + + +#%post -n sm-client-py-src-tar +## sm-client-py-src-tar - postinst +# if [ -f $D/usr/src/sm-client-1.0.tar.bz2 ] ; then +# ( cd $D/ && tar -xf $D/usr/src/sm-client-1.0.tar.bz2 ) +# fi + + +%files +%defattr(-,root,root,-) +%dir "/usr/lib/python2.7/site-packages/sm_client" +/usr/lib/python2.7/site-packages/sm_client/* +%dir "/usr/lib/python2.7/site-packages/sm_client-1.0.0-py2.7.egg-info" +/usr/lib/python2.7/site-packages/sm_client-1.0.0-py2.7.egg-info/* + +#%files -n sm-client-py-src-tar +#%defattr(-,-,-,-) +#"/usr/src/sm-client-1.0.tar.bz2" + diff --git a/service-mgmt-client/sm-client/LICENSE b/service-mgmt-client/sm-client/LICENSE new file mode 100644 index 00000000..68c771a0 --- /dev/null +++ b/service-mgmt-client/sm-client/LICENSE @@ -0,0 +1,176 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + diff --git a/service-mgmt-client/sm-client/README.rst b/service-mgmt-client/sm-client/README.rst new file mode 100644 index 00000000..cb8b1e51 --- /dev/null +++ b/service-mgmt-client/sm-client/README.rst @@ -0,0 +1,5 @@ +Python bindings for the Service Management API +============================================== + +A python and command line client library for Service Management. + diff --git a/service-mgmt-client/sm-client/doc/source/conf.py b/service-mgmt-client/sm-client/doc/source/conf.py new file mode 100644 index 00000000..09eaa752 --- /dev/null +++ b/service-mgmt-client/sm-client/doc/source/conf.py @@ -0,0 +1,76 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# -*- coding: utf-8 -*- +# + +# -- General configuration ---------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.intersphinx', + 'sphinx.ext.viewcode', + 'oslo.sphinx' + ] + +# autodoc generation is a bit aggressive and a nuisance when doing heavy +# text edit cycles. +# execute "export SPHINX_DEBUG=1" in your terminal to disable + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'python-ironicclient' +copyright = u'OpenStack Foundation' + +# A list of ignored prefixes for module index sorting. +modindex_common_prefix = ['ironicclient.'] + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +add_module_names = True + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# -- Options for HTML output -------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme_path = ["."] +html_theme = '_theme' +html_static_path = ['_static'] + +# Output file base name for HTML help builder. +htmlhelp_basename = '%sdoc' % project + + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass +# [howto/manual]). +latex_documents = [ + ( + 'index', + '%s.tex' % project, + u'%s Documentation' % project, + u'OpenStack LLC', + 'manual' + ), +] + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'http://docs.python.org/': None} diff --git a/service-mgmt-client/sm-client/requirements.txt b/service-mgmt-client/sm-client/requirements.txt new file mode 100644 index 00000000..fdcf65de --- /dev/null +++ b/service-mgmt-client/sm-client/requirements.txt @@ -0,0 +1,7 @@ +pbr>=0.5 +anyjson>=0.3.3 +argparse +httplib2 +lxml>=2.3 +PrettyTable>=0.6,<0.8 +python-keystoneclient>=0.3.2 diff --git a/service-mgmt-client/sm-client/setup.cfg b/service-mgmt-client/sm-client/setup.cfg new file mode 100644 index 00000000..0573637e --- /dev/null +++ b/service-mgmt-client/sm-client/setup.cfg @@ -0,0 +1,34 @@ +[metadata] +name = sm_client +summary = SM Provisioning API Client Library +description-file = README.rst +author = WindRiver +author-email = openstack-dev@lists.openstack.org +home-page = http://www.windriver.com/ +classifier = + Environment :: OpenStack + Intended Audience :: Information Technology + Intended Audience :: System Administrators + License :: OSI Approved :: Apache Software License + Operating System :: POSIX :: Linux + Programming Language :: Python + Programming Language :: Python :: 2 + Programming Language :: Python :: 2.7 + Programming Language :: Python :: 2.6 + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.3 + +[files] +packages = sm_client + +[entry_points] +console_scripts = + smc = sm_client.shell:main + +[pbr] +autodoc_index_modules = True + +[build_sphinx] +all_files = 1 +build-dir = doc/build +source-dir = doc/source diff --git a/service-mgmt-client/sm-client/setup.py b/service-mgmt-client/sm-client/setup.py new file mode 100644 index 00000000..d9c5f6d1 --- /dev/null +++ b/service-mgmt-client/sm-client/setup.py @@ -0,0 +1,23 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import setuptools + +setuptools.setup( + name='sm_client', + description='Service Management Client and CLI', + version='1.0.0', + license='Apache-2.0', + packages=['sm_client', 'sm_client.v1', 'sm_client.openstack', + 'sm_client.openstack.common', + 'sm_client.openstack.common.config', + 'sm_client.openstack.common.rootwrap', + 'sm_client.common'], + # entry_points={ + # 'console_scripts': [ + # 'smc = sm_client.shell:main' + # ]} +) diff --git a/service-mgmt-client/sm-client/sm_client/__init__.py b/service-mgmt-client/sm-client/sm_client/__init__.py new file mode 100644 index 00000000..a82ee232 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/__init__.py @@ -0,0 +1,21 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# All Rights Reserved. +# + +# import pbr.version + +try: + import sm_client.client + Client = sm_client.client.Client +except ImportError: + import warnings + warnings.warn("Could not import sm_client.client", ImportWarning) + + +__version__ = "1.0" +# __version__ = pbr.version.VersionInfo('python-sm_client').version_string() diff --git a/service-mgmt-client/sm-client/sm_client/client.py b/service-mgmt-client/sm-client/sm_client/client.py new file mode 100644 index 00000000..8fb21bc2 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/client.py @@ -0,0 +1,111 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + + +from sm_client.common import utils +from keystoneclient.v2_0 import client as ksclient + + +def _get_ksclient(**kwargs): + """Get an endpoint and auth token from Keystone. + + :param kwargs: keyword args containing credentials: + * username: name of user + * password: user's password + * auth_url: endpoint to authenticate against + * insecure: allow insecure SSL (no cert verification) + * tenant_{name|id}: name or ID of tenant + """ + return ksclient.Client(username=kwargs.get('username'), + password=kwargs.get('password'), + tenant_id=kwargs.get('tenant_id'), + tenant_name=kwargs.get('tenant_name'), + auth_url=kwargs.get('auth_url'), + insecure=kwargs.get('insecure')) + + +def _get_endpoint(client, **kwargs): + """Get an endpoint using the provided keystone client.""" + return client.service_catalog.url_for( + service_type=kwargs.get('service_type') or 'baremetal', + endpoint_type=kwargs.get('endpoint_type') or 'publicURL', + region_name=kwargs.get('os_region_name') or 'RegionOne') + + +def get_client(api_version, **kwargs): + """Get an authtenticated client, based on the credentials + in the keyword args. + + :param api_version: the API version to use ('1' or '2') + :param kwargs: keyword args containing credentials, either: + * os_auth_token: pre-existing token to re-use + * smc_url: smc API endpoint + or: + * os_username: name of user + * os_password: user's password + * os_auth_url: endpoint to authenticate against + * insecure: allow insecure SSL (no cert verification) + * os_tenant_{name|id}: name or ID of tenant + * os_region_name: region of the service + """ + if kwargs.get('os_auth_token') and kwargs.get('smc_url'): + token = kwargs.get('os_auth_token') + endpoint = kwargs.get('smc_url') + elif (kwargs.get('os_username') and + kwargs.get('os_password') and + kwargs.get('os_auth_url') and + (kwargs.get('os_tenant_id') or kwargs.get('os_tenant_name'))): + + ks_kwargs = { + 'username': kwargs.get('os_username'), + 'password': kwargs.get('os_password'), + 'tenant_id': kwargs.get('os_tenant_id'), + 'tenant_name': kwargs.get('os_tenant_name'), + 'auth_url': kwargs.get('os_auth_url'), + 'service_type': kwargs.get('os_service_type'), + 'endpoint_type': kwargs.get('os_endpoint_type'), + 'insecure': kwargs.get('insecure'), + } + _ksclient = _get_ksclient(**ks_kwargs) + token = ((lambda: kwargs.get('os_auth_token')) + if kwargs.get('os_auth_token') + else (lambda: _ksclient.auth_token)) + + ep_kwargs = { + 'username': kwargs.get('os_username'), + 'password': kwargs.get('os_password'), + 'tenant_id': kwargs.get('os_tenant_id'), + 'tenant_name': kwargs.get('os_tenant_name'), + 'auth_url': kwargs.get('os_auth_url'), + 'service_type': kwargs.get('os_service_type'), + 'endpoint_type': kwargs.get('os_endpoint_type'), + 'region_name': kwargs.get('os_region_name'), + 'insecure': kwargs.get('insecure'), + } + + endpoint = kwargs.get('smc_url') or \ + _get_endpoint(_ksclient, **ep_kwargs) + + #region_name=kwargs.get('os_region_name') or 'RegionOne' + # neutron_endpoint = _get_endpoint(_ksclient, service_type='network', endpoint_type='internalURL', region_name=region_name ) + + cli_kwargs = { + 'token': token, + 'insecure': kwargs.get('insecure'), + 'timeout': kwargs.get('timeout'), + 'ca_file': kwargs.get('ca_file'), + 'cert_file': kwargs.get('cert_file'), + 'key_file': kwargs.get('key_file'), + # 'neutron_endpoint': neutron_endpoint, + } + + return Client(api_version, endpoint, **cli_kwargs) + + +def Client(version, *args, **kwargs): + module = utils.import_versioned_module(version, 'client') + client_class = getattr(module, 'Client') + return client_class(*args, **kwargs) diff --git a/service-mgmt-client/sm-client/sm_client/common/__init__.py b/service-mgmt-client/sm-client/sm_client/common/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/service-mgmt-client/sm-client/sm_client/common/base.py b/service-mgmt-client/sm-client/sm_client/common/base.py new file mode 100644 index 00000000..3ebf2530 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/common/base.py @@ -0,0 +1,146 @@ +# Copyright 2012 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Base utilities to build API operation managers and objects on top of. +""" + +import copy + + +# Python 2.4 compat +try: + all +except NameError: + def all(iterable): + return True not in (not x for x in iterable) + + +def getid(obj): + """Abstracts the common pattern of allowing both an object or an + object's ID (UUID) as a parameter when dealing with relationships. + """ + try: + return obj.id + except AttributeError: + return obj + + +class Manager(object): + """Managers interact with a particular type of API and provide CRUD + operations for them. + """ + resource_class = None + + def __init__(self, api): + self.api = api + + def _create(self, url, body): + resp, body = self.api.json_request('POST', url, body=body) + if body: + return self.resource_class(self, body) + + def _list(self, url, response_key=None, obj_class=None, body=None): + resp, body = self.api.json_request('GET', url) + + if obj_class is None: + obj_class = self.resource_class + + if response_key: + try: + data = body[response_key] + except KeyError: + return [] + else: + data = body + if not isinstance(data, list): + data = [data] + + return [obj_class(self, res, loaded=True) for res in data if res] + + def _update(self, url, body, response_key=None): + resp, body = self.api.json_request('PATCH', url, body=body) + # PATCH requests may not return a body + if body: + return self.resource_class(self, body) + + def _delete(self, url): + self.api.raw_request('DELETE', url) + + +class Resource(object): + """A resource represents a particular instance of an object (tenant, user, + etc). This is pretty much just a bag for attributes. + + :param manager: Manager object + :param info: dictionary representing resource attributes + :param loaded: prevent lazy-loading if set to True + """ + def __init__(self, manager, info, loaded=False): + self.manager = manager + self._info = info + self._add_details(info) + self._loaded = loaded + + def _add_details(self, info): + for (k, v) in info.iteritems(): + setattr(self, k, v) + + def __getattr__(self, k): + if k not in self.__dict__: + # NOTE(bcwaldon): disallow lazy-loading if already loaded once + if not self.is_loaded(): + self.get() + return self.__getattr__(k) + + raise AttributeError(k) + else: + return self.__dict__[k] + + def __repr__(self): + reprkeys = sorted(k for k in self.__dict__.keys() if k[0] != '_' and + k != 'manager') + info = ", ".join("%s=%s" % (k, getattr(self, k)) for k in reprkeys) + return "<%s %s>" % (self.__class__.__name__, info) + + def get(self): + # set_loaded() first ... so if we have to bail, we know we tried. + self.set_loaded(True) + if not hasattr(self.manager, 'get'): + return + + new = self.manager.get(self.id) + if new: + self._add_details(new._info) + + def __eq__(self, other): + if not isinstance(other, self.__class__): + return False + if hasattr(self, 'id') and hasattr(other, 'id'): + return self.id == other.id + return self._info == other._info + + def is_loaded(self): + return self._loaded + + def set_loaded(self, val): + self._loaded = val + + def to_dict(self): + return copy.deepcopy(self._info) diff --git a/service-mgmt-client/sm-client/sm_client/common/http.py b/service-mgmt-client/sm-client/sm_client/common/http.py new file mode 100644 index 00000000..986994b0 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/common/http.py @@ -0,0 +1,302 @@ +# Copyright 2012 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import copy +import httplib +import logging +import os +import socket +import StringIO +import urlparse + +try: + import ssl +except ImportError: + #TODO(bcwaldon): Handle this failure more gracefully + pass + +try: + import json +except ImportError: + import simplejson as json + +# Python 2.5 compat fix +if not hasattr(urlparse, 'parse_qsl'): + import cgi + urlparse.parse_qsl = cgi.parse_qsl + + +from sm_client import exc + + +LOG = logging.getLogger(__name__) +USER_AGENT = 'python-sm_client' +CHUNKSIZE = 1024 * 64 # 64kB + + +class HTTPClient(object): + + def __init__(self, endpoint, **kwargs): + self.endpoint = endpoint + self.auth_token = kwargs.get('token') + self.connection_params = self.get_connection_params(endpoint, **kwargs) + + @staticmethod + def get_connection_params(endpoint, **kwargs): + parts = urlparse.urlparse(endpoint) + + _args = (parts.hostname, parts.port, parts.path) + _kwargs = {'timeout': (float(kwargs.get('timeout')) + if kwargs.get('timeout') else 600)} + + if parts.scheme == 'https': + _class = VerifiedHTTPSConnection + _kwargs['ca_file'] = kwargs.get('ca_file', None) + _kwargs['cert_file'] = kwargs.get('cert_file', None) + _kwargs['key_file'] = kwargs.get('key_file', None) + _kwargs['insecure'] = kwargs.get('insecure', False) + elif parts.scheme == 'http': + _class = httplib.HTTPConnection + else: + msg = 'Unsupported scheme: %s' % parts.scheme + raise exc.InvalidEndpoint(msg) + + return (_class, _args, _kwargs) + + def get_connection(self): + _class = self.connection_params[0] + try: + return _class(*self.connection_params[1][0:2], + **self.connection_params[2]) + except httplib.InvalidURL: + raise exc.InvalidEndpoint() + + def log_curl_request(self, method, url, kwargs): + curl = ['curl -i -X %s' % method] + + for (key, value) in kwargs['headers'].items(): + header = '-H \'%s: %s\'' % (key, value) + curl.append(header) + + conn_params_fmt = [ + ('key_file', '--key %s'), + ('cert_file', '--cert %s'), + ('ca_file', '--cacert %s'), + ] + for (key, fmt) in conn_params_fmt: + value = self.connection_params[2].get(key) + if value: + curl.append(fmt % value) + + if self.connection_params[2].get('insecure'): + curl.append('-k') + + if 'body' in kwargs: + curl.append('-d \'%s\'' % kwargs['body']) + + curl.append('%s%s' % (self.endpoint, url)) + LOG.debug(' '.join(curl)) + + @staticmethod + def log_http_response(resp, body=None): + status = (resp.version / 10.0, resp.status, resp.reason) + dump = ['\nHTTP/%.1f %s %s' % status] + dump.extend(['%s: %s' % (k, v) for k, v in resp.getheaders()]) + dump.append('') + if body: + dump.extend([body, '']) + LOG.debug('\n'.join(dump)) + + def _make_connection_url(self, url): + (_class, _args, _kwargs) = self.connection_params + base_url = _args[2] + return '%s/%s' % (base_url.rstrip('/'), url.lstrip('/')) + + def _extract_error_message(self, body): + try: + body_json = json.loads(body) + if 'error_message' in body_json: + body_json = json.loads(body_json['error_message']) + if 'faultstring' in body_json: + return body_json['faultstring'] + except ValueError: + pass + + def _http_request(self, url, method, **kwargs): + """Send an http request with the specified characteristics. + + Wrapper around httplib.HTTP(S)Connection.request to handle tasks such + as setting headers and error handling. + """ + # Copy the kwargs so we can reuse the original in case of redirects + kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {})) + kwargs['headers'].setdefault('User-Agent', USER_AGENT) + if self.auth_token: + kwargs['headers'].setdefault('X-Auth-Token', self.auth_token) + + self.log_curl_request(method, url, kwargs) + conn = self.get_connection() + + try: + conn_url = self._make_connection_url(url) + conn.request(method, conn_url, **kwargs) + resp = conn.getresponse() + except socket.gaierror as e: + message = ("Error finding address for %(url)s: %(e)s" + % dict(url=url, e=e)) + raise exc.InvalidEndpoint(message=message) + except (socket.error, socket.timeout) as e: + endpoint = self.endpoint + message = ("Error communicating with %(endpoint)s %(e)s" + % dict(endpoint=endpoint, e=e)) + raise exc.CommunicationError(message=message) + + body_iter = ResponseBodyIterator(resp) + + # Read body into string if it isn't obviously image data + body_str = None + if resp.getheader('content-type', None) != 'application/octet-stream': + body_str = ''.join([chunk for chunk in body_iter]) + self.log_http_response(resp, body_str) + body_iter = StringIO.StringIO(body_str) + else: + self.log_http_response(resp) + + if 400 <= resp.status < 600: + LOG.warn("Request returned failure status.") + err_msg = self._extract_error_message(body_str) + raise exc.from_response(resp, err_msg) + elif resp.status in (301, 302, 305): + # Redirected. Reissue the request to the new location. + return self._http_request(resp['location'], method, **kwargs) + elif resp.status == 300: + raise exc.from_response(resp) + + return resp, body_iter + + def json_request(self, method, url, **kwargs): + kwargs.setdefault('headers', {}) + kwargs['headers'].setdefault('Content-Type', 'application/json') + kwargs['headers'].setdefault('Accept', 'application/json') + + if 'body' in kwargs: + kwargs['body'] = json.dumps(kwargs['body']) + + resp, body_iter = self._http_request(url, method, **kwargs) + content_type = resp.getheader('content-type', None) + + if resp.status == 204 or resp.status == 205 or content_type is None: + return resp, list() + + if 'application/json' in content_type: + body = ''.join([chunk for chunk in body_iter]) + try: + body = json.loads(body) + except ValueError: + LOG.error('Could not decode response body as JSON') + else: + body = None + + return resp, body + + def raw_request(self, method, url, **kwargs): + kwargs.setdefault('headers', {}) + kwargs['headers'].setdefault('Content-Type', + 'application/octet-stream') + return self._http_request(url, method, **kwargs) + + +class VerifiedHTTPSConnection(httplib.HTTPSConnection): + """httplib-compatibile connection using client-side SSL authentication + + :see http://code.activestate.com/recipes/ + 577548-https-httplib-client-connection-with-certificate-v/ + """ + + def __init__(self, host, port, key_file=None, cert_file=None, + ca_file=None, timeout=None, insecure=False): + httplib.HTTPSConnection.__init__(self, host, port, key_file=key_file, + cert_file=cert_file) + self.key_file = key_file + self.cert_file = cert_file + if ca_file is not None: + self.ca_file = ca_file + else: + self.ca_file = self.get_scm_ca_file() + self.timeout = timeout + self.insecure = insecure + + def connect(self): + """Connect to a host on a given (SSL) port. + If ca_file is pointing somewhere, use it to check Server Certificate. + + Redefined/copied and extended from httplib.py:1105 (Python 2.6.x). + This is needed to pass cert_reqs=ssl.CERT_REQUIRED as parameter to + ssl.wrap_socket(), which forces SSL to check server certificate against + our client certificate. + """ + sock = socket.create_connection((self.host, self.port), self.timeout) + + if self._tunnel_host: + self.sock = sock + self._tunnel() + + if self.insecure is True: + kwargs = {'cert_reqs': ssl.CERT_NONE} + else: + kwargs = {'cert_reqs': ssl.CERT_REQUIRED, 'ca_certs': self.ca_file} + + if self.cert_file: + kwargs['certfile'] = self.cert_file + if self.key_file: + kwargs['keyfile'] = self.key_file + + self.sock = ssl.wrap_socket(sock, **kwargs) + + @staticmethod + def get_scm_ca_file(): + """Return path to scm default CA file.""" + # Standard CA file locations for Debian/Ubuntu, RedHat/Fedora, + # Suse, FreeBSD/OpenBSD + ca_path = ['/etc/ssl/certs/ca-certificates.crt', + '/etc/pki/tls/certs/ca-bundle.crt', + '/etc/ssl/ca-bundle.pem', + '/etc/ssl/cert.pem'] + for ca in ca_path: + if os.path.exists(ca): + return ca + return None + + +class ResponseBodyIterator(object): + """A class that acts as an iterator over an HTTP response.""" + + def __init__(self, resp): + self.resp = resp + + def __iter__(self): + while True: + yield self.next() + + def next(self): + chunk = self.resp.read(CHUNKSIZE) + if chunk: + return chunk + else: + raise StopIteration() diff --git a/service-mgmt-client/sm-client/sm_client/common/utils.py b/service-mgmt-client/sm-client/sm_client/common/utils.py new file mode 100644 index 00000000..9b596ced --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/common/utils.py @@ -0,0 +1,231 @@ +# Copyright 2012 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import argparse +import os +import sys +import textwrap +import uuid + +import prettytable + +from sm_client import exc +from sm_client.openstack.common import importutils + + +class HelpFormatter(argparse.HelpFormatter): + def start_section(self, heading): + # Title-case the headings + heading = '%s%s' % (heading[0].upper(), heading[1:]) + super(HelpFormatter, self).start_section(heading) + + +def define_command(subparsers, command, callback, cmd_mapper): + '''Define a command in the subparsers collection. + + :param subparsers: subparsers collection where the command will go + :param command: command name + :param callback: function that will be used to process the command + ''' + desc = callback.__doc__ or '' + help = desc.strip().split('\n')[0] + arguments = getattr(callback, 'arguments', []) + + subparser = subparsers.add_parser(command, help=help, + description=desc, + add_help=False, + formatter_class=HelpFormatter) + subparser.add_argument('-h', '--help', action='help', + help=argparse.SUPPRESS) + cmd_mapper[command] = subparser + for (args, kwargs) in arguments: + subparser.add_argument(*args, **kwargs) + subparser.set_defaults(func=callback) + + +def define_commands_from_module(subparsers, command_module, cmd_mapper): + '''Find all methods beginning with 'do_' in a module, and add them + as commands into a subparsers collection. + ''' + for method_name in (a for a in dir(command_module) if a.startswith('do_')): + # Commands should be hypen-separated instead of underscores. + command = method_name[3:].replace('_', '-') + callback = getattr(command_module, method_name) + define_command(subparsers, command, callback, cmd_mapper) + + +# Decorator for cli-args +def arg(*args, **kwargs): + def _decorator(func): + # Because of the sematics of decorator composition if we just append + # to the options list positional options will appear to be backwards. + func.__dict__.setdefault('arguments', []).insert(0, (args, kwargs)) + return func + return _decorator + + +def pretty_choice_list(l): + return ', '.join("'%s'" % i for i in l) + + +def print_list(objs, fields, field_labels, formatters={}, sortby=0): + pt = prettytable.PrettyTable([f for f in field_labels], + caching=False, print_empty=False) + pt.align = 'l' + + for o in objs: + row = [] + for field in fields: + if field in formatters: + row.append(formatters[field](o)) + else: + data = getattr(o, field, '') + row.append(data) + pt.add_row(row) + print pt.get_string(sortby=field_labels[sortby]) + + +def print_tuple_list(tuples, tuple_labels=[]): + pt = prettytable.PrettyTable(['Property', 'Value'], + caching=False, print_empty=False) + pt.align = 'l' + + if not tuple_labels: + for t in tuples: + if len(t) == 2: + pt.add_row([t[0], t[1]]) + else: + for t,l in zip(tuples,tuple_labels): + if len(t) == 2: + pt.add_row([l, t[1]]) + + print pt.get_string() + + +def print_dict(d, dict_property="Property", wrap=0): + pt = prettytable.PrettyTable([dict_property, 'Value'], + caching=False, print_empty=False) + pt.align = 'l' + for k, v in d.iteritems(): + # convert dict to str to check length + if isinstance(v, dict): + v = str(v) + if wrap > 0: + v = textwrap.fill(str(v), wrap) + # if value has a newline, add in multiple rows + # e.g. fault with stacktrace + if v and isinstance(v, basestring) and r'\n' in v: + lines = v.strip().split(r'\n') + col1 = k + for line in lines: + pt.add_row([col1, line]) + col1 = '' + else: + pt.add_row([k, v]) + print pt.get_string() + + +def find_resource(manager, name_or_id): + """Helper for the _find_* methods.""" + # first try to get entity as integer id + try: + if isinstance(name_or_id, int) or name_or_id.isdigit(): + return manager.get(int(name_or_id)) + except exc.NotFound: + pass + + # now try to get entity as uuid + try: + uuid.UUID(str(name_or_id)) + return manager.get(name_or_id) + except (ValueError, exc.NotFound): + pass + + # finally try to find entity by name + try: + return manager.find(name=name_or_id) + except exc.NotFound: + msg = "No %s with a name or ID of '%s' exists." % \ + (manager.resource_class.__name__.lower(), name_or_id) + raise exc.CommandError(msg) + + +def string_to_bool(arg): + return arg.strip().lower() in ('t', 'true', 'yes', '1') + + +def env(*vars, **kwargs): + """Search for the first defined of possibly many env vars + + Returns the first environment variable defined in vars, or + returns the default defined in kwargs. + """ + for v in vars: + value = os.environ.get(v, None) + if value: + return value + return kwargs.get('default', '') + + +def import_versioned_module(version, submodule=None): + module = 'sm_client.v%s' % version + if submodule: + module = '.'.join((module, submodule)) + return importutils.import_module(module) + + +def args_array_to_dict(kwargs, key_to_convert): + values_to_convert = kwargs.get(key_to_convert) + if values_to_convert: + try: + kwargs[key_to_convert] = dict(v.split("=", 1) + for v in values_to_convert) + except ValueError: + raise exc.CommandError( + '%s must be a list of KEY=VALUE not "%s"' % ( + key_to_convert, values_to_convert)) + return kwargs + + +def args_array_to_patch(op, attributes): + patch = [] + for attr in attributes: + # Sanitize + if not attr.startswith('/'): + attr = '/' + attr + + if op in ['add', 'replace']: + try: + path, value = attr.split("=", 1) + patch.append({'op': op, 'path': path, 'value': value}) + except ValueError: + raise exc.CommandError('Attributes must be a list of ' + 'PATH=VALUE not "%s"' % attr) + elif op == "remove": + # For remove only the key is needed + patch.append({'op': op, 'path': attr}) + else: + raise exc.CommandError('Unknown PATCH operation: %s' % op) + return patch + + +def exit(msg=''): + if msg: + print >> sys.stderr, msg + sys.exit(1) diff --git a/service-mgmt-client/sm-client/sm_client/exc.py b/service-mgmt-client/sm-client/sm_client/exc.py new file mode 100644 index 00000000..5486b01e --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/exc.py @@ -0,0 +1,166 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + + +import sys + + +class BaseException(Exception): + """An error occurred.""" + def __init__(self, message=None): + self.message = message + + def __str__(self): + return self.message or self.__class__.__doc__ + + +class CommandError(BaseException): + """Invalid usage of CLI.""" + + +class InvalidEndpoint(BaseException): + """The provided endpoint is invalid.""" + + +class CommunicationError(BaseException): + """Unable to communicate with server.""" + + +class ClientException(Exception): + """DEPRECATED.""" + + +class HTTPException(ClientException): + """Base exception for all HTTP-derived exceptions.""" + code = 'N/A' + + def __init__(self, details=None): + self.details = details + + def __str__(self): + return self.details or "%s (HTTP %s)" % (self.__class__.__name__, + self.code) + + +class HTTPMultipleChoices(HTTPException): + code = 300 + + def __str__(self): + self.details = ("Requested version of OpenStack Images API is not" + "available.") + return "%s (HTTP %s) %s" % (self.__class__.__name__, self.code, + self.details) + + +class BadRequest(HTTPException): + """DEPRECATED.""" + code = 400 + + +class HTTPBadRequest(BadRequest): + pass + + +class Unauthorized(HTTPException): + """DEPRECATED.""" + code = 401 + + +class HTTPUnauthorized(Unauthorized): + pass + + +class Forbidden(HTTPException): + """DEPRECATED.""" + code = 403 + + +class HTTPForbidden(Forbidden): + pass + + +class NotFound(HTTPException): + """DEPRECATED.""" + code = 404 + + +class HTTPNotFound(NotFound): + pass + + +class HTTPMethodNotAllowed(HTTPException): + code = 405 + + +class Conflict(HTTPException): + """DEPRECATED.""" + code = 409 + + +class HTTPConflict(Conflict): + pass + + +class OverLimit(HTTPException): + """DEPRECATED.""" + code = 413 + + +class HTTPOverLimit(OverLimit): + pass + + +class HTTPInternalServerError(HTTPException): + code = 500 + + +class HTTPNotImplemented(HTTPException): + code = 501 + + +class HTTPBadGateway(HTTPException): + code = 502 + + +class ServiceUnavailable(HTTPException): + """DEPRECATED.""" + code = 503 + + +class HTTPServiceUnavailable(ServiceUnavailable): + pass + + +#NOTE(bcwaldon): Build a mapping of HTTP codes to corresponding exception +# classes +_code_map = {} +for obj_name in dir(sys.modules[__name__]): + if obj_name.startswith('HTTP'): + obj = getattr(sys.modules[__name__], obj_name) + _code_map[obj.code] = obj + + +def from_response(response, error=None): + """Return an instance of an HTTPException based on httplib response.""" + cls = _code_map.get(response.status, HTTPException) + return cls(error) + + +class NoTokenLookupException(Exception): + """DEPRECATED.""" + pass + + +class EndpointNotFound(Exception): + """DEPRECATED.""" + pass + + +class InvalidAttribute(ClientException): + pass + +class InvalidAttributeValue(ClientException): + pass diff --git a/service-mgmt-client/sm-client/sm_client/openstack/__init__.py b/service-mgmt-client/sm-client/sm_client/openstack/__init__.py new file mode 100644 index 00000000..4bab4c35 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + diff --git a/service-mgmt-client/sm-client/sm_client/openstack/common/__init__.py b/service-mgmt-client/sm-client/sm_client/openstack/common/__init__.py new file mode 100644 index 00000000..4bab4c35 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/common/__init__.py @@ -0,0 +1,18 @@ +# Copyright 2013 Hewlett-Packard Development Company, L.P. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + diff --git a/service-mgmt-client/sm-client/sm_client/openstack/common/config/generator.py b/service-mgmt-client/sm-client/sm_client/openstack/common/config/generator.py new file mode 100644 index 00000000..765aae24 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/common/config/generator.py @@ -0,0 +1,258 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 SINA Corporation +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + +# +# @author: Zhongyue Luo, SINA Corporation. +# +"""Extracts OpenStack config option info from module(s).""" + +import imp +import os +import re +import socket +import sys +import textwrap + +from oslo_config import cfg + +from sm_client.openstack.common import gettextutils +from sm_client.openstack.common import importutils + +gettextutils.install('python-sm_client') + +STROPT = "StrOpt" +BOOLOPT = "BoolOpt" +INTOPT = "IntOpt" +FLOATOPT = "FloatOpt" +LISTOPT = "ListOpt" +MULTISTROPT = "MultiStrOpt" + +OPT_TYPES = { + STROPT: 'string value', + BOOLOPT: 'boolean value', + INTOPT: 'integer value', + FLOATOPT: 'floating point value', + LISTOPT: 'list value', + MULTISTROPT: 'multi valued', +} + +OPTION_COUNT = 0 +OPTION_REGEX = re.compile(r"(%s)" % "|".join([STROPT, BOOLOPT, INTOPT, + FLOATOPT, LISTOPT, + MULTISTROPT])) + +PY_EXT = ".py" +BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), + "../../../../")) +WORDWRAP_WIDTH = 60 + + +def generate(srcfiles): + mods_by_pkg = dict() + for filepath in srcfiles: + pkg_name = filepath.split(os.sep)[1] + mod_str = '.'.join(['.'.join(filepath.split(os.sep)[:-1]), + os.path.basename(filepath).split('.')[0]]) + mods_by_pkg.setdefault(pkg_name, list()).append(mod_str) + # NOTE(lzyeval): place top level modules before packages + pkg_names = filter(lambda x: x.endswith(PY_EXT), mods_by_pkg.keys()) + pkg_names.sort() + ext_names = filter(lambda x: x not in pkg_names, mods_by_pkg.keys()) + ext_names.sort() + pkg_names.extend(ext_names) + + # opts_by_group is a mapping of group name to an options list + # The options list is a list of (module, options) tuples + opts_by_group = {'DEFAULT': []} + + for pkg_name in pkg_names: + mods = mods_by_pkg.get(pkg_name) + mods.sort() + for mod_str in mods: + if mod_str.endswith('.__init__'): + mod_str = mod_str[:mod_str.rfind(".")] + + mod_obj = _import_module(mod_str) + if not mod_obj: + continue + + for group, opts in _list_opts(mod_obj): + opts_by_group.setdefault(group, []).append((mod_str, opts)) + + print_group_opts('DEFAULT', opts_by_group.pop('DEFAULT', [])) + for group, opts in opts_by_group.items(): + print_group_opts(group, opts) + + print "# Total option count: %d" % OPTION_COUNT + + +def _import_module(mod_str): + try: + if mod_str.startswith('bin.'): + imp.load_source(mod_str[4:], os.path.join('bin', mod_str[4:])) + return sys.modules[mod_str[4:]] + else: + return importutils.import_module(mod_str) + except ImportError as ie: + sys.stderr.write("%s\n" % str(ie)) + return None + except Exception: + return None + + +def _is_in_group(opt, group): + "Check if opt is in group." + for key, value in group._opts.items(): + if value['opt'] == opt: + return True + return False + + +def _guess_groups(opt, mod_obj): + # is it in the DEFAULT group? + if _is_in_group(opt, cfg.CONF): + return 'DEFAULT' + + # what other groups is it in? + for key, value in cfg.CONF.items(): + if isinstance(value, cfg.CONF.GroupAttr): + if _is_in_group(opt, value._group): + return value._group.name + + raise RuntimeError( + "Unable to find group for option %s, " + "maybe it's defined twice in the same group?" + % opt.name + ) + + +def _list_opts(obj): + def is_opt(o): + return (isinstance(o, cfg.Opt) and + not isinstance(o, cfg.SubCommandOpt)) + + opts = list() + for attr_str in dir(obj): + attr_obj = getattr(obj, attr_str) + if is_opt(attr_obj): + opts.append(attr_obj) + elif (isinstance(attr_obj, list) and + all(map(lambda x: is_opt(x), attr_obj))): + opts.extend(attr_obj) + + ret = {} + for opt in opts: + ret.setdefault(_guess_groups(opt, obj), []).append(opt) + return ret.items() + + +def print_group_opts(group, opts_by_module): + print "[%s]" % group + print + global OPTION_COUNT + for mod, opts in opts_by_module: + OPTION_COUNT += len(opts) + print '#' + print '# Options defined in %s' % mod + print '#' + print + for opt in opts: + _print_opt(opt) + print + + +def _get_my_ip(): + try: + csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + csock.connect(('8.8.8.8', 80)) + (addr, port) = csock.getsockname() + csock.close() + return addr + except socket.error: + return None + + +def _sanitize_default(s): + """Set up a reasonably sensible default for pybasedir, my_ip and host.""" + if s.startswith(BASEDIR): + return s.replace(BASEDIR, '/usr/lib/python/site-packages') + elif BASEDIR in s: + return s.replace(BASEDIR, '') + elif s == _get_my_ip(): + return '10.0.0.1' + elif s == socket.gethostname(): + return 'python-sm_client' + elif s.strip() != s: + return '"%s"' % s + return s + + +def _print_opt(opt): + opt_name, opt_default, opt_help = opt.dest, opt.default, opt.help + if not opt_help: + sys.stderr.write('WARNING: "%s" is missing help string.\n' % opt_name) + opt_type = None + try: + opt_type = OPTION_REGEX.search(str(type(opt))).group(0) + except (ValueError, AttributeError) as err: + sys.stderr.write("%s\n" % str(err)) + sys.exit(1) + opt_help += ' (' + OPT_TYPES[opt_type] + ')' + print '#', "\n# ".join(textwrap.wrap(opt_help, WORDWRAP_WIDTH)) + try: + if opt_default is None: + print '#%s=' % opt_name + elif opt_type == STROPT: + assert(isinstance(opt_default, basestring)) + print '#%s=%s' % (opt_name, _sanitize_default(opt_default)) + elif opt_type == BOOLOPT: + assert(isinstance(opt_default, bool)) + print '#%s=%s' % (opt_name, str(opt_default).lower()) + elif opt_type == INTOPT: + assert(isinstance(opt_default, int) and + not isinstance(opt_default, bool)) + print '#%s=%s' % (opt_name, opt_default) + elif opt_type == FLOATOPT: + assert(isinstance(opt_default, float)) + print '#%s=%s' % (opt_name, opt_default) + elif opt_type == LISTOPT: + assert(isinstance(opt_default, list)) + print '#%s=%s' % (opt_name, ','.join(opt_default)) + elif opt_type == MULTISTROPT: + assert(isinstance(opt_default, list)) + if not opt_default: + opt_default = [''] + for default in opt_default: + print '#%s=%s' % (opt_name, default) + print + except Exception: + sys.stderr.write('Error in option "%s"\n' % opt_name) + sys.exit(1) + + +def main(): + if len(sys.argv) < 2: + print "usage: %s [srcfile]...\n" % sys.argv[0] + sys.exit(0) + generate(sys.argv[1:]) + +if __name__ == '__main__': + main() diff --git a/service-mgmt-client/sm-client/sm_client/openstack/common/gettextutils.py b/service-mgmt-client/sm-client/sm_client/openstack/common/gettextutils.py new file mode 100644 index 00000000..99f0592d --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/common/gettextutils.py @@ -0,0 +1,54 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +gettext for openstack-common modules. + +Usual usage in an openstack.common module: + + from smc.openstack.common.gettextutils import _ +""" + +import gettext +import os + +_localedir = os.environ.get('sm_client'.upper() + '_LOCALEDIR') +_t = gettext.translation('sm_client', localedir=_localedir, fallback=True) + + +def _(msg): + return _t.ugettext(msg) + + +def install(domain): + """Install a _() function using the given translation domain. + + Given a translation domain, install a _() function using gettext's + install() function. + + The main difference from gettext.install() is that we allow + overriding the default localedir (e.g. /usr/share/locale) using + a translation-domain-specific environment variable (e.g. + NOVA_LOCALEDIR). + """ + gettext.install(domain, + localedir=os.environ.get(domain.upper() + '_LOCALEDIR'), + unicode=True) diff --git a/service-mgmt-client/sm-client/sm_client/openstack/common/importutils.py b/service-mgmt-client/sm-client/sm_client/openstack/common/importutils.py new file mode 100644 index 00000000..9ee48932 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/common/importutils.py @@ -0,0 +1,71 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Import related utilities and helper functions. +""" + +import sys +import traceback + + +def import_class(import_str): + """Returns a class from a string including module and class""" + mod_str, _sep, class_str = import_str.rpartition('.') + try: + __import__(mod_str) + return getattr(sys.modules[mod_str], class_str) + except (ValueError, AttributeError): + raise ImportError('Class %s cannot be found (%s)' % + (class_str, + traceback.format_exception(*sys.exc_info()))) + + +def import_object(import_str, *args, **kwargs): + """Import a class and return an instance of it.""" + return import_class(import_str)(*args, **kwargs) + + +def import_object_ns(name_space, import_str, *args, **kwargs): + """ + Import a class and return an instance of it, first by trying + to find the class in a default namespace, then failing back to + a full path if not found in the default namespace. + """ + import_value = "%s.%s" % (name_space, import_str) + try: + return import_class(import_value)(*args, **kwargs) + except ImportError: + return import_class(import_str)(*args, **kwargs) + + +def import_module(import_str): + """Import a module.""" + __import__(import_str) + return sys.modules[import_str] + + +def try_import(import_str, default=None): + """Try to import a module and if it fails return default.""" + try: + return import_module(import_str) + except ImportError: + return default diff --git a/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/__init__.py b/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/__init__.py new file mode 100644 index 00000000..c0b12fbe --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/__init__.py @@ -0,0 +1,20 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + diff --git a/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/cmd.py b/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/cmd.py new file mode 100644 index 00000000..0a4f67ed --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/cmd.py @@ -0,0 +1,123 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +""" +Root wrapper for OpenStack services + +""" + +from __future__ import print_function + +import ConfigParser +import logging +import os +import pwd +import signal +import subprocess +import sys + + +RC_UNAUTHORIZED = 99 +RC_NOCOMMAND = 98 +RC_BADCONFIG = 97 +RC_NOEXECFOUND = 96 + + +def _subprocess_setup(): + # Python installs a SIGPIPE handler by default. This is usually not what + # non-Python subprocesses expect. + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + + +def _exit_error(execname, message, errorcode, log=True): + print("%s: %s" % (execname, message)) + if log: + logging.error(message) + sys.exit(errorcode) + + +def main(): + # Split arguments, require at least a command + execname = sys.argv.pop(0) + if len(sys.argv) < 2: + _exit_error(execname, "No command specified", RC_NOCOMMAND, log=False) + + configfile = sys.argv.pop(0) + userargs = sys.argv[:] + + # Add ../ to sys.path to allow running from branch + possible_topdir = os.path.normpath(os.path.join(os.path.abspath(execname), + os.pardir, os.pardir)) + if os.path.exists(os.path.join(possible_topdir, "sm_client", + "__init__.py")): + sys.path.insert(0, possible_topdir) + + from sm_client.openstack.common.rootwrap import wrapper + + # Load configuration + try: + rawconfig = ConfigParser.RawConfigParser() + rawconfig.read(configfile) + config = wrapper.RootwrapConfig(rawconfig) + except ValueError as exc: + msg = "Incorrect value in %s: %s" % (configfile, exc.message) + _exit_error(execname, msg, RC_BADCONFIG, log=False) + except ConfigParser.Error: + _exit_error(execname, "Incorrect configuration file: %s" % configfile, + RC_BADCONFIG, log=False) + + if config.use_syslog: + wrapper.setup_syslog(execname, + config.syslog_log_facility, + config.syslog_log_level) + + # Execute command if it matches any of the loaded filters + filters = wrapper.load_filters(config.filters_path) + try: + filtermatch = wrapper.match_filter(filters, userargs, + exec_dirs=config.exec_dirs) + if filtermatch: + command = filtermatch.get_command(userargs, + exec_dirs=config.exec_dirs) + if config.use_syslog: + logging.info("(%s > %s) Executing %s (filter match = %s)" % ( + os.getlogin(), pwd.getpwuid(os.getuid())[0], + command, filtermatch.name)) + + obj = subprocess.Popen(command, + stdin=sys.stdin, + stdout=sys.stdout, + stderr=sys.stderr, + preexec_fn=_subprocess_setup, + env=filtermatch.get_environment(userargs)) + obj.wait() + sys.exit(obj.returncode) + + except wrapper.FilterMatchNotExecutable as exc: + msg = ("Executable not found: %s (filter match = %s)" + % (exc.match.exec_path, exc.match.name)) + _exit_error(execname, msg, RC_NOEXECFOUND, log=config.use_syslog) + + except wrapper.NoFilterMatched: + msg = ("Unauthorized command: %s (no filter matched)" + % ' '.join(userargs)) + _exit_error(execname, msg, RC_UNAUTHORIZED, log=config.use_syslog) diff --git a/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/filters.py b/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/filters.py new file mode 100644 index 00000000..4db09cdc --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/filters.py @@ -0,0 +1,232 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +import os +import re + + +class CommandFilter(object): + """Command filter only checking that the 1st argument matches exec_path.""" + + def __init__(self, exec_path, run_as, *args): + self.name = '' + self.exec_path = exec_path + self.run_as = run_as + self.args = args + self.real_exec = None + + def get_exec(self, exec_dirs=[]): + """Returns existing executable, or empty string if none found.""" + if self.real_exec is not None: + return self.real_exec + self.real_exec = "" + if self.exec_path.startswith('/'): + if os.access(self.exec_path, os.X_OK): + self.real_exec = self.exec_path + else: + for binary_path in exec_dirs: + expanded_path = os.path.join(binary_path, self.exec_path) + if os.access(expanded_path, os.X_OK): + self.real_exec = expanded_path + break + return self.real_exec + + def match(self, userargs): + """Only check that the first argument (command) matches exec_path.""" + return os.path.basename(self.exec_path) == userargs[0] + + def get_command(self, userargs, exec_dirs=[]): + """Returns command to execute (with sudo -u if run_as != root).""" + to_exec = self.get_exec(exec_dirs=exec_dirs) or self.exec_path + if (self.run_as != 'root'): + # Used to run commands at lesser privileges + return ['sudo', '-u', self.run_as, to_exec] + userargs[1:] + return [to_exec] + userargs[1:] + + def get_environment(self, userargs): + """Returns specific environment to set, None if none.""" + return None + + +class RegExpFilter(CommandFilter): + """Command filter doing regexp matching for every argument.""" + + def match(self, userargs): + # Early skip if command or number of args don't match + if (len(self.args) != len(userargs)): + # DENY: argument numbers don't match + return False + # Compare each arg (anchoring pattern explicitly at end of string) + for (pattern, arg) in zip(self.args, userargs): + try: + if not re.match(pattern + '$', arg): + break + except re.error: + # DENY: Badly-formed filter + return False + else: + # ALLOW: All arguments matched + return True + + # DENY: Some arguments did not match + return False + + +class PathFilter(CommandFilter): + """Command filter checking that path arguments are within given dirs + + One can specify the following constraints for command arguments: + 1) pass - pass an argument as is to the resulting command + 2) some_str - check if an argument is equal to the given string + 3) abs path - check if a path argument is within the given base dir + + A typical rootwrapper filter entry looks like this: + # cmdname: filter name, raw command, user, arg_i_constraint [, ...] + chown: PathFilter, /bin/chown, root, nova, /var/lib/images + + """ + + def match(self, userargs): + command, arguments = userargs[0], userargs[1:] + + equal_args_num = len(self.args) == len(arguments) + exec_is_valid = super(PathFilter, self).match(userargs) + args_equal_or_pass = all( + arg == 'pass' or arg == value + for arg, value in zip(self.args, arguments) + if not os.path.isabs(arg) # arguments not specifying abs paths + ) + paths_are_within_base_dirs = all( + os.path.commonprefix([arg, os.path.realpath(value)]) == arg + for arg, value in zip(self.args, arguments) + if os.path.isabs(arg) # arguments specifying abs paths + ) + + return (equal_args_num and + exec_is_valid and + args_equal_or_pass and + paths_are_within_base_dirs) + + def get_command(self, userargs, exec_dirs=[]): + command, arguments = userargs[0], userargs[1:] + + # convert path values to canonical ones; copy other args as is + args = [os.path.realpath(value) if os.path.isabs(arg) else value + for arg, value in zip(self.args, arguments)] + + return super(PathFilter, self).get_command([command] + args, + exec_dirs) + + +class DnsmasqFilter(CommandFilter): + """Specific filter for the dnsmasq call (which includes env).""" + + CONFIG_FILE_ARG = 'CONFIG_FILE' + + def match(self, userargs): + if (userargs[0] == 'env' and + userargs[1].startswith(self.CONFIG_FILE_ARG) and + userargs[2].startswith('NETWORK_ID=') and + userargs[3] == 'dnsmasq'): + return True + return False + + def get_command(self, userargs, exec_dirs=[]): + to_exec = self.get_exec(exec_dirs=exec_dirs) or self.exec_path + dnsmasq_pos = userargs.index('dnsmasq') + return [to_exec] + userargs[dnsmasq_pos + 1:] + + def get_environment(self, userargs): + env = os.environ.copy() + env[self.CONFIG_FILE_ARG] = userargs[1].split('=')[-1] + env['NETWORK_ID'] = userargs[2].split('=')[-1] + return env + + +class DeprecatedDnsmasqFilter(DnsmasqFilter): + """Variant of dnsmasq filter to support old-style FLAGFILE.""" + CONFIG_FILE_ARG = 'FLAGFILE' + + +class KillFilter(CommandFilter): + """Specific filter for the kill calls. + 1st argument is the user to run /bin/kill under + 2nd argument is the location of the affected executable + Subsequent arguments list the accepted signals (if any) + + This filter relies on /proc to accurately determine affected + executable, so it will only work on procfs-capable systems (not OSX). + """ + + def __init__(self, *args): + super(KillFilter, self).__init__("/bin/kill", *args) + + def match(self, userargs): + if userargs[0] != "kill": + return False + args = list(userargs) + if len(args) == 3: + # A specific signal is requested + signal = args.pop(1) + if signal not in self.args[1:]: + # Requested signal not in accepted list + return False + else: + if len(args) != 2: + # Incorrect number of arguments + return False + if len(self.args) > 1: + # No signal requested, but filter requires specific signal + return False + try: + command = os.readlink("/proc/%d/exe" % int(args[1])) + # NOTE(yufang521247): /proc/PID/exe may have '\0' on the + # end, because python doen't stop at '\0' when read the + # target path. + command = command.split('\0')[0] + # NOTE(dprince): /proc/PID/exe may have ' (deleted)' on + # the end if an executable is updated or deleted + if command.endswith(" (deleted)"): + command = command[:command.rindex(" ")] + if command != self.args[0]: + # Affected executable does not match + return False + except (ValueError, OSError): + # Incorrect PID + return False + return True + + +class ReadFileFilter(CommandFilter): + """Specific filter for the utils.read_file_as_root call.""" + + def __init__(self, file_path, *args): + self.file_path = file_path + super(ReadFileFilter, self).__init__("/bin/cat", "root", *args) + + def match(self, userargs): + if userargs[0] != 'cat': + return False + if userargs[1] != self.file_path: + return False + if len(userargs) != 2: + return False + return True diff --git a/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/wrapper.py b/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/wrapper.py new file mode 100644 index 00000000..77c6a4e8 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/openstack/common/rootwrap/wrapper.py @@ -0,0 +1,155 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2011 OpenStack Foundation. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + + +import ConfigParser +import logging +import logging.handlers +import os +import string + +from sm_client.openstack.common.rootwrap import filters + + +class NoFilterMatched(Exception): + """This exception is raised when no filter matched.""" + pass + + +class FilterMatchNotExecutable(Exception): + """raise if filter matche but not executable + + This exception is raised when a filter matched but no executable was + found. + """ + def __init__(self, match=None, **kwargs): + self.match = match + + +class RootwrapConfig(object): + + def __init__(self, config): + # filters_path + self.filters_path = config.get("DEFAULT", "filters_path").split(",") + + # exec_dirs + if config.has_option("DEFAULT", "exec_dirs"): + self.exec_dirs = config.get("DEFAULT", "exec_dirs").split(",") + else: + # Use system PATH if exec_dirs is not specified + self.exec_dirs = os.environ["PATH"].split(':') + + # syslog_log_facility + if config.has_option("DEFAULT", "syslog_log_facility"): + v = config.get("DEFAULT", "syslog_log_facility") + facility_names = logging.handlers.SysLogHandler.facility_names + self.syslog_log_facility = getattr(logging.handlers.SysLogHandler, + v, None) + if self.syslog_log_facility is None and v in facility_names: + self.syslog_log_facility = facility_names.get(v) + if self.syslog_log_facility is None: + raise ValueError('Unexpected syslog_log_facility: %s' % v) + else: + default_facility = logging.handlers.SysLogHandler.LOG_SYSLOG + self.syslog_log_facility = default_facility + + # syslog_log_level + if config.has_option("DEFAULT", "syslog_log_level"): + v = config.get("DEFAULT", "syslog_log_level") + self.syslog_log_level = logging.getLevelName(v.upper()) + if (self.syslog_log_level == "Level %s" % v.upper()): + raise ValueError('Unexepected syslog_log_level: %s' % v) + else: + self.syslog_log_level = logging.ERROR + + # use_syslog + if config.has_option("DEFAULT", "use_syslog"): + self.use_syslog = config.getboolean("DEFAULT", "use_syslog") + else: + self.use_syslog = False + + +def setup_syslog(execname, facility, level): + rootwrap_logger = logging.getLogger() + rootwrap_logger.setLevel(level) + handler = logging.handlers.SysLogHandler(address='/dev/log', + facility=facility) + handler.setFormatter(logging.Formatter( + os.path.basename(execname) + ': %(message)s')) + rootwrap_logger.addHandler(handler) + + +def build_filter(class_name, *args): + """Returns a filter object of class class_name.""" + if not hasattr(filters, class_name): + logging.warning("Skipping unknown filter class (%s) specified " + "in filter definitions" % class_name) + return None + filterclass = getattr(filters, class_name) + return filterclass(*args) + + +def load_filters(filters_path): + """Load filters from a list of directories.""" + filterlist = [] + for filterdir in filters_path: + if not os.path.isdir(filterdir): + continue + for filterfile in os.listdir(filterdir): + filterconfig = ConfigParser.RawConfigParser() + filterconfig.read(os.path.join(filterdir, filterfile)) + for (name, value) in filterconfig.items("Filters"): + filterdefinition = [string.strip(s) for s in value.split(',')] + newfilter = build_filter(*filterdefinition) + if newfilter is None: + continue + newfilter.name = name + filterlist.append(newfilter) + return filterlist + + +def match_filter(filter_list, userargs, exec_dirs=[]): + """check user command and args + + Checks user command and arguments through command filters and + returns the first matching filter. + Raises NoFilterMatched if no filter matched. + Raises FilterMatchNotExecutable if no executable was found for the + best filter match. + """ + first_not_executable_filter = None + + for f in filter_list: + if f.match(userargs): + # Try other filters if executable is absent + if not f.get_exec(exec_dirs=exec_dirs): + if not first_not_executable_filter: + first_not_executable_filter = f + continue + # Otherwise return matching filter for execution + return f + + if first_not_executable_filter: + # A filter matched, but no executable was found for it + raise FilterMatchNotExecutable(match=first_not_executable_filter) + + # No filter matched + raise NoFilterMatched() diff --git a/service-mgmt-client/sm-client/sm_client/shell.py b/service-mgmt-client/sm-client/sm_client/shell.py new file mode 100644 index 00000000..c9bdba79 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/shell.py @@ -0,0 +1,277 @@ +# +# Copyright (c) 2013-2015 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + + +""" +Command-line interface for Service Manager (SM) +""" + +import argparse +import httplib2 +import logging +import sys + +import sm_client +from sm_client import client as cgclient +from sm_client.common import utils +from sm_client import exc + +# from sm_client.v1.nclient import get_neutron_client + + +class SmcShell(object): + + def get_base_parser(self): + parser = argparse.ArgumentParser( + prog='smc', + description=__doc__.strip(), + epilog='See "smc help COMMAND" ' + 'for help on a specific command.', + add_help=False, + formatter_class=HelpFormatter, + ) + + # Global arguments + parser.add_argument('-h', '--help', + action='store_true', + help=argparse.SUPPRESS, + ) + + parser.add_argument('--version', + action='version', + version=sm_client.__version__) + + parser.add_argument('--debug', + default=bool(utils.env('SM_CLIENT_DEBUG')), + action='store_true', + help='Defaults to env[SM_CLIENT_DEBUG]') + + parser.add_argument('-v', '--verbose', + default=False, action="store_true", + help="Print more verbose output") + + parser.add_argument('-k', '--insecure', + default=False, + action='store_true', + help="Explicitly allow smc client to " + "perform \"insecure\" SSL (https) requests. " + "The server's certificate will " + "not be verified against any certificate " + "authorities. This option should be used with " + "caution") + + parser.add_argument('--cert-file', + help='Path of certificate file to use in SSL ' + 'connection. This file can optionally be prepended' + ' with the private key') + + parser.add_argument('--key-file', + help='Path of client key to use in SSL connection.' + ' This option is not necessary if your key is ' + 'prepended to your cert file') + + parser.add_argument('--ca-file', + help='Path of CA SSL certificate(s) used to verify' + ' the remote server certificate. Without this ' + 'option smcclient looks for the default smc ' + 'CA certificates') + + parser.add_argument('--timeout', + default=600, + help='Number of seconds to wait for a response') + + parser.add_argument('--os-username', + default=utils.env('OS_USERNAME'), + help='Defaults to env[OS_USERNAME]') + + parser.add_argument('--os_username', + help=argparse.SUPPRESS) + + parser.add_argument('--os-password', + default=utils.env('OS_PASSWORD'), + help='Defaults to env[OS_PASSWORD]') + + parser.add_argument('--os_password', + help=argparse.SUPPRESS) + + parser.add_argument('--os-tenant-id', + default=utils.env('OS_TENANT_ID'), + help='Defaults to env[OS_TENANT_ID]') + + parser.add_argument('--os_tenant_id', + help=argparse.SUPPRESS) + + parser.add_argument('--os-tenant-name', + default=utils.env('OS_TENANT_NAME'), + help='Defaults to env[OS_TENANT_NAME]') + + parser.add_argument('--os_tenant_name', + help=argparse.SUPPRESS) + + parser.add_argument('--os-auth-url', + default=utils.env('OS_AUTH_URL'), + help='Defaults to env[OS_AUTH_URL]') + + parser.add_argument('--os_auth_url', + help=argparse.SUPPRESS) + + parser.add_argument('--os-region-name', + default=utils.env('OS_REGION_NAME'), + help='Defaults to env[OS_REGION_NAME]') + + parser.add_argument('--os_region_name', + help=argparse.SUPPRESS) + + parser.add_argument('--os-auth-token', + default=utils.env('OS_AUTH_TOKEN'), + help='Defaults to env[OS_AUTH_TOKEN]') + + parser.add_argument('--os_auth_token', + help=argparse.SUPPRESS) + + parser.add_argument('--smc-url', + # default=utils.env('SMC_URL'), + default="http://localhost:7777", + help='Defaults to env[SMC_URL]') + + parser.add_argument('--smc_url', + help=argparse.SUPPRESS) + + parser.add_argument('--smc-api-version', + default=utils.env( + 'SMC_API_VERSION', default='1'), + help='Defaults to env[SMC_API_VERSION] ' + 'or 1') + + parser.add_argument('--smc_api_version', + help=argparse.SUPPRESS) + + parser.add_argument('--os-service-type', + default=utils.env('OS_SERVICE_TYPE'), + help='Defaults to env[OS_SERVICE_TYPE]') + + parser.add_argument('--os_service_type', + help=argparse.SUPPRESS) + + parser.add_argument('--os-endpoint-type', + default=utils.env('OS_ENDPOINT_TYPE'), + help='Defaults to env[OS_ENDPOINT_TYPE]') + + parser.add_argument('--os_endpoint_type', + help=argparse.SUPPRESS) + + return parser + + def get_subcommand_parser(self, version): + parser = self.get_base_parser() + + self.subcommands = {} + subparsers = parser.add_subparsers(metavar='') + submodule = utils.import_versioned_module(version, 'shell') + submodule.enhance_parser(parser, subparsers, self.subcommands) + utils.define_commands_from_module(subparsers, self, self.subcommands) + return parser + + def _setup_debugging(self, debug): + if debug: + logging.basicConfig( + format="%(levelname)s (%(module)s:%(lineno)d) %(message)s", + level=logging.DEBUG) + + httplib2.debuglevel = 1 + else: + logging.basicConfig( + format="%(levelname)s %(message)s", + level=logging.CRITICAL) + + def main(self, argv): + # Parse args once to find version + parser = self.get_base_parser() + (options, args) = parser.parse_known_args(argv) + self._setup_debugging(options.debug) + + # build available subcommands based on version + api_version = options.smc_api_version + subcommand_parser = self.get_subcommand_parser(api_version) + self.parser = subcommand_parser + + # Handle top-level --help/-h before attempting to parse + # a command off the command line + if options.help or not argv: + self.do_help(options) + return 0 + + # Parse args again and call whatever callback was selected + args = subcommand_parser.parse_args(argv) + + # Short-circuit and deal with help command right away. + if args.func == self.do_help: + self.do_help(args) + return 0 + + if not (args.os_auth_token and args.smc_url): + if not args.os_username: + raise exc.CommandError("You must provide a username via " + "either --os-username or via " + "env[OS_USERNAME]") + + if not args.os_password: + raise exc.CommandError("You must provide a password via " + "either --os-password or via " + "env[OS_PASSWORD]") + + if not (args.os_tenant_id or args.os_tenant_name): + raise exc.CommandError("You must provide a tenant_id via " + "either --os-tenant-id or via " + "env[OS_TENANT_ID]") + + if not args.os_auth_url: + raise exc.CommandError("You must provide an auth url via " + "either --os-auth-url or via " + "env[OS_AUTH_URL]") + + client = cgclient.get_client(api_version, **(args.__dict__)) + + nargs = args.__dict__ + # nargs['neutron_endpoint'] = client.neutron_endpoint + # client.neutronClient = get_neutron_client(**nargs) + + try: + args.func(client, args) + except exc.Unauthorized: + raise exc.CommandError("Invalid Identity credentials.") + + @utils.arg('command', metavar='', nargs='?', + help='Display help for ') + def do_help(self, args): + """Display help about this program or one of its subcommands.""" + if getattr(args, 'command', None): + if args.command in self.subcommands: + self.subcommands[args.command].print_help() + else: + raise exc.CommandError("'%s' is not a valid subcommand" % + args.command) + else: + self.parser.print_help() + + +class HelpFormatter(argparse.HelpFormatter): + def start_section(self, heading): + # Title-case the headings + heading = '%s%s' % (heading[0].upper(), heading[1:]) + super(HelpFormatter, self).start_section(heading) + + +def main(): + try: + SmcShell().main(sys.argv[1:]) + + except Exception as e: + print >> sys.stderr, e + sys.exit(1) + +if __name__ == "__main__": + main() diff --git a/service-mgmt-client/sm-client/sm_client/v1/__init__.py b/service-mgmt-client/sm-client/sm_client/v1/__init__.py new file mode 100644 index 00000000..69b48868 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/__init__.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + diff --git a/service-mgmt-client/sm-client/sm_client/v1/client.py b/service-mgmt-client/sm-client/sm_client/v1/client.py new file mode 100644 index 00000000..51ba4fcd --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/client.py @@ -0,0 +1,45 @@ +# Copyright 2012 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import http +from sm_client.v1 import iservice +from sm_client.v1 import iservicegroup +from sm_client.v1 import sm_sda +from sm_client.v1 import smservicenode +from sm_client.v1 import sm_nodes + + +class Client(http.HTTPClient): + """Client for the Smc v1 API. + + :param string endpoint: A user-supplied endpoint URL for the smc + service. + :param function token: Provides token for authentication. + :param integer timeout: Allows customization of the timeout for client + http requests. (optional) + """ + + def __init__(self, *args, **kwargs): + """Initialize a new client for the Smc v1 API.""" + super(Client, self).__init__(*args, **kwargs) + self.iservice = iservice.iServiceManager(self) + self.iservicegroup = iservicegroup.iServiceGroupManager(self) + self.sm_sda = sm_sda.Sm_SdaManager(self) + self.sm_nodes = sm_nodes.Sm_NodesManager(self) + self.smservicenode = smservicenode.smServiceNodeManager(self) diff --git a/service-mgmt-client/sm-client/sm_client/v1/iservice.py b/service-mgmt-client/sm-client/sm_client/v1/iservice.py new file mode 100644 index 00000000..88698f59 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/iservice.py @@ -0,0 +1,63 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2013 Red Hat, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import base +from sm_client import exc + + +CREATION_ATTRIBUTES = ['name', 'hostname', 'state', 'activity', 'reason'] +# missing forihostid + + +class iService(base.Resource): + def __repr__(self): + return "" % self._info + + +class iServiceManager(base.Manager): + resource_class = iService + + @staticmethod + def _path(id=None): + return '/v1/services/%s' % id if id else '/v1/services' + + def list(self): + return self._list(self._path(), "services") + + def get(self, iservice_id): + try: + return self._list(self._path(iservice_id))[0] + except IndexError: + return None + + def create(self, **kwargs): + new = {} + for (key, value) in kwargs.items(): + if key in CREATION_ATTRIBUTES: + new[key] = value + else: + raise exc.InvalidAttribute() + return self._create(self._path(), new) + + def delete(self, iservice_id): + return self._delete(self._path(iservice_id)) + + def update(self, iservice_id, patch): + return self._update(self._path(iservice_id), patch) diff --git a/service-mgmt-client/sm-client/sm_client/v1/iservice_shell.py b/service-mgmt-client/sm-client/sm_client/v1/iservice_shell.py new file mode 100644 index 00000000..ed850abe --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/iservice_shell.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import utils +from sm_client import exc + + +def _print_iservice_show(iservice): + fields = ['id', 'name', 'desired_state', 'state', 'status'] + data = dict([(f, getattr(iservice, f, '')) for f in fields]) + utils.print_dict(data, wrap=72) + + +# These are now part of the "system" command +def donot_service_list(cc, args): + """List services.""" + iservice = cc.iservice.list() + fields = ['id', 'name', 'desired_state', 'state', 'status'] + field_labels = ['id', 'name', 'desired_state', 'state', 'status'] + + utils.print_list(iservice, fields, field_labels, sortby=1) + + +@utils.arg('iservice', metavar='', help="ID of iservice") +def donot_service_show(cc, args): + """Show a service.""" + try: + iservice = cc.iservice.get(args.iservice) + except exc.HTTPNotFound: + raise exc.CommandError('service not found: %s' % args.iservice) + else: + _print_iservice_show(iservice) + + +@utils.arg('-c', '--servicename', + metavar='', + help='servicename of the service [REQUIRED]') +@utils.arg('-n', '--hostname', + metavar='', + help='hostname of the service [REQUIRED]') +@utils.arg('-s', '--state', + metavar='', + help='state of the service [REQUIRED]') +@utils.arg('-a', '--activity', + metavar="", + action='append', + help="Record activity key/value metadata. ") +@utils.arg('-r', '--reason', + metavar="", + action='append', + help="Record reason key/value metadata. ") +def donot_service_create(cc, args): + """Create a new service.""" + field_list = ['servicename', 'hostname', 'state', 'activity', 'reason'] + fields = dict((k, v) for (k, v) in vars(args).items() + if k in field_list and not (v is None)) + # fields = utils.args_array_to_dict(fields, 'activity') + fields = utils.args_array_to_dict(fields, 'reason') + iservice = cc.iservice.create(**fields) + + field_list.append('uuid') + data = dict([(f, getattr(iservice, f, '')) for f in field_list]) + utils.print_dict(data, wrap=72) + + +@utils.arg('iservice', + metavar='', + nargs='+', + help="ID of iservice") +def donot_service_delete(cc, args): + """Delete a iservice.""" + for c in args.iservice: + try: + cc.iservice.delete(c) + except exc.HTTPNotFound: + raise exc.CommandError('Service not found: %s' % c) + print 'Deleted service %s' % c + + +@utils.arg('iservice', + metavar='', + help="ID of iservice") +@utils.arg('attributes', + metavar='', + nargs='+', + action='append', + default=[], + help="Attributes to add/replace or remove ") +def donot_service_modify_lab(cc, args): + """LAB ONLY Update a service. """ + # JKUNG comment this out prior to delivery + patch = utils.args_array_to_patch("replace", args.attributes[0]) + try: + iservice = cc.iservice.update(args.iservice, patch) + except exc.HTTPNotFound: + raise exc.CommandError('Service not found: %s' % args.iservice) + _print_iservice_show(iservice) diff --git a/service-mgmt-client/sm-client/sm_client/v1/iservicegroup.py b/service-mgmt-client/sm-client/sm_client/v1/iservicegroup.py new file mode 100644 index 00000000..76253c9c --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/iservicegroup.py @@ -0,0 +1,62 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2013 Red Hat, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import base +from sm_client import exc + + +CREATION_ATTRIBUTES = ['servicename', 'state'] + + +class iService(base.Resource): + def __repr__(self): + return "" % self._info + + +class iServiceGroupManager(base.Manager): + resource_class = iService + + @staticmethod + def _path(id=None): + return '/v1/service_groups/%s' % id if id else '/v1/service_groups' + + def list(self): + return self._list(self._path(), "service_groups") + + def get(self, iservicegroup_id): + try: + return self._list(self._path(iservicegroup_id))[0] + except IndexError: + return None + + def create(self, **kwargs): + new = {} + for (key, value) in kwargs.items(): + if key in CREATION_ATTRIBUTES: + new[key] = value + else: + raise exc.InvalidAttribute() + return self._create(self._path(), new) + + def delete(self, iservicegroup_id): + return self._delete(self._path(iservicegroup_id)) + + def update(self, iservicegroup_id, patch): + return self._update(self._path(iservicegroup_id), patch) diff --git a/service-mgmt-client/sm-client/sm_client/v1/iservicegroup_shell.py b/service-mgmt-client/sm-client/sm_client/v1/iservicegroup_shell.py new file mode 100644 index 00000000..b7b61468 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/iservicegroup_shell.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import utils +from sm_client import exc + + +def _print_iservicegroup_show(iservicegroup): + fields = ['id', 'name', 'state', 'status'] + data = dict([(f, getattr(iservicegroup, f, '')) for f in fields]) + utils.print_dict(data, wrap=72) + + +def do_servicegroup_list(cc, args): + """List Service Groups.""" + iservicegroup = cc.iservicegroup.list() + fields = ['id', 'name', 'state', 'status'] + field_labels = ['id', 'name', 'state', 'status'] + utils.print_list(iservicegroup, fields, field_labels, sortby=1) + + +@utils.arg('servicegroup', metavar='', + help="ID of iservicegroup") +def do_servicegroup_show(cc, args): + """Show a Service Group.""" + try: + servicegroup = cc.iservicegroup.get(args.servicegroup) + except exc.HTTPNotFound: + raise exc.CommandError( + 'Service Group not found: %s' % args.servicegroup) + else: + _print_iservicegroup_show(servicegroup) + + +@utils.arg('-n', '--name', + metavar='', + help='name of the service group [REQUIRED]') +@utils.arg('-s', '--state', + metavar='', + help='state of the servicegroup [REQUIRED]') +def donot_servicegroup_create(cc, args): + """Create a new servicegroup.""" + field_list = ['name', 'state'] + fields = dict((k, v) for (k, v) in vars(args).items() + if k in field_list and not (v is None)) + # fields = utils.args_array_to_dict(fields, 'activity') + iservicegroup = cc.iservicegroup.create(**fields) + + field_list.append('uuid') + data = dict([(f, getattr(iservicegroup, f, '')) for f in field_list]) + utils.print_dict(data, wrap=72) + + +@utils.arg('iservicegroup', + metavar='', + nargs='+', + help="ID of iservicegroup") +def donot_servicegroup_delete(cc, args): + """Delete a servicegroup.""" + for c in args.iservicegroup: + try: + cc.iservicegroup.delete(c) + except exc.HTTPNotFound: + raise exc.CommandError('Service not found: %s' % c) + print 'Deleted servicegroup %s' % c + + +@utils.arg('iservicegroup', + metavar='', + help="ID of iservicegroup") +@utils.arg('attributes', + metavar='', + nargs='+', + action='append', + default=[], + help="Attributes to add/replace or remove ") +def donot_servicegroup_modify_labonly(cc, args): + """LAB ONLY Update a servicegroup. """ + # JKUNG comment this out prior to delivery + patch = utils.args_array_to_patch("replace", args.attributes[0]) + try: + iservicegroup = cc.iservicegroup.update(args.iservicegroup, patch) + except exc.HTTPNotFound: + raise exc.CommandError( + 'Service Group not found: %s' % args.iservicegroup) + _print_iservicegroup_show(iservicegroup) diff --git a/service-mgmt-client/sm-client/sm_client/v1/shell.py b/service-mgmt-client/sm-client/sm_client/v1/shell.py new file mode 100644 index 00000000..b4ac7422 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/shell.py @@ -0,0 +1,35 @@ +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# + + +from sm_client.common import utils +from sm_client.v1 import iservicegroup_shell +from sm_client.v1 import iservice_shell +from sm_client.v1 import smservicenode_shell +from sm_client.v1 import sm_sda_shell +from sm_client.v1 import sm_nodes_shell + +COMMAND_MODULES = [ + iservicegroup_shell, + iservice_shell, + smservicenode_shell, + sm_sda_shell, + sm_nodes_shell +] + + +def enhance_parser(parser, subparsers, cmd_mapper): + '''Take a basic (nonversioned) parser and enhance it with + commands and options specific for this version of API. + + :param parser: top level parser :param subparsers: top level + parser's subparsers collection where subcommands will go + ''' + for command_module in COMMAND_MODULES: + utils.define_commands_from_module(subparsers, command_module, + cmd_mapper) diff --git a/service-mgmt-client/sm-client/sm_client/v1/sm_nodes.py b/service-mgmt-client/sm-client/sm_client/v1/sm_nodes.py new file mode 100644 index 00000000..55c588d7 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/sm_nodes.py @@ -0,0 +1,62 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2013 Red Hat, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import base +from sm_client import exc + + +CREATION_ATTRIBUTES = ['servicename', 'state'] + + +class sm_Nodes(base.Resource): + def __repr__(self): + return "" % self._info + + +class Sm_NodesManager(base.Manager): + resource_class = sm_Nodes + + @staticmethod + def _path(id=None): + return '/v1/nodes/%s' % id if id else '/v1/nodes' + + def list(self): + return self._list(self._path(), "nodes") + + def get(self, nodes_id): + try: + return self._list(self._path(nodes_id))[0] + except IndexError: + return None + + def create(self, **kwargs): + new = {} + for (key, value) in kwargs.items(): + if key in CREATION_ATTRIBUTES: + new[key] = value + else: + raise exc.InvalidAttribute() + return self._create(self._path(), new) + + def delete(self, nodes_id): + return self._delete(self._path(nodes_id)) + + def update(self, nodes_id, patch): + return self._update(self._path(nodes_id), patch) diff --git a/service-mgmt-client/sm-client/sm_client/v1/sm_nodes_shell.py b/service-mgmt-client/sm-client/sm_client/v1/sm_nodes_shell.py new file mode 100644 index 00000000..0254164c --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/sm_nodes_shell.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import utils +from sm_client import exc + + +def _print_sm_node_show(node): + fields = ['id', 'name', 'state', 'online'] + data = dict([(f, getattr(node, f, '')) for f in fields]) + utils.print_dict(data, wrap=72) + + +def do_node_list(cc, args): + """List Node(s).""" + node = cc.sm_nodes.list() + fields = ['id', 'name', 'state', 'online'] + field_labels = ['id', 'name', 'state', 'online'] + utils.print_list(node, fields, field_labels, sortby=1) + + +@utils.arg('node', metavar='', + help="uuid of a Service Domain Assignment") +def do_node_show(cc, args): + """Show a Node.""" + try: + node = cc.sm_nodes.get(args.node) + except exc.HTTPNotFound: + raise exc.CommandError( + 'Service Domain Assignment not found: %s' % args.node) + else: + _print_sm_node_show(node) diff --git a/service-mgmt-client/sm-client/sm_client/v1/sm_sda.py b/service-mgmt-client/sm-client/sm_client/v1/sm_sda.py new file mode 100644 index 00000000..66ec5a5f --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/sm_sda.py @@ -0,0 +1,62 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2013 Red Hat, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import base +from sm_client import exc + + +CREATION_ATTRIBUTES = ['servicename', 'state'] + + +class sm_Sda(base.Resource): + def __repr__(self): + return "" % self._info + + +class Sm_SdaManager(base.Manager): + resource_class = sm_Sda + + @staticmethod + def _path(id=None): + return '/v1/sm_sda/%s' % id if id else '/v1/sm_sda' + + def list(self): + return self._list(self._path(), "sm_sda") + + def get(self, sm_sda_id): + try: + return self._list(self._path(sm_sda_id))[0] + except IndexError: + return None + + def create(self, **kwargs): + new = {} + for (key, value) in kwargs.items(): + if key in CREATION_ATTRIBUTES: + new[key] = value + else: + raise exc.InvalidAttribute() + return self._create(self._path(), new) + + def delete(self, sm_sda_id): + return self._delete(self._path(sm_sda_id)) + + def update(self, sm_sda_id, patch): + return self._update(self._path(sm_sda_id), patch) diff --git a/service-mgmt-client/sm-client/sm_client/v1/sm_sda_shell.py b/service-mgmt-client/sm-client/sm_client/v1/sm_sda_shell.py new file mode 100755 index 00000000..cda25cc6 --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/sm_sda_shell.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import utils +from sm_client import exc + + +def _print_sm_sda_show(sm_sda): + fields = ['id', 'uuid', 'name', 'node_name', 'service_group_name', + 'desired_state', 'state', 'status', 'condition'] + data = dict([(f, getattr(sm_sda, f, '')) for f in fields]) + utils.print_dict(data, wrap=72) + + +def do_sda_list(cc, args): + """List Service Domain Assignments.""" + sm_sda = cc.sm_sda.list() + fields = ['uuid', 'service_group_name', 'node_name', 'state', 'status', + 'condition'] + field_labels = ['uuid', 'service_group_name', 'node_name', + 'state', 'status', 'condition'] + utils.print_list(sm_sda, fields, field_labels, sortby=1) + + +@utils.arg('sm_sda', metavar='', + help="uuid of a Service Domain Assignment") +def do_sda_show(cc, args): + """Show a Service Domain Assignment.""" + try: + sm_sda = cc.sm_sda.get(args.sm_sda) + except exc.HTTPNotFound: + raise exc.CommandError( + 'Service Domain Assignment not found: %s' % args.sm_sda) + else: + _print_sm_sda_show(sm_sda) diff --git a/service-mgmt-client/sm-client/sm_client/v1/smservicenode.py b/service-mgmt-client/sm-client/sm_client/v1/smservicenode.py new file mode 100644 index 00000000..f7dbe01c --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/smservicenode.py @@ -0,0 +1,62 @@ +# -*- encoding: utf-8 -*- +# +# Copyright © 2013 Red Hat, Inc +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import base +from sm_client import exc + + +CREATION_ATTRIBUTES = ['servicename', 'state'] + + +class smService(base.Resource): + def __repr__(self): + return "" % self._info + + +class smServiceNodeManager(base.Manager): + resource_class = smService + + @staticmethod + def _path(id=None): + return '/v1/servicenode/%s' % id if id else '/v1/servicenode' + + def list(self, hostname): + return self._list(self._path(hostname), "servicenode") + + def get(self, smservicenode_id): + try: + return self._list(self._path(smservicenode_id))[0] + except IndexError: + return None + + def create(self, **kwargs): + new = {} + for (key, value) in kwargs.items(): + if key in CREATION_ATTRIBUTES: + new[key] = value + else: + raise exc.InvalidAttribute() + return self._create(self._path(), new) + + def delete(self, smservicenode_id): + return self._delete(self._path(smservicenode_id)) + + def update(self, smservicenode_id, patch): + return self._update(self._path(smservicenode_id), patch) diff --git a/service-mgmt-client/sm-client/sm_client/v1/smservicenode_shell.py b/service-mgmt-client/sm-client/sm_client/v1/smservicenode_shell.py new file mode 100644 index 00000000..d0791b1a --- /dev/null +++ b/service-mgmt-client/sm-client/sm_client/v1/smservicenode_shell.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 Red Hat, Inc. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +from sm_client.common import utils +from sm_client import exc + + +def _print_smservicenode_show(smservicenode): + fields = ['id', 'uuid', 'name', 'node_name', 'service_group_name', + 'desired_state', 'state', 'status'] + data = dict([(f, getattr(smservicenode, f, '')) for f in fields]) + utils.print_dict(data, wrap=72) + + +@utils.arg('hostname', metavar='', + help="hostname of servicenode") +def donot_servicenode_list(cc, args): + """List sm servicenodes by hostname.""" + smservicenode = cc.smservicenode.list(args.hostname) + fields = ['uuid', 'name', 'node_name', 'service_group_name', + 'state', 'status'] + field_labels = ['uuid', 'name', 'node_name', 'service_group_name', + 'state', 'status'] + utils.print_list(smservicenode, fields, field_labels, sortby=1) + + +@utils.arg('smservicenode', metavar='', + help="uuid of smservicenode") +def donot_servicenode_show(cc, args): + """Show an smservicenode.""" + try: + smservicenode = cc.smservicenode.get(args.smservicenode) + except exc.HTTPNotFound: + raise exc.CommandError( + 'servicenode not found: %s' % args.smservicenode) + else: + _print_smservicenode_show(smservicenode) diff --git a/service-mgmt-client/sm-client/tools_junk/__init__.py b/service-mgmt-client/sm-client/tools_junk/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/service-mgmt-client/sm-client/tools_junk/install_venv_common.py b/service-mgmt-client/sm-client/tools_junk/install_venv_common.py new file mode 100644 index 00000000..15916651 --- /dev/null +++ b/service-mgmt-client/sm-client/tools_junk/install_venv_common.py @@ -0,0 +1,216 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2013 OpenStack Foundation +# Copyright 2013 IBM Corp. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# + + +"""Provides methods needed by installation script for OpenStack development +virtual environments. + +Since this script is used to bootstrap a virtualenv from the system's Python +environment, it should be kept strictly compatible with Python 2.6. + +Synced in from openstack-common +""" + +from __future__ import print_function + +import optparse +import os +import subprocess +import sys + + +class InstallVenv(object): + + def __init__(self, root, venv, requirements, + test_requirements, py_version, + project): + self.root = root + self.venv = venv + self.requirements = requirements + self.test_requirements = test_requirements + self.py_version = py_version + self.project = project + + def die(self, message, *args): + print(message % args, file=sys.stderr) + sys.exit(1) + + def check_python_version(self): + if sys.version_info < (2, 6): + self.die("Need Python Version >= 2.6") + + def run_command_with_code(self, cmd, redirect_output=True, + check_exit_code=True): + """Runs a command in an out-of-process shell. + + Returns the output of that command. Working directory is self.root. + """ + if redirect_output: + stdout = subprocess.PIPE + else: + stdout = None + + proc = subprocess.Popen(cmd, cwd=self.root, stdout=stdout) + output = proc.communicate()[0] + if check_exit_code and proc.returncode != 0: + self.die('Command "%s" failed.\n%s', ' '.join(cmd), output) + return (output, proc.returncode) + + def run_command(self, cmd, redirect_output=True, check_exit_code=True): + return self.run_command_with_code(cmd, redirect_output, + check_exit_code)[0] + + def get_distro(self): + if (os.path.exists('/etc/fedora-release') or + os.path.exists('/etc/redhat-release')): + return Fedora( + self.root, self.venv, self.requirements, + self.test_requirements, self.py_version, self.project) + else: + return Distro( + self.root, self.venv, self.requirements, + self.test_requirements, self.py_version, self.project) + + def check_dependencies(self): + self.get_distro().install_virtualenv() + + def create_virtualenv(self, no_site_packages=True): + """Creates the virtual environment and installs PIP. + + Creates the virtual environment and installs PIP only into the + virtual environment. + """ + if not os.path.isdir(self.venv): + print('Creating venv...', end=' ') + if no_site_packages: + self.run_command(['virtualenv', '-q', '--no-site-packages', + self.venv]) + else: + self.run_command(['virtualenv', '-q', self.venv]) + print('done.') + else: + print("venv already exists...") + pass + + def pip_install(self, *args): + self.run_command(['tools/with_venv.sh', + 'pip', 'install', '--upgrade'] + list(args), + redirect_output=False) + + def install_dependencies(self): + print('Installing dependencies with pip (this can take a while)...') + + # First things first, make sure our venv has the latest pip and + # setuptools. + self.pip_install('pip>=1.3') + self.pip_install('setuptools') + + self.pip_install('-r', self.requirements) + self.pip_install('-r', self.test_requirements) + + def post_process(self): + self.get_distro().post_process() + + def parse_args(self, argv): + """Parses command-line arguments.""" + parser = optparse.OptionParser() + parser.add_option('-n', '--no-site-packages', + action='store_true', + help="Do not inherit packages from global Python " + "install") + return parser.parse_args(argv[1:])[0] + + +class Distro(InstallVenv): + + def check_cmd(self, cmd): + return bool(self.run_command(['which', cmd], + check_exit_code=False).strip()) + + def install_virtualenv(self): + if self.check_cmd('virtualenv'): + return + + if self.check_cmd('easy_install'): + print('Installing virtualenv via easy_install...', end=' ') + if self.run_command(['easy_install', 'virtualenv']): + print('Succeeded') + return + else: + print('Failed') + + self.die('ERROR: virtualenv not found.\n\n%s development' + ' requires virtualenv, please install it using your' + ' favorite package management tool' % self.project) + + def post_process(self): + """Any distribution-specific post-processing gets done here. + + In particular, this is useful for applying patches to code inside + the venv. + """ + pass + + +class Fedora(Distro): + """This covers all Fedora-based distributions. + + Includes: Fedora, RHEL, CentOS, Scientific Linux + """ + + def check_pkg(self, pkg): + return self.run_command_with_code(['rpm', '-q', pkg], + check_exit_code=False)[1] == 0 + + def apply_patch(self, originalfile, patchfile): + self.run_command(['patch', '-N', originalfile, patchfile], + check_exit_code=False) + + def install_virtualenv(self): + if self.check_cmd('virtualenv'): + return + + if not self.check_pkg('python-virtualenv'): + self.die("Please install 'python-virtualenv'.") + + super(Fedora, self).install_virtualenv() + + def post_process(self): + """Workaround for a bug in eventlet. + + This currently affects RHEL6.1, but the fix can safely be + applied to all RHEL and Fedora distributions. + + This can be removed when the fix is applied upstream. + + Nova: https://bugs.launchpad.net/nova/+bug/884915 + Upstream: https://bitbucket.org/eventlet/eventlet/issue/89 + RHEL: https://bugzilla.redhat.com/958868 + """ + + # Install "patch" program if it's not there + if not self.check_pkg('patch'): + self.die("Please install 'patch'.") + + # Apply the eventlet patch + self.apply_patch(os.path.join(self.venv, 'lib', self.py_version, + 'site-packages', + 'eventlet/green/subprocess.py'), + 'contrib/redhat-eventlet.patch') diff --git a/service-mgmt-client/sm-client/tools_junk/with_venv.sh b/service-mgmt-client/sm-client/tools_junk/with_venv.sh new file mode 100755 index 00000000..a2d8baa1 --- /dev/null +++ b/service-mgmt-client/sm-client/tools_junk/with_venv.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# +# Copyright (c) 2013-2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +tools_path=${tools_path:-$(dirname $0)} +venv_path=${venv_path:-${tools_path}} +venv_dir=${venv_name:-/../.venv} +TOOLS=${tools_path} +VENV=${venv:-${venv_path}/${venv_dir}} +source ${VENV}/bin/activate && "$@" diff --git a/service-mgmt-tools/centos/build_srpm.data b/service-mgmt-tools/centos/build_srpm.data new file mode 100644 index 00000000..cefac972 --- /dev/null +++ b/service-mgmt-tools/centos/build_srpm.data @@ -0,0 +1,4 @@ +SRC_DIR=sm-tools +TAR_NAME=sm-tools +VERSION=1.0 +TIS_PATCH_VER=1 diff --git a/service-mgmt-tools/centos/sm-tools.spec b/service-mgmt-tools/centos/sm-tools.spec new file mode 100644 index 00000000..8a53cd35 --- /dev/null +++ b/service-mgmt-tools/centos/sm-tools.spec @@ -0,0 +1,56 @@ +Summary: Service Management Tools +Name: sm-tools +Version: 1.0 +Release: %{tis_patch_ver}%{?_tis_dist} +License: Apache-2.0 +Group: base +Packager: Wind River +URL: unknown +Source0: %{name}-%{version}.tar.gz + +%define debug_package %{nil} + +BuildRequires: python +BuildRequires: python-setuptools +Requires: python-libs + +%prep +%setup -q + +%build +%{__python2} setup.py build + +%install +%global _buildsubdir %{_builddir}/%{name}-%{version} +%{__python2} setup.py install -O1 --skip-build --root %{buildroot} + +%description +Service Management Tools + +#%package -n sm-tools-py-src-tar +#Summary: Service Management Tools source tarball +#Group: base + +#%description -n sm-tools-py-src-tar +#Service Management Tools source tarball + + +#%post -n sm-tools-py-src-tar +## sm-tools-py-src-tar - postinst +# if [ -f $D/usr/src/sm-tools-1.0.tar.bz2 ] ; then +# ( cd $D/ && tar -xf $D/usr/src/sm-tools-1.0.tar.bz2 ) +# fi + + +%files +%defattr(-,root,root,-) +%dir "/usr/lib/python2.7/site-packages/sm_tools" +/usr/lib/python2.7/site-packages/sm_tools/* +%dir "/usr/lib/python2.7/site-packages/sm_tools-1.0.0-py2.7.egg-info" +/usr/lib/python2.7/site-packages/sm_tools-1.0.0-py2.7.egg-info/* +/usr/bin/* + +#%files -n sm-tools-py-src-tar +#%defattr(-,-,-,-) +#"/usr/src/sm-tools-1.0.tar.bz2" + diff --git a/service-mgmt-tools/sm-tools/LICENSE b/service-mgmt-tools/sm-tools/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/service-mgmt-tools/sm-tools/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/service-mgmt-tools/sm-tools/setup.py b/service-mgmt-tools/sm-tools/setup.py new file mode 100755 index 00000000..8ad33521 --- /dev/null +++ b/service-mgmt-tools/sm-tools/setup.py @@ -0,0 +1,29 @@ +# +# Copyright (c) 2013-2014, 2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import setuptools + +setuptools.setup( + name='sm_tools', + description='Service Management Tools', + version='1.0.0', + license='Apache-2.0', + packages=['sm_tools'], + entry_points={ + 'console_scripts': [ + 'sm-configure = sm_tools.sm_configure:main', + 'sm-provision = sm_tools.sm_provision:main', + 'sm-deprovision = sm_tools.sm_provision:main ', + 'sm-dump = sm_tools.sm_dump:main', + 'sm-query = sm_tools.sm_query:main', + 'sm-patch = sm_tools.sm_patch:main', + 'sm-manage = sm_tools.sm_action:main', + 'sm-unmanage = sm_tools.sm_action:main ', + 'sm-restart-safe = sm_tools.sm_action:main ', + 'sm-restart = sm_tools.sm_action:main ', + 'sm-iface-state = sm_tools.sm_domain_interface_set_state:main ' + ]} +) diff --git a/service-mgmt-tools/sm-tools/sm_tools/__init__.py b/service-mgmt-tools/sm-tools/sm_tools/__init__.py new file mode 100644 index 00000000..147b74f9 --- /dev/null +++ b/service-mgmt-tools/sm-tools/sm_tools/__init__.py @@ -0,0 +1,5 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# diff --git a/service-mgmt-tools/sm-tools/sm_tools/sm_action.py b/service-mgmt-tools/sm-tools/sm_tools/sm_action.py new file mode 100644 index 00000000..cbe3ddaf --- /dev/null +++ b/service-mgmt-tools/sm-tools/sm_tools/sm_action.py @@ -0,0 +1,88 @@ +# +# Copyright (c) 2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +import os +import sys +import argparse +import sqlite3 + +from sm_api_msg_utils import restart_service as restart_service +from sm_api_msg_utils import restart_service_safe as restart_service_safe +from sm_api_msg_utils import database_running_name as database_name + + +def main(): + filename = os.path.basename(sys.argv[0]) + if "sm-manage" == filename: + action = "manage" + elif "sm-unmanage" == filename: + action = "unmanage" + elif "sm-restart-safe" == filename: + action = "restart-safe" + else: + action = "restart" + + try: + parser = argparse.ArgumentParser(description='SM Action ') + subparsers = parser.add_subparsers(help='types') + + # Service + service_parser = subparsers.add_parser('service', help='service action') + service_parser.set_defaults(which='service') + service_parser.add_argument('service', help='service name') + + args = parser.parse_args() + + if args.which == 'service': + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + cursor.execute("SELECT * FROM SERVICES WHERE NAME = '%s';" + % args.service) + row = cursor.fetchone() + if row is None: + print "Given service (%s) does not exist." % args.service + sys.exit() + + database.close() + + SM_VAR_RUN_SERVICES_DIR = '/var/run/sm/services' + unmanage_filepath = SM_VAR_RUN_SERVICES_DIR + '/' + unmanage_filename = "%s.unmanaged" % args.service + + if 'manage' == action: + if os.path.exists(SM_VAR_RUN_SERVICES_DIR): + if os.path.isfile(unmanage_filepath + unmanage_filename): + os.remove(unmanage_filepath + unmanage_filename) + + print "Service (%s) is now being managed." % args.service + + elif 'unmanage' == action: + if not os.path.exists(SM_VAR_RUN_SERVICES_DIR): + os.makedirs(SM_VAR_RUN_SERVICES_DIR) + + if not os.path.isfile(unmanage_filepath + unmanage_filename): + open(unmanage_filepath + unmanage_filename, 'w').close() + + print "Service (%s) is no longer being managed." % args.service + + elif 'restart-safe' == action: + restart_service_safe(args.service) + print "Service (%s) is restarting." % args.service + + else: + restart_service(args.service) + + print "Service (%s) is restarting." % args.service + + sys.exit(0) + + except KeyboardInterrupt: + sys.exit() + + except Exception as e: + print e + sys.exit(-1) \ No newline at end of file diff --git a/service-mgmt-tools/sm-tools/sm_tools/sm_api_msg_utils.py b/service-mgmt-tools/sm-tools/sm_tools/sm_api_msg_utils.py new file mode 100644 index 00000000..e586ca80 --- /dev/null +++ b/service-mgmt-tools/sm-tools/sm_tools/sm_api_msg_utils.py @@ -0,0 +1,68 @@ +# +# Copyright (c) 2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +import time +import socket + +database_name = "/var/lib/sm/sm.db" +database_running_name = "/var/run/sm/sm.db" + +SM_API_SERVER_ADDR = "/tmp/.sm_server_api" + +SM_API_MSG_VERSION = "1" +SM_API_MSG_REVISION = "1" + +SM_API_MSG_TYPE_RESTART_SERVICE = "RESTART_SERVICE" +SM_API_MSG_SKIP_DEP_CHECK = "skip-dep" + +SM_API_MSG_TYPE_RELOAD_DATA = "RELOAD_DATA" + +SM_API_MSG_TYPE_SDI_SET_STATE = "SERVICE_DOMAIN_INTERFACE_SET_STATE" + +# offsets +SM_API_MSG_VERSION_FIELD = 0 +SM_API_MSG_REVISION_FIELD = 1 +SM_API_MSG_SEQNO_FIELD = 2 +SM_API_MSG_TYPE_FIELD = 3 +SM_API_MSG_ORIGIN_FIELD = 4 +SM_API_MSG_SERVICE_NAME_FIELD = 5 +SM_API_MSG_PARAM = 6 + + +def _send_msg_to_sm(sm_api_msg): + s = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) + try: + s.setblocking(True) + s.sendto(sm_api_msg, SM_API_SERVER_ADDR) + time.sleep(1) + + except socket.error, e: + print "sm-api socket error: %s on %s" % (e, sm_api_msg) + + +def restart_service(service_name): + """ + Message SM to restart a service + """ + sm_api_msg = ("%s,%s,%i,%s,%s,%s" + % (SM_API_MSG_VERSION, SM_API_MSG_REVISION, 1, + SM_API_MSG_TYPE_RESTART_SERVICE, "sm-action", + service_name)) + + _send_msg_to_sm(sm_api_msg) + + +def restart_service_safe(service_name): + """ + Message SM to restart a service w/o checking dependency + """ + sm_api_msg = ("%s,%s,%i,%s,%s,%s,%s" + % (SM_API_MSG_VERSION, SM_API_MSG_REVISION, 1, + SM_API_MSG_TYPE_RESTART_SERVICE, "sm-action", + service_name, SM_API_MSG_SKIP_DEP_CHECK)) + + _send_msg_to_sm(sm_api_msg) + diff --git a/service-mgmt-tools/sm-tools/sm_tools/sm_configure.py b/service-mgmt-tools/sm-tools/sm_tools/sm_configure.py new file mode 100644 index 00000000..77d3b157 --- /dev/null +++ b/service-mgmt-tools/sm-tools/sm_tools/sm_configure.py @@ -0,0 +1,223 @@ +# +# Copyright (c) 2014-2015 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +import sys +import argparse +import sqlite3 +from netaddr import IPNetwork +from sm_api_msg_utils import database_name as database_name + +cpe_duplex = "duplex" +cpe_duplex_direct = "duplex-direct" +mgmt_if = 'management-interface' +infra_if = 'infrastructure-interface' +tor_connect = 'tor' +dc_connect = 'dc' +database_name = "/var/lib/sm/sm.db" + + +def main(): + try: + parser = argparse.ArgumentParser(description='SM Configuration') + subparsers = parser.add_subparsers(help='types') + + if_parser = subparsers.add_parser('interface', + help='Interface Configuration') + if_parser.set_defaults(which='interface') + if_parser.add_argument('service_domain', help='service domain name') + if_parser.add_argument('service_domain_interface', + help='service domain interface name') + if_parser.add_argument('network_multicast', help='network multicast') + if_parser.add_argument('network_address', help='network address') + if_parser.add_argument('network_port', help='network port') + if_parser.add_argument('network_heartbeat_port', + help='network heartbeat port') + if_parser.add_argument('network_peer_address', + help='network peer address') + if_parser.add_argument('network_peer_port', help='network peer port') + if_parser.add_argument('network_peer_heartbeat_port', + help='network peer heartbeat port') + + si_parser = subparsers.add_parser('service_instance', + help='Service Instance ' + 'Configuration') + si_parser.set_defaults(which='service_instance') + si_parser.add_argument('service', help='service name') + si_parser.add_argument('instance', help='instance name') + si_parser.add_argument('parameters', help='instance parameters') + + sys_parser = subparsers.add_parser('system', + help='system Configuration') + sys_parser.set_defaults(which='system') + sys_parser.add_argument( + "--cpe_mode", choices=[cpe_duplex, cpe_duplex_direct], + required=True, + help='cpe mode, available selections: %s, %s' % ( + cpe_duplex, cpe_duplex_direct) + ) + + sg_parser = subparsers.add_parser('service_group', + help='Service Group ' + 'Configuration') + sg_parser.set_defaults(which='service_group') + sg_parser.add_argument('provisioned', help='provisioned') + sg_parser.add_argument('service_domain', help='service domain name') + sg_parser.add_argument('service_group', help='service group name') + sg_parser.add_argument('redundancy', help='redundancy mode') + sg_parser.add_argument('active', help='number of active unit') + sg_parser.add_argument('standby', help='number of standby unit') + sg_parser.add_argument('aggregate', help='service group aggregate') + sg_parser.add_argument('active_only', help='active only if active') + + args = parser.parse_args() + + if args.which == "system": + if cpe_duplex == args.cpe_mode: + configure_cpe_duplex() + elif cpe_duplex_direct == args.cpe_mode: + configure_cpe_dc() + else: + database = sqlite3.connect(database_name) + _dispatch_config_action(args, database) + database.close() + + sys.exit(0) + + except KeyboardInterrupt: + sys.exit() + + except Exception as e: + print e + sys.exit(-1) + + +def _dispatch_config_action(args, database): + if args.which == 'interface': + + cursor = database.cursor() + + cursor.execute("SELECT INTERFACE_NAME FROM " + "SERVICE_DOMAIN_INTERFACES WHERE " + "SERVICE_DOMAIN = '%s' and " + "SERVICE_DOMAIN_INTERFACE = '%s';" + % (args.service_domain, + args.service_domain_interface)) + + data = cursor.fetchone() + + if IPNetwork(args.network_address).version == 6: + network_type = "ipv6-udp" + else: + network_type = "ipv4-udp" + + if data is not None: + cursor.execute("UPDATE SERVICE_DOMAIN_INTERFACES SET " + "NETWORK_TYPE = '%s', " + "NETWORK_MULTICAST = '%s', " + "NETWORK_ADDRESS = '%s', " + "NETWORK_PORT = '%s', " + "NETWORK_HEARTBEAT_PORT = '%s', " + "NETWORK_PEER_ADDRESS = '%s', " + "NETWORK_PEER_PORT = '%s', " + "NETWORK_PEER_HEARTBEAT_PORT = '%s' " + "WHERE SERVICE_DOMAIN = '%s' and " + "SERVICE_DOMAIN_INTERFACE = '%s';" + % (network_type, + args.network_multicast, + args.network_address, + args.network_port, + args.network_heartbeat_port, + args.network_peer_address, + args.network_peer_port, + args.network_peer_heartbeat_port, + args.service_domain, + args.service_domain_interface)) + database.commit() + + if args.which == 'service_instance': + + cursor = database.cursor() + + cursor.execute("SELECT SERVICE_NAME FROM SERVICE_INSTANCES " + "WHERE SERVICE_NAME = '%s';" % args.service) + + data = cursor.fetchone() + + if data is None: + cursor.execute("INSERT INTO SERVICE_INSTANCES " + "VALUES( NULL, '%s', '%s', '%s' );" + % (args.service, args.instance, + args.parameters)) + else: + cursor.execute("UPDATE SERVICE_INSTANCES SET " + "INSTANCE_NAME = '%s', " + "INSTANCE_PARAMETERS = '%s' " + "WHERE SERVICE_NAME = '%s';" + % (args.instance, args.parameters, + args.service)) + + database.commit() + + if args.which == 'service_group': + + cursor = database.cursor() + + cursor.execute("SELECT SERVICE_GROUP_NAME FROM SERVICE_DOMAIN_MEMBERS " + "WHERE NAME = '%s' and " + "SERVICE_GROUP_NAME = '%s';" + % (args.service_domain, + args.service_group)) + + data = cursor.fetchone() + + if data is None: + cursor.execute("INSERT INTO SERVICE_DOMAIN_MEMBERS " + "VALUES( NULL, '%s', '%s', '%s', '%s'," + "'%s', '%s', '%s', '%s');" + % (args.provisioned, + args.service_domain, + args.service_group, + args.redundancy, + args.active, + args.standby, + args.aggregate, + args.active_only)) + else: + cursor.execute("UPDATE SERVICE_DOMAIN_MEMBERS SET " + "REDUNDANCY_MODEL = '%s', " + "N_ACTIVE = '%s', " + "M_STANDBY = '%s', " + "SERVICE_GROUP_AGGREGATE = '%s' " + "WHERE SERVICE_GROUP_NAME = '%s';" + % (args.redundancy, + args.active, + args.standby, + args.aggregate, + args.service_group + )) + + database.commit() + + +def configure_cpe_duplex(): + configure_if_connect_type(mgmt_if, tor_connect) + configure_if_connect_type(infra_if, tor_connect) + + +def configure_cpe_dc(): + configure_if_connect_type(mgmt_if, dc_connect) + configure_if_connect_type(infra_if, dc_connect) + + +def configure_if_connect_type(if_name, connect_type): + database = sqlite3.connect(database_name) + + cursor = database.cursor() + sql = "UPDATE SERVICE_DOMAIN_INTERFACES SET INTERFACE_CONNECT_TYPE='%s' " \ + "WHERE SERVICE_DOMAIN_INTERFACE = '%s'" % (connect_type, if_name) + + cursor.execute(sql) + database.commit() + database.close() diff --git a/service-mgmt-tools/sm-tools/sm_tools/sm_dump.py b/service-mgmt-tools/sm-tools/sm_tools/sm_dump.py new file mode 100755 index 00000000..24919ee9 --- /dev/null +++ b/service-mgmt-tools/sm-tools/sm_tools/sm_dump.py @@ -0,0 +1,193 @@ +# +# Copyright (c) 2014-2015 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +import os +import sys +import argparse +import sqlite3 +import psutil +import ntpath +import os.path + +database_name = "/var/run/sm/sm.db" + + +def get_pid(pid_file): + if os.path.isfile(pid_file): + with open(pid_file, "r") as f: + pid = f.readline().strip('\n ') + try: + pid = int(pid) + except: + pid = -1 + return pid + return -1 + + +def get_process_name(pid): + if pid < 0: + return '' + + try: + p = psutil.Process(pid) + name = p.name() + if name == 'python': + cmd_line = p.cmdline() + if len(cmd_line) > 1: + name = ntpath.basename(cmd_line[1]) + + return name + except: + # most likely it is a leftover pid + return '' + + +def main(): + try: + parser = argparse.ArgumentParser(description='SM Dump') + parser.add_argument("--verbose", help="increase dump output", + action="store_true") + parser.add_argument("--pid", help="print pid", + action="store_true") + parser.add_argument("--pn", help="print process name", + action="store_true") + parser.add_argument("--pid_file", help="print pid file name", + action="store_true") + parser.add_argument("--impact", help="severity of service failure", + action="store_true") + args = parser.parse_args() + + if not os.path.exists(database_name): + print "%s not available." % database_name + sys.exit(0) + + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + if args.verbose: + # Service-Groups Dump + print "\n-Service_Groups%s" % ('-' * 92) + + cursor.execute("SELECT name, desired_state, state, status, " + "condition from service_groups WHERE " + "PROVISIONED = 'yes';") + + data = cursor.fetchall() + + if data is not None: + for row in data: + print "%-32s %-20s %-20s %-10s %-20s" % (row[0], row[1], + row[2], row[3], + row[4]) + + print "%s" % ('-' * 107) + + # Services Dump + len = 98 + if args.impact: + len += 10 + if args.pid: + len += 9 + if args.pn: + len += 22 + if args.pid_file: + len += 28 + + print "\n-Services%s" % ('-' * len) + + cursor.execute("SELECT s.name, s.desired_state, s.state, " + "s.status, s.condition, s.pid_file, " + "g.SERVICE_FAILURE_IMPACT " + "from services s, service_group_members g " + "WHERE s.PROVISIONED = 'yes' and " + "s.name = g.service_name;") + + data = cursor.fetchall() + + if data is not None: + for row in data: + pid_file = row[5] + pid = get_pid(pid_file) + pn = get_process_name(pid) + msg = "%-32s %-20s %-20s " % (row[0], row[1],row[2]) + if args.impact: + msg += "%-10s" % (row[6]) + if args.pid: + msg += "%-7s" % (pid if pid > 0 else '') + if args.pn: + msg += "%-20s" % (pn) + if args.pid_file: + msg += "%-25s" % (pid_file) + msg += "%-10s %20s" % (row[3], row[4]) + print msg + + print "%s" % ('-' * len) + + else: + # Service-Groups Dump + print "\n-Service_Groups%s" % ('-' * 72) + + cursor.execute("SELECT name, desired_state, state, status " + "from service_groups WHERE PROVISIONED = 'yes';") + + data = cursor.fetchall() + + if data is not None: + for row in data: + print "%-32s %-20s %-20s %-10s" % (row[0], row[1], row[2], + row[3]) + + print "%s" % ('-' * 87) + + len = 78 + if args.impact: + len += 10 + if args.pid: + len += 9 + if args.pn: + len += 22 + if args.pid_file: + len += 28 + + # Services Dump + print "\n-Services%s" % ('-' * len) + + cursor.execute("SELECT s.name, s.desired_state, s.state, s.status, " + "s.pid_file, g.SERVICE_FAILURE_IMPACT " + "from services s, service_group_members g " + "where s.provisioned = 'yes' and " + "s.name = g.service_name;") + + data = cursor.fetchall() + + if data is not None: + for row in data: + pid_file = row[4] + pid = get_pid(pid_file) + pn = get_process_name(pid) + msg = "%-32s %-20s %-20s " % (row[0], row[1],row[2]) + if args.impact: + msg += "%-10s" % (row[5]) + if args.pid: + msg += "%-7s" % (pid if pid > 0 else '') + if args.pn: + msg += "%-20s" % (pn) + if args.pid_file: + msg += "%-25s" % (pid_file) + msg += "%-10s " % (row[3]) + print msg + + print "%s" % ('-' * len) + + database.close() + + except KeyboardInterrupt: + sys.exit() + + except Exception as e: + print e + sys.exit(-1) + diff --git a/service-mgmt-tools/sm-tools/sm_tools/sm_patch.py b/service-mgmt-tools/sm-tools/sm_tools/sm_patch.py new file mode 100644 index 00000000..e6a7c0c7 --- /dev/null +++ b/service-mgmt-tools/sm-tools/sm_tools/sm_patch.py @@ -0,0 +1,59 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +import os +import sys +import argparse +import sqlite3 + +database_patches_dir = "/var/lib/sm/patches/" +database_master_name = "/var/lib/sm/sm.db" +database_running_name = "/var/run/sm/sm.db" + + +def main(): + + try: + parser = argparse.ArgumentParser(description='SM Patch') + subparsers = parser.add_subparsers(help='types') + db_parser = subparsers.add_parser('database', help='Database') + db_parser.set_defaults(which='database') + db_parser.add_argument('which_database', help='master or running') + db_parser.add_argument('patch_name', help='patch name') + + args = parser.parse_args() + + if args.which == 'database': + if args.which_database == 'master': + if not os.path.exists(database_master_name): + print "%s not available." % database_master_name + sys.exit() + + database = sqlite3.connect(database_master_name) + else: + if not os.path.exists(database_running_name): + print "%s not available." % database_running_name + sys.exit() + + database = sqlite3.connect(database_running_name) + + cursor = database.cursor() + + with open(database_patches_dir + args.patch_name) as patch_file: + for line in patch_file: + if not line.startswith('#'): + cursor.execute(line) + + database.commit() + database.close() + + sys.exit(0) + + except KeyboardInterrupt: + sys.exit() + + except Exception as e: + print e + sys.exit(-1) diff --git a/service-mgmt-tools/sm-tools/sm_tools/sm_provision.py b/service-mgmt-tools/sm-tools/sm_tools/sm_provision.py new file mode 100755 index 00000000..42867e6d --- /dev/null +++ b/service-mgmt-tools/sm-tools/sm_tools/sm_provision.py @@ -0,0 +1,160 @@ +# +# Copyright (c) 2015 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +import os +import sys +import argparse +import sqlite3 + +database_name = "/var/lib/sm/sm.db" + + +def main(): + file_name = os.path.basename(sys.argv[0]) + if "sm-provision" == file_name: + provision_str = "yes" + else: + provision_str = "no" + + try: + parser = argparse.ArgumentParser(description='SM Provision ') + subparsers = parser.add_subparsers(help='types') + + # Domain + sd = subparsers.add_parser('service-domain', + help='Provision Service Domain') + sd.set_defaults(which='service_domain') + sd.add_argument('service_domain', help='service domain name') + + # Domain Member + sd_member_parser = subparsers.add_parser('service-domain-member', + help='Provision Service ' + 'Domain Member') + sd_member_parser.set_defaults(which='service_domain_member') + sd_member_parser.add_argument('service_domain', + help='service domain name') + sd_member_parser.add_argument('service_group', + help='service group name') + + # Domain Interface + sd_member_parser = subparsers.add_parser('service-domain-interface', + help='Provision Service ' + 'Domain Interface') + sd_member_parser.set_defaults(which='service_domain_interface') + sd_member_parser.add_argument('service_domain', + help='service domain name') + sd_member_parser.add_argument('service_domain_interface', + help='service domain interface name') + + # Service-Group + sg = subparsers.add_parser('service-group', + help='Provision Service Group') + sg.set_defaults(which='service_group') + sg.add_argument('service_group', help='service group name') + + # Service-Group-Member + sg_member_parser = subparsers.add_parser('service-group-member', + help='Provision Service Group ' + 'Member') + sg_member_parser.set_defaults(which='service_group_member') + sg_member_parser.add_argument('service_group', + help='service group name') + sg_member_parser.add_argument('service_group_member', + help='service group member name') + + # Service + service_parser = subparsers.add_parser('service', + help='Provision Service') + service_parser.set_defaults(which='service') + service_parser.add_argument('service', help='service name') + + args = parser.parse_args() + + if args.which == 'service_domain': + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + cursor.execute("UPDATE SERVICE_DOMAINS SET " + "PROVISIONED = '%s' WHERE NAME = '%s';" + % (provision_str, args.service_domain)) + + database.commit() + database.close() + + elif args.which == 'service_domain_member': + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + cursor.execute("UPDATE SERVICE_DOMAIN_MEMBERS SET " + "PROVISIONED = '%s' WHERE NAME = '%s' and " + "SERVICE_GROUP_NAME = '%s';" + % (provision_str, args.service_domain, + args.service_group)) + + database.commit() + database.close() + + elif args.which == 'service_domain_interface': + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + cursor.execute("UPDATE SERVICE_DOMAIN_INTERFACES SET " + "PROVISIONED = '%s' WHERE SERVICE_DOMAIN = '%s' and " + "SERVICE_DOMAIN_INTERFACE = '%s';" + % (provision_str, args.service_domain, + args.service_domain_interface)) + + database.commit() + database.close() + + elif args.which == 'service_group': + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + cursor.execute("UPDATE SERVICE_GROUPS SET " + "PROVISIONED = '%s' WHERE NAME = '%s';" + % (provision_str, args.service_group)) + + database.commit() + database.close() + + elif args.which == 'service_group_member': + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + cursor.execute("UPDATE SERVICE_GROUP_MEMBERS SET " + "PROVISIONED = '%s' WHERE NAME = '%s' and " + "SERVICE_NAME = '%s';" + % (provision_str, args.service_group, + args.service_group_member)) + + database.commit() + database.close() + + elif args.which == 'service': + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + cursor.execute("UPDATE SERVICES SET " + "PROVISIONED = '%s' WHERE NAME = '%s';" + % (provision_str, args.service)) + + database.commit() + database.close() + + sys.exit(0) + + except KeyboardInterrupt: + sys.exit() + + except Exception as e: + print e + sys.exit(-1) diff --git a/service-mgmt-tools/sm-tools/sm_tools/sm_query.py b/service-mgmt-tools/sm-tools/sm_tools/sm_query.py new file mode 100644 index 00000000..5f8c67f8 --- /dev/null +++ b/service-mgmt-tools/sm-tools/sm_tools/sm_query.py @@ -0,0 +1,61 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +import os +import sys +import argparse +import sqlite3 + +database_name = "/var/run/sm/sm.db" + + +def main(): + + if not os.path.exists(database_name): + print "%s not available." % database_name + sys.exit(0) + + try: + parser = argparse.ArgumentParser(description='SM Query') + subparsers = parser.add_subparsers(help='types') + + s_parser = subparsers.add_parser('service', help='Query Service') + s_parser.set_defaults(which='service') + s_parser.add_argument('service_name', help='service name') + + args = parser.parse_args() + + if args.which == 'service': + database = sqlite3.connect(database_name) + + cursor = database.cursor() + + cursor.execute("SELECT NAME, DESIRED_STATE, STATE, STATUS FROM " + "SERVICES WHERE NAME = '%s';" + % args.service_name) + + row = cursor.fetchone() + + if row is None: + print "%s is disabled." % args.service_name + + else: + service_name = row[0] + state = row[2] + status = row[3] + + if status == 'none': + print "%s is %s" % (service_name, state) + else: + print "%s is %s-%s" % (service_name, state, status) + + database.close() + + except KeyboardInterrupt: + sys.exit() + + except Exception as e: + print e + sys.exit(-1) diff --git a/service-mgmt/LICENSE b/service-mgmt/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/service-mgmt/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/service-mgmt/sm-1.0.0/LICENSE b/service-mgmt/sm-1.0.0/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/service-mgmt/sm-1.0.0/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/service-mgmt/sm-1.0.0/Makefile b/service-mgmt/sm-1.0.0/Makefile new file mode 100644 index 00000000..fe76b58e --- /dev/null +++ b/service-mgmt/sm-1.0.0/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +build: + @(cd src; make build ) + +install_non_bb: + @(cd src; make $@) + @(cd scripts; make $@) + +clean: + @( cd src; make clean ) diff --git a/service-mgmt/sm-1.0.0/centos/build_srpm.data b/service-mgmt/sm-1.0.0/centos/build_srpm.data new file mode 100644 index 00000000..cfe7ee97 --- /dev/null +++ b/service-mgmt/sm-1.0.0/centos/build_srpm.data @@ -0,0 +1,5 @@ +SRC_DIR=$PKG_BASE +COPY_LIST="$PKG_BASE/LICENSE" +TAR_NAME=sm +VERSION=1.0.0 +TIS_PATCH_VER=23 diff --git a/service-mgmt/sm-1.0.0/centos/sm.spec b/service-mgmt/sm-1.0.0/centos/sm.spec new file mode 100644 index 00000000..778fb1f6 --- /dev/null +++ b/service-mgmt/sm-1.0.0/centos/sm.spec @@ -0,0 +1,98 @@ +Summary: Service Management +Name: sm +Version: 1.0.0 +Release: %{tis_patch_ver}%{?_tis_dist} +License: Apache-2.0 +Group: base +Packager: Wind River +URL: unknown +Source0: %{name}-%{version}.tar.gz +Source1: LICENSE + +BuildRequires: fm-common-dev +BuildRequires: sm-db-dev +BuildRequires: sm-common-dev +BuildRequires: glib2-devel +BuildRequires: glibc +BuildRequires: sqlite-devel +BuildRequires: gcc +BuildRequires: libuuid-devel +BuildRequires: json-c +BuildRequires: json-c-devel +BuildRequires: openssl-devel + + +# BuildRequires is to get %_unitdir I think +BuildRequires: systemd +BuildRequires: systemd-devel +Requires(post): systemd +Requires(preun): systemd + +# Needed for /etc/init.d, can be removed when we go fully systemd +Requires: chkconfig +# Needed for /etc/pmon.d +Requires: cgts-mtce-common-pmon +# Needed for /etc/logrotate.d +Requires: logrotate +# for collect stuff +Requires: time + +%description +Service Managment + +#%package -n sm-dbg +#Summary: Service Management - Debugging files +#Group: devel +#Recommends: sm = 1.0.0-r10.0 + +#%description -n sm-dbg +#Service Managment This package contains ELF symbols and related sources +#for debugging purposes. + +%prep +%autosetup + +%build +VER=%{version} +MAJOR=`echo $VER | awk -F . '{print $1}'` +make -j"%(nproc)" + +%install +rm -rf $RPM_BUILD_ROOT +VER=%{version} +MAJOR=`echo $VER | awk -F . '{print $1}'` +make DEST_DIR=$RPM_BUILD_ROOT UNIT_DIR=%{_unitdir} install_non_bb + +%post +/usr/bin/systemctl enable sm.service >/dev/null 2>&1 +/usr/bin/systemctl enable sm-shutdown.service >/dev/null 2>&1 + + +%files +%license LICENSE +%defattr(-,root,root,-) +%{_unitdir}/* +"/usr/bin/sm" +"/usr/local/sbin/sm-notify" +"/usr/local/sbin/sm-troubleshoot" +"/usr/local/sbin/sm-notification" +"/etc/init.d/sm" +"/etc/init.d/sm-shutdown" +"/etc/pmon.d/sm.conf" +"/etc/logrotate.d/sm.logrotate" + +#%files -n sm-dbg +#%defattr(-,-,-,-) +#%dir "/usr" +#%dir "/usr/bin" +#%dir "/usr/src" +#%dir "/usr/bin/.debug" +#"/usr/bin/.debug/sm" +#%dir "/usr/src/debug" +#%dir "/usr/src/debug/sm" +#%dir "/usr/src/debug/sm/1.0.0-r10" +#%dir "/usr/src/debug/sm/1.0.0-r10/src" +#/usr/src/debug/sm/1.0.0-r10/src/*.c +#/usr/src/debug/sm/1.0.0-r10/src/*.h + + diff --git a/service-mgmt/sm-1.0.0/scripts/Makefile b/service-mgmt/sm-1.0.0/scripts/Makefile new file mode 100644 index 00000000..6471cf35 --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/Makefile @@ -0,0 +1,15 @@ +install_non_bb: + install -d ${DEST_DIR}/etc/init.d + install sm ${DEST_DIR}/etc/init.d/sm + install sm.shutdown ${DEST_DIR}/etc/init.d/sm-shutdown + install -d ${DEST_DIR}/etc/pmon.d + install -m 644 sm.conf ${DEST_DIR}/etc/pmon.d/sm.conf + install -d ${DEST_DIR}/etc/logrotate.d + install -m 644 sm.logrotate ${DEST_DIR}/etc/logrotate.d/sm.logrotate + install -d 755 ${DEST_DIR}/usr/local/sbin + install sm.notify ${DEST_DIR}/usr/local/sbin/sm-notify + install sm.troubleshoot ${DEST_DIR}/usr/local/sbin/sm-troubleshoot + install sm.notification ${DEST_DIR}/usr/local/sbin/sm-notification + install -d $(DEST_DIR)$(UNIT_DIR) + install -m 644 *.service $(DEST_DIR)$(UNIT_DIR) + diff --git a/service-mgmt/sm-1.0.0/scripts/sm b/service-mgmt/sm-1.0.0/scripts/sm new file mode 100755 index 00000000..fa51152c --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm @@ -0,0 +1,155 @@ +#! /bin/sh +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# chkconfig: - 84 84 +# processname: sm +# description: Service Management Engine +# +### BEGIN INIT INFO +# Description: sm +# +# Short-Description: Service Management Engine. +# Provides: sm +# Required-Start: $network +# Should-Start: $syslog +# Required-Stop: $network +# Default-Start: 3 5 +# Default-Stop: 0 6 +### END INIT INFO + +. /etc/init.d/functions + +RETVAL=0 + +SM_NAME="sm" +SM="/usr/bin/${SM_NAME}" +SM_PIDFILE="/var/run/${SM_NAME}.pid" + +if [ ! -e "${SM}" ] +then + logger "${SM} is missing" + exit 5 +fi + +PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin +COMPUTE_RESERVED_FILE=/etc/nova/compute_reserved.conf +SM_PLATFORM_CORES_FILE=/var/run/sm/.platform_cores + +export PATH + +case "$1" in + start) + if [ -f $COMPUTE_RESERVED_FILE ]; then + . $COMPUTE_RESERVED_FILE + mkdir /var/run/sm -p + echo $PLATFORM_CPU_LIST > $SM_PLATFORM_CORES_FILE + fi + sm_args="" + if [ "`/usr/bin/facter is_virtual`" = "true" ] + then + sm_args="--interval-extension 10 --timeout-extension 30" + fi + + echo -n "Starting ${SM_NAME}: " + if [ -n "`pidof ${SM}`" ] + then + # PMOND might have restarted SM already. + RETVAL=0 + else + start-stop-daemon --start -b -x ${SM} -- ${sm_args} + RETVAL=$? + fi + if [ ${RETVAL} -eq 0 ] + then + echo "OK" + else + echo "FAIL" + RETVAL=1 + fi + ;; + + stop) + echo -n "Stopping ${SM_NAME}: " + if [ -n "`pidof ${SM}`" ] + then + killproc ${SM} + fi + + SHUTDOWN_TIMEOUT=20 + count=0 + while [ ${count} -lt ${SHUTDOWN_TIMEOUT} ] + do + pidof ${SM} &> /dev/null + rc=$? + if [ ${rc} -eq 1 ] + then + echo "OK" + break + fi + count=`expr ${count} + 1` + sleep 1 + done + + pidof ${SM} &> /dev/null + rc=$? + if [ ${rc} -eq 0 ] + then + echo "FAIL" + RETVAL=7 + fi + + rm -f ${SM_PIDFILE} + ;; + + status) + pid=`cat ${SM_PIDFILE} 2>/dev/null` + if [ -n "${pid}" ] + then + if ps -p ${pid} &>/dev/null + then + echo "${SM_NAME} is running" + RETVAL=0 + else + echo "${SM_NAME} is not running but has pid file" + RETVAL=1 + fi + else + echo "${SM_NAME} is not running" + RETVAL=3 + fi + ;; + + restart) + pid=`cat ${SM_PIDFILE} 2>/dev/null` + if [ -n "${pid}" ] + then + kill -USR2 ${pid} + fi + $0 stop + sleep 1 + $0 start + ;; + + reload) + pid=`cat ${SM_PIDFILE} 2>/dev/null` + if [ -n "${pid}" ] + then + echo "${SM_NAME} reload" + kill -HUP ${pid} + fi + ;; + + force-reload) + echo "${SM_NAME} force-reload" + $0 restart + ;; + + *) + echo "usage: $0 { start | stop | status | restart | reload | force-reload }" + ;; +esac + +exit ${RETVAL} diff --git a/service-mgmt/sm-1.0.0/scripts/sm-shutdown.service b/service-mgmt/sm-1.0.0/scripts/sm-shutdown.service new file mode 100644 index 00000000..5b093dfd --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm-shutdown.service @@ -0,0 +1,13 @@ +[Unit] +Description=Service Management Shutdown Unit +After=sm.service + +[Service] +Type=oneshot +User=root +ExecStop=/etc/init.d/sm-shutdown stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/service-mgmt/sm-1.0.0/scripts/sm.conf b/service-mgmt/sm-1.0.0/scripts/sm.conf new file mode 100644 index 00000000..97747ec9 --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm.conf @@ -0,0 +1,16 @@ +; +; Copyright (c) 2014 Wind River Systems, Inc. +; +; SPDX-License-Identifier: Apache-2.0 +; +[process] +process = sm +pidfile = /var/run/sm.pid +script = /etc/init.d/sm +style = lsb ; lsb +severity = critical ; minor, major, critical +restarts = 3 ; restarts before error assertion +startuptime = 5 ; seconds to wait after process start +interval = 5 ; number of seconds to wait between restarts +debounce = 20 ; number of seconds to wait before degrade clear +quorum = 1 ; process is in the host watchdog quorum diff --git a/service-mgmt/sm-1.0.0/scripts/sm.logrotate b/service-mgmt/sm-1.0.0/scripts/sm.logrotate new file mode 100644 index 00000000..e19b3802 --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm.logrotate @@ -0,0 +1,61 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +nodateext + +/var/log/sm-customer.alarm +{ + nodateext + size 100M + start 1 + missingok + rotate 20 + compress + copytruncate +} + +/var/log/sm-customer.log +{ + nodateext + size 100M + start 1 + missingok + rotate 20 + compress + copytruncate +} + +/var/log/sm-scheduler.log +{ + nodateext + size 100M + start 1 + missingok + rotate 20 + compress + copytruncate +} + +/var/log/sm-trap.log +{ + nodateext + size 100M + start 1 + missingok + rotate 20 + compress + copytruncate +} + +/var/log/sm-troubleshoot.log +{ + nodateext + size 100M + start 1 + missingok + rotate 20 + compress + copytruncate +} diff --git a/service-mgmt/sm-1.0.0/scripts/sm.notification b/service-mgmt/sm-1.0.0/scripts/sm.notification new file mode 100644 index 00000000..a8af2d56 --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm.notification @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014-2016 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# The following environment Variables are set, +# NOTIFICATION_SEQNUM= +# SERVICE_GROUP_AGGREGATE_NAME= +# SERVICE_GROUP_AGGREGATE_DESIRED_STATE= +# SERVICE_GROUP_AGGREGATE_STATE= +# +# SERVICE_GROUP_NAME= +# SERVICE_GROUP_DESIRED_STATE= +# SERVICE_GROUP_STATE= +# SERVICE_GROUP_NOTIFICATION= +# +# where service-group-state is one of: +# unknown, standby, go-standby, go-active, active, disabling, +# disabled, shutdown +# +# where service-group-notification is one of: +# unknown, standby, go-standby, go-active, active, disabling, +# disabled, shutdown +# +import six +import os +import sys +import subprocess +import datetime +import tsconfig.tsconfig as tsconfig + + +def get_time(): + return datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S") + + +def main(): + want_log_file = False + + notification_seqnum = os.environ.get('NOTIFICATION_SEQNUM', '-1') + sg_aggregate_name = os.environ.get('SERVICE_GROUP_AGGREGATE_NAME', '') + sg_aggregate_desired_state = \ + os.environ.get('SERVICE_GROUP_AGGREGATE_DESIRED_STATE', '') + sg_aggregate_state = os.environ.get('SERVICE_GROUP_AGGREGATE_STATE', '') + + sg_name = os.environ.get('SERVICE_GROUP_NAME', '') + sg_desired_state = os.environ.get('SERVICE_GROUP_DESIRED_STATE', '') + sg_state = os.environ.get('SERVICE_GROUP_STATE', '') + sg_notification = os.environ.get('SERVICE_GROUP_NOTIFICATION', '') + + sm_log_file = "/tmp/sm-notification.log" + + if want_log_file: + with open(sm_log_file, 'a') as f: + six.print_("=======================================", file=f) + six.print_(" TIME: %s" % get_time(), file=f) + six.print_("SEQUENCE_NUMBER: %s" % notification_seqnum, file=f) + six.print_("", file=f) + + if 0 < len(sg_aggregate_name): + six.print_("SERVICE_GROUP_AGGREGATE", file=f) + six.print_(" name: %s" % sg_aggregate_name, file=f) + six.print_(" desired_state: %s" % sg_aggregate_desired_state, + file=f) + six.print_(" state: %s" % sg_aggregate_state, file=f) + six.print_("", file=f) + + six.print_("SERVICE_GROUP", file=f) + six.print_(" name: %s" % sg_name, file=f) + six.print_(" desired_state: %s" % sg_desired_state, file=f) + six.print_(" state: %s" % sg_state, file=f) + six.print_(" notification: %s" % sg_notification, file=f) + + # Script to start/stop compute services. Called here for CPE upgrade + # support. Scripts will be run in a separate process so it does not + # block sm. + if 'compute' in tsconfig.subfunctions: + compute_services_script = "/etc/init.d/compute_services" + if sg_name == 'vim-services': + if sg_desired_state == "active" and sg_state == "active": + if want_log_file: + with open(sm_log_file, 'a') as f: + six.print_("Called script: %s start" % + compute_services_script, file=f) + subprocess.Popen([compute_services_script, "start"]) + elif sg_aggregate_state == "go-standby" \ + and sg_desired_state == "standby" \ + and sg_state == "standby": + if want_log_file: + with open(sm_log_file, 'a') as f: + six.print_("Called script: %s stop" % + compute_services_script, file=f) + subprocess.Popen([compute_services_script, "stop"]) + + +if __name__ == '__main__': + try: + main() + except Exception as e: + print "Exception occurred: %s" % e + + sys.exit(0) diff --git a/service-mgmt/sm-1.0.0/scripts/sm.notify b/service-mgmt/sm-1.0.0/scripts/sm.notify new file mode 100644 index 00000000..c9331729 --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm.notify @@ -0,0 +1,40 @@ +#! /bin/bash +# +# Copyright (c) 2015 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +# Read the options +TEMP=`getopt -o s:e: --long service:,event: -n 'test.sh' -- "$@"` +eval set -- "$TEMP" + +# Extract options and their arguments into variables. +while true +do + case "$1" in + -s|--service) + SERVICE=$2 + shift 2 + ;; + + -e|--event) + EVENT=$2 + shift 2 + ;; + + --) + shift + break + ;; + + *) + echo "Unknown argument given, arg=$1" + exit 1 + ;; + esac +done + +echo "1,1,SERVICE_EVENT,sm-notify,$SERVICE,$EVENT," | socat - unix-sendto:/tmp/.sm_notify_api + +exit 0 diff --git a/service-mgmt/sm-1.0.0/scripts/sm.service b/service-mgmt/sm-1.0.0/scripts/sm.service new file mode 100644 index 00000000..18be2c06 --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm.service @@ -0,0 +1,16 @@ +[Unit] +Description=Service Management Unit +After=network-online.target syslog-ng.service config.service sm-watchdog.service systemd-udev-settle.service +Before=sm-shutdown.service sm-api.service pmon.service + +[Service] +Type=forking +RemainAfterExit=yes +User=root +ExecStart=/etc/init.d/sm start +ExecStop=/etc/init.d/sm stop +PIDFile=/var/run/sm.pid +KillMode=process + +[Install] +WantedBy=multi-user.target diff --git a/service-mgmt/sm-1.0.0/scripts/sm.shutdown b/service-mgmt/sm-1.0.0/scripts/sm.shutdown new file mode 100644 index 00000000..4d7764dd --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm.shutdown @@ -0,0 +1,40 @@ +#! /bin/sh +# +# Copyright (c) 2014-2017 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +case "$1" in + start) + ;; + + stop) + . /etc/platform/platform.conf + if [[ "$subfunction" == "controller,compute"* ]]; then + # Trigger logout of iSCSI connections to avoid shutdown race condition + /sbin/iscsiadm -m node --logoutall=all + fi + touch /var/run/.sm_node_unhealthy + + date >> /var/log/sm-shutdown.log + echo "Shutdown SM." >> /var/log/sm-shutdown.log + + sleep 5 + ;; + + status) + ;; + + restart) + ;; + + reload) + ;; + + force-reload) + ;; + + *) +esac + diff --git a/service-mgmt/sm-1.0.0/scripts/sm.troubleshoot b/service-mgmt/sm-1.0.0/scripts/sm.troubleshoot new file mode 100644 index 00000000..6a2b2f3d --- /dev/null +++ b/service-mgmt/sm-1.0.0/scripts/sm.troubleshoot @@ -0,0 +1,166 @@ +#! /bin/bash +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +LOGFILE=$1 +if [ -n "$LOGFILE" ] +then + exec >> $LOGFILE +fi + +exec 2>&1 + +export COLUMNS=768 + +HOSTNAME=`hostname` + +function delimiter() +{ + echo " " + echo "--------------------------------------------------------------------" + echo "`date` : ${HOSTNAME} : ${1}" + echo "--------------------------------------------------------------------" +} + +delimiter "uname -a" +timeout --signal KILL 5s uname -a + +delimiter "cat /etc/motd" +timeout --signal KILL 5s cat /etc/motd + +delimiter "ntpq -n -p" +timeout --signal KILL 5s /usr/sbin/ntpq -n -p + +delimiter "cat /proc/stat" +timeout --signal KILL 5s cat /proc/stat + +delimiter "cat /proc/cpuinfo" +timeout --signal KILL 5s cat /proc/cpuinfo + +delimiter "cat /proc/meminfo" +timeout --signal KILL 5s cat /proc/meminfo + +delimiter "chkconfig --list" +timeout --signal KILL 5s /usr/sbin/chkconfig --list + +delimiter "sm-dump" +timeout --signal KILL 5s sm-dump + +delimiter "find /etc/init.d/ -type f -exec sha512sum {} \;" +timeout --signal KILL 5s find /etc/init.d/ -type f -exec sha512sum {} \; + +delimiter "find /usr/lib/ocf/ -type f -exec sha512sum {} \;" +timeout --signal KILL 5s find /usr/lib/ocf/ -type f -exec sha512sum {} \; + +delimiter "top -b -n 1 -H -p cat /var/run/sm.pid, cat /var/run/sm-trap.pid" +timeout --signal KILL 5s top -b -n 1 -H -p `cat /var/run/sm.pid`, `cat /var/run/sm-trap.pid` + +delimiter "pmap -x cat /var/run/sm.pid" +timeout --signal KILL 5s pmap -x `cat /var/run/sm.pid` + +delimiter "pmap -x cat /var/run/sm-trap.pid" +timeout --signal KILL 5s pmap -x `cat /var/run/sm-trap.pid` + +delimiter "pmap -x cat /var/run/sm-eru.pid" +timeout --signal KILL 5s pmap -x `cat /var/run/sm-eru.pid` + +delimiter "pmap -x cat /var/run/sm-watchdog.pid" +timeout --signal KILL 5s pmap -x `cat /var/run/sm-watchdog.pid` + +delimiter "top -b -n 1 -H -c" +timeout --signal KILL 5s top -b -n 1 -H -c + +delimiter "top -b -n 1 -H -c" +timeout --signal KILL 5s top -b -n 1 -H -c + +delimiter "pstree" +timeout --signal KILL 5s pstree + +delimiter "ps -elfL" +timeout --signal KILL 5s ps -elfL + +delimiter "ip -s link show" +timeout --signal KILL 5s /sbin/ip -s link show + +delimiter "ip addr show" +timeout --signal KILL 5s /sbin/ip addr show + +delimiter "ip neigh" +timeout --signal KILL 5s /sbin/ip neigh + +delimiter "ip route" +timeout --signal KILL 5s /sbin/ip route + +delimiter "tc -s qdisc show" +timeout --signal KILL 5s /sbin/tc -s qdisc show + +delimiter "iptables -nvL" +timeout --signal KILL 5s /usr/sbin/iptables -nvL + +delimiter "cat /etc/hosts" +timeout --signal KILL 5s cat /etc/hosts + +delimiter "cat /etc/services" +timeout --signal KILL 5s cat /etc/services + +delimiter "netstat -anpo" +timeout --signal KILL 5s netstat -anpo + +delimiter "ping -c 2 controller-0" +timeout --signal KILL 5s ping -c 2 controller-0 + +delimiter "ping -c 2 controller-1" +timeout --signal KILL 5s ping -c 2 controller-1 + +delimiter "drbd-overview" +timeout --signal KILL 5s /usr/sbin/drbd-overview + +delimiter "cat /proc/drbd" +timeout --signal KILL 5s cat /proc/drbd + +delimiter "nfsstat -o all" +timeout --signal KILL 5s /usr/sbin/nfsstat -o all + +delimiter "df -h" +timeout --signal KILL 5s df -h + +delimiter "mount" +timeout --signal KILL 5s mount + +delimiter "exportfs" +timeout --signal KILL 5s /usr/sbin/exportfs + +delimiter "tgtadm --lld iscsi --op show --mode target" +timeout --signal KILL 5s /usr/sbin/tgtadm --lld iscsi --op show --mode target + +delimiter "pvdisplay" +timeout --signal KILL 5s /usr/sbin/pvdisplay + +delimiter "lvdisplay" +timeout --signal KILL 5s /usr/sbin/lvdisplay + +delimiter "fdisk -l" +timeout --signal KILL 5s /sbin/fdisk -l + +delimiter "cat /proc/scsi/scsi" +timeout --signal KILL 5s cat /proc/scsi/scsi + +delimiter "cat /proc/partitions" +timeout --signal KILL 5s cat /proc/partitions + +delimiter "cat /proc/diskstats" +timeout --signal KILL 5s cat /proc/diskstats + +delimiter "cat /proc/net/igmp" +timeout --signal KILL 5s cat /proc/net/igmp + +delimiter "cat /proc/net/igmp6" +timeout --signal KILL 5s cat /proc/net/igmp6 + +delimiter "ip maddr" +timeout --signal KILL 5s /sbin/ip maddr + +exit 0 diff --git a/service-mgmt/sm-1.0.0/src/Makefile b/service-mgmt/sm-1.0.0/src/Makefile new file mode 100644 index 00000000..f4e6de87 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/Makefile @@ -0,0 +1,130 @@ +# +# Copyright (c) 2014-2018 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +INCLUDES =-I$(STAGING_DIR)/usr/include/glib-2.0 +INCLUDES+=-I$(STAGING_DIR)/usr/lib64/glib-2.0/include + +SRCS=main.c +SRCS+=sm_process.c +SRCS+=sm_process_death.c +SRCS+=sm_heartbeat.c +SRCS+=sm_heartbeat_msg.c +SRCS+=sm_heartbeat_thread.c +SRCS+=sm_log.c +SRCS+=sm_log_thread.c +SRCS+=sm_alarm.c +SRCS+=sm_alarm_thread.c +SRCS+=sm_troubleshoot.c +SRCS+=sm_api.c +SRCS+=sm_notify_api.c +SRCS+=sm_msg.c +SRCS+=sm_node_api.cpp +SRCS+=sm_node_fsm.c +SRCS+=sm_node_unknown_state.c +SRCS+=sm_node_enabled_state.c +SRCS+=sm_node_disabled_state.c +SRCS+=sm_service_domain_table.c +SRCS+=sm_service_domain_member_table.c +SRCS+=sm_service_domain_interface_table.c +SRCS+=sm_service_domain_neighbor_table.c +SRCS+=sm_service_domain_assignment_table.c +SRCS+=sm_service_domain_api.c +SRCS+=sm_service_domain_utils.c +SRCS+=sm_service_domain_fsm.c +SRCS+=sm_service_domain_initial_state.c +SRCS+=sm_service_domain_waiting_state.c +SRCS+=sm_service_domain_other_state.c +SRCS+=sm_service_domain_backup_state.c +SRCS+=sm_service_domain_leader_state.c +SRCS+=sm_service_domain_interface_api.c +SRCS+=sm_service_domain_interface_fsm.c +SRCS+=sm_service_domain_interface_unknown_state.c +SRCS+=sm_service_domain_interface_enabled_state.c +SRCS+=sm_service_domain_interface_disabled_state.c +SRCS+=sm_service_domain_neighbor_fsm.c +SRCS+=sm_service_domain_neighbor_down_state.c +SRCS+=sm_service_domain_neighbor_exchange_start_state.c +SRCS+=sm_service_domain_neighbor_exchange_state.c +SRCS+=sm_service_domain_neighbor_full_state.c +SRCS+=sm_service_domain_scheduler.c +SRCS+=sm_service_domain_filter.c +SRCS+=sm_service_domain_weight.c +SRCS+=sm_service_group_table.c +SRCS+=sm_service_group_member_table.c +SRCS+=sm_service_group_api.c +SRCS+=sm_service_group_health.c +SRCS+=sm_service_group_engine.c +SRCS+=sm_service_group_fsm.c +SRCS+=sm_service_group_initial_state.c +SRCS+=sm_service_group_active_state.c +SRCS+=sm_service_group_go_active_state.c +SRCS+=sm_service_group_go_standby_state.c +SRCS+=sm_service_group_standby_state.c +SRCS+=sm_service_group_disabling_state.c +SRCS+=sm_service_group_disabled_state.c +SRCS+=sm_service_group_shutdown_state.c +SRCS+=sm_service_group_enable.c +SRCS+=sm_service_group_go_active.c +SRCS+=sm_service_group_go_standby.c +SRCS+=sm_service_group_disable.c +SRCS+=sm_service_group_audit.c +SRCS+=sm_service_group_notification.c +SRCS+=sm_service_table.c +SRCS+=sm_service_dependency_table.c +SRCS+=sm_service_action_table.c +SRCS+=sm_service_action_result_table.c +SRCS+=sm_service_api.c +SRCS+=sm_service_dependency.c +SRCS+=sm_service_engine.c +SRCS+=sm_service_fsm.c +SRCS+=sm_service_initial_state.c +SRCS+=sm_service_unknown_state.c +SRCS+=sm_service_enabled_active_state.c +SRCS+=sm_service_enabled_go_active_state.c +SRCS+=sm_service_enabled_go_standby_state.c +SRCS+=sm_service_enabled_standby_state.c +SRCS+=sm_service_enabling_state.c +SRCS+=sm_service_enabling_throttle_state.c +SRCS+=sm_service_disabling_state.c +SRCS+=sm_service_disabled_state.c +SRCS+=sm_service_shutdown_state.c +SRCS+=sm_service_enable.c +SRCS+=sm_service_go_active.c +SRCS+=sm_service_go_standby.c +SRCS+=sm_service_disable.c +SRCS+=sm_service_audit.c +SRCS+=sm_service_action.c +SRCS+=sm_service_heartbeat.c +SRCS+=sm_service_heartbeat_api.c +SRCS+=sm_service_heartbeat_thread.c +SRCS+=sm_main_event_handler.c +SRCS+=fm_api_wrapper.c +SRCS+=sm_failover.c +SRCS+=sm_failover_thread.c +SRCS+=sm_swact_state.c +SRCS+=sm_task_affining_thread.c +SRCS+=sm_node_swact_monitor.cpp +SRCS+=sm_service_domain_interface_not_in_use_state.c +SRCS+=sm_configuration_table.c + +OBJS= $(SRCS:.c=.o) +CCFLAGS= -g -O2 -Wall -Werror -Wformat +EXTRACCFLAGS= -D__STDC_FORMAT_MACROS +LDLIBS= -lsqlite3 -lglib-2.0 -luuid -lpthread -lrt -lsm_common -lsm_db -lfmcommon -ljson-c -lcrypto -lssl +LDFLAGS = -rdynamic + +.c.o: + $(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) -c $< -o $@ + +build: $(OBJS) + $(CXX) $(CCFLAGS) $(EXTRACCFLAGS) $(OBJS) ${LDFLAGS} $(LDLIBS) -o sm + +install_non_bb: + install -d 755 ${DEST_DIR}/usr/bin + install -m 755 sm ${DEST_DIR}/usr/bin/sm + +clean: + @rm -f *.o *.a *.so + @rm -f sm diff --git a/service-mgmt/sm-1.0.0/src/fm_api_wrapper.c b/service-mgmt/sm-1.0.0/src/fm_api_wrapper.c new file mode 100644 index 00000000..a42612aa --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/fm_api_wrapper.c @@ -0,0 +1,159 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "fm_api_wrapper.h" + +#include + +#include "sm_debug.h" + +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; + +// **************************************************************************** +// FM Wrapper - FM Set Fault +// ========================= +EFmErrorT fm_set_fault_wrapper( const SFmAlarmDataT* alarm, fm_uuid_t* uuid ) +{ + EFmErrorT fm_error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( FM_ERR_NOCONNECT ); + } + + fm_error = fm_set_fault( alarm, uuid ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( fm_error ); +} +// **************************************************************************** + +// **************************************************************************** +// FM Wrapper - FM Clear Fault +// =========================== +EFmErrorT fm_clear_fault_wrapper( AlarmFilter* filter ) +{ + EFmErrorT fm_error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( FM_ERR_NOCONNECT ); + } + + fm_error = fm_clear_fault( filter ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( fm_error ); +} +// **************************************************************************** + +// **************************************************************************** +// FM Wrapper - FM Clear All +// ========================= +EFmErrorT fm_clear_all_wrapper( fm_ent_inst_t* inst_id ) +{ + EFmErrorT fm_error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( FM_ERR_NOCONNECT ); + } + + fm_error = fm_clear_all( inst_id ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( fm_error ); +} +// **************************************************************************** + +// **************************************************************************** +// FM Wrapper - FM Get Fault +// ========================= +EFmErrorT fm_get_fault_wrapper( AlarmFilter* filter, SFmAlarmDataT* alarm ) +{ + EFmErrorT fm_error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( FM_ERR_NOCONNECT ); + } + + fm_error = fm_get_fault( filter, alarm ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( fm_error ); +} +// **************************************************************************** + +// **************************************************************************** +// FM Wrapper - FM Get Faults +// ========================== +EFmErrorT fm_get_faults_wrapper( fm_ent_inst_t* inst_id, SFmAlarmDataT* alarm, + unsigned int* max_alarms_to_get ) +{ + EFmErrorT fm_error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( FM_ERR_NOCONNECT ); + } + + fm_error = fm_get_faults( inst_id, alarm, max_alarms_to_get ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( fm_error ); +} +// **************************************************************************** + +// **************************************************************************** +// FM Wrapper - FM Get Faults By Id +// ================================ +EFmErrorT fm_get_faults_by_id_wrapper( fm_alarm_id* alarm_id, + SFmAlarmDataT* alarm, unsigned int* max_alarms_to_get ) +{ + EFmErrorT fm_error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( FM_ERR_NOCONNECT ); + } + + fm_error = fm_get_faults_by_id( alarm_id, alarm, max_alarms_to_get ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( fm_error ); +} +// **************************************************************************** + diff --git a/service-mgmt/sm-1.0.0/src/fm_api_wrapper.h b/service-mgmt/sm-1.0.0/src/fm_api_wrapper.h new file mode 100644 index 00000000..1f534d54 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/fm_api_wrapper.h @@ -0,0 +1,40 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __FM_API_WRAPPER_H__ +#define __FM_API_WRAPPER_H__ + + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// +// The following functions are wrapped to guarantee thread safety of the +// FM API library. +// +extern EFmErrorT fm_set_fault_wrapper( const SFmAlarmDataT* alarm, + fm_uuid_t* uuid); + +extern EFmErrorT fm_clear_fault_wrapper( AlarmFilter *filter ); + +extern EFmErrorT fm_clear_all_wrapper( fm_ent_inst_t *inst_id ); + +extern EFmErrorT fm_get_fault_wrapper( AlarmFilter *filter, + SFmAlarmDataT* alarm ); + +EFmErrorT fm_get_faults_wrapper( fm_ent_inst_t *inst_id, + SFmAlarmDataT *alarm, unsigned int* max_alarms_to_get ); + +EFmErrorT fm_get_faults_by_id_wrapper( fm_alarm_id* alarm_id, + SFmAlarmDataT* alarm, unsigned int* max_alarms_to_get ); + +#ifdef __cplusplus +} +#endif + +#endif // __FM_API_WRAPPER_H__ diff --git a/service-mgmt/sm-1.0.0/src/main.c b/service-mgmt/sm-1.0.0/src/main.c new file mode 100644 index 00000000..4f4a5a69 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/main.c @@ -0,0 +1,65 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_trap.h" +#include "sm_process.h" + +// **************************************************************************** +// Main - Thread +// ============= +int main( int argc, char *argv[], char *envp[] ) +{ + SmErrorT error; + + error = sm_trap_initialize( "sm" ); + if( SM_OKAY != error ) + { + printf( "Trap initialization handling failed, error=%s.\n", + sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + error = sm_debug_initialize(); + if( SM_OKAY != error ) + { + printf( "Debug initialization failed, error=%s.\n", + sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + error = sm_process_main( argc, argv, envp ); + if( SM_OKAY != error ) + { + printf( "Process failure, error=%s.\n", sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + error = sm_debug_finalize(); + if( SM_OKAY != error ) + { + printf( "Debug finalization failed, error=%s.\n", + sm_error_str( error ) ); + } + + error = sm_trap_finalize(); + if( SM_OKAY != error ) + { + printf( "Trap handling finalization failed, error=%s.\n", + sm_error_str( error ) ); + } + + return( EXIT_SUCCESS ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/service_status b/service-mgmt/sm-1.0.0/src/service_status new file mode 100644 index 00000000..26ba3f99 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/service_status @@ -0,0 +1,114 @@ +sm_log.c: "%s", service_group_member->name ); +sm_log.c: service_group_member->name ); +sm_service_group_audit.c: if( 0 != service_group_member->service_failure_timestamp ) +sm_service_group_audit.c: delta_ms = elapsed_ms - service_group_member->service_failure_timestamp; +sm_service_group_audit.c: service_group_member->service_name, delta_ms ); +sm_service_group_audit.c: switch( service_group_member->service_failure_impact ) +sm_service_group_audit.c: service_group_member->service_name, delta_ms ); +sm_service_group_audit.c: switch( service_group_member->service_status ) +sm_service_group_audit.c: service_group_member->service_name, +sm_service_group_audit.c: service_group_member->service_state, +sm_service_group_audit.c: service_group_member->service_status, +sm_service_group_audit.c: service_group_member->service_condition ); +sm_service_group_audit.c: service_group_member->service_condition, +sm_service_group_audit.c: service_group_member->service_name, +sm_service_group_audit.c: service_group_member->service_state, +sm_service_group_audit.c: service_group_member->service_status, +sm_service_group_audit.c: service_group_member->service_condition ); +sm_service_group_audit.c: switch( service_group_member->service_failure_impact ) +sm_service_group_audit.c: service_group_member->service_condition, +sm_service_group_audit.c: service_group_member->service_name, +sm_service_group_audit.c: service_group_member->service_state, +sm_service_group_audit.c: service_group_member->service_status, +sm_service_group_audit.c: service_group_member->service_condition ); +sm_service_group_audit.c: "group (%s).", service_group_member->service_name, +sm_service_group_audit.c: service_group_member->service_failure_impact ), +sm_service_group_audit.c: "overall_status=%s.", service_group_member->name, +sm_service_group_audit.c: service_group_member->service_name, +sm_service_group_audit.c: "overall_condition=%s.", service_group_member->name, +sm_service_group_audit.c: service_group_member->service_name, +sm_service_group_disable.c: DPRINTFD( "Disabling %s of %s", service_group_member->service_name, +sm_service_group_disable.c: error = sm_service_api_disable( service_group_member->service_name ); +sm_service_group_disable.c: service_group_member->service_name, +sm_service_group_disable.c: if( SM_SERVICE_STATE_DISABLED == service_group_member->service_state ) +sm_service_group_disable.c: "state=%s.", service_group_member->service_name, +sm_service_group_disable.c: service_group_member->name, +sm_service_group_disable.c: sm_service_state_str( service_group_member->service_state ) ); +sm_service_group_disable.c: "complete, state=%s.", service_group_member->service_name, +sm_service_group_disable.c: service_group_member->name, +sm_service_group_disable.c: sm_service_state_str( service_group_member->service_state ) ); +sm_service_group_enable.c: DPRINTFD( "Enabling %s of %s", service_group_member->service_name, +sm_service_group_enable.c: if(( SM_SERVICE_STATE_ENABLED_ACTIVE == service_group_member->service_state )|| +sm_service_group_enable.c: ( SM_SERVICE_STATE_ENABLED_GO_ACTIVE == service_group_member->service_state )|| +sm_service_group_enable.c: ( SM_SERVICE_STATE_ENABLED_GO_STANDBY == service_group_member->service_state )|| +sm_service_group_enable.c: ( SM_SERVICE_STATE_ENABLED_STANDBY == service_group_member->service_state )) +sm_service_group_enable.c: "state=%s.", service_group_member->service_name, +sm_service_group_enable.c: service_group_member->name, +sm_service_group_enable.c: sm_service_state_str( service_group_member->service_state ) ); +sm_service_group_enable.c: "complete, state=%s.", service_group_member->service_name, +sm_service_group_enable.c: service_group_member->name, +sm_service_group_enable.c: sm_service_state_str( service_group_member->service_state ) ); +sm_service_group_fsm.c: service = sm_service_table_read( service_group_member->service_name ); +sm_service_group_fsm.c: service_group_member->service_name, +sm_service_group_fsm.c: if(( service->state != service_group_member->service_state )|| +sm_service_group_fsm.c: ( service->status != service_group_member->service_status )) +sm_service_group_fsm.c: service_group_member->service_state = service->state; +sm_service_group_fsm.c: service_group_member->service_status = service->status; +sm_service_group_fsm.c: error = sm_service_api_recover( service_group_member->service_name, +sm_service_group_fsm.c: service_group_member->service_name, +sm_service_group_fsm.c: service_group_member->service_state = state; +sm_service_group_fsm.c: service_group_member->service_status = status; +sm_service_group_fsm.c: service_group_member->service_condition = condition; +sm_service_group_fsm.c: service_group_member->service_failure_timestamp +sm_service_group_fsm.c: error = sm_service_group_fsm_event_handler( service_group_member->name, +sm_service_group_fsm.c: "error=%s.", service_group_member->service_name, +sm_service_group_fsm.c: service_group_member->name, sm_error_str( error ) ); +sm_service_group_go_active.c: DPRINTFD( "Go-Active on %s of %s", service_group_member->service_name, +sm_service_group_go_active.c: error = sm_service_api_go_active( service_group_member->service_name ); +sm_service_group_go_active.c: service_group_member->service_name, +sm_service_group_go_active.c: if( SM_SERVICE_STATE_ENABLED_ACTIVE == service_group_member->service_state ) +sm_service_group_go_active.c: "state=%s.", service_group_member->service_name, +sm_service_group_go_active.c: service_group_member->name, +sm_service_group_go_active.c: sm_service_state_str( service_group_member->service_state ) ); +sm_service_group_go_active.c: "complete, state=%s.", service_group_member->service_name, +sm_service_group_go_active.c: service_group_member->name, +sm_service_group_go_active.c: sm_service_state_str( service_group_member->service_state ) ); +sm_service_group_go_standby.c: DPRINTFD( "Go-Standby on %s of %s", service_group_member->service_name, +sm_service_group_go_standby.c: error = sm_service_api_go_standby( service_group_member->service_name ); +sm_service_group_go_standby.c: service_group_member->service_name, +sm_service_group_go_standby.c: if(( SM_SERVICE_STATE_ENABLED_STANDBY == service_group_member->service_state )|| +sm_service_group_go_standby.c: ( SM_SERVICE_STATE_ENABLING == service_group_member->service_state )|| +sm_service_group_go_standby.c: ( SM_SERVICE_STATE_DISABLING == service_group_member->service_state )|| +sm_service_group_go_standby.c: ( SM_SERVICE_STATE_DISABLED == service_group_member->service_state )) +sm_service_group_go_standby.c: "state=%s.", service_group_member->service_name, +sm_service_group_go_standby.c: service_group_member->name, +sm_service_group_go_standby.c: sm_service_state_str( service_group_member->service_state ) ); +sm_service_group_go_standby.c: "complete, state=%s.", service_group_member->service_name, +sm_service_group_go_standby.c: service_group_member->name, +sm_service_group_go_standby.c: sm_service_state_str( service_group_member->service_state ) ); +sm_service_group_member_table.c: if(( 0 == strcmp( service_group_name, service_group_member->name ) )&& +sm_service_group_member_table.c: ( 0 == strcmp( service_name, service_group_member->service_name ) )) +sm_service_group_member_table.c: if( service_group_member_id == service_group_member->id ) +sm_service_group_member_table.c: if( 0 == strcmp( service_name, service_group_member->service_name ) ) +sm_service_group_member_table.c: if( 0 == strcmp( service_group_name, service_group_member->name ) ) +sm_service_group_member_table.c: db_service_group_member->name, +sm_service_group_member_table.c: db_service_group_member->service_name ); +sm_service_group_member_table.c: service_group_member->id = db_service_group_member->id; +sm_service_group_member_table.c: snprintf( service_group_member->name, sizeof(service_group_member->name), +sm_service_group_member_table.c: "%s", db_service_group_member->name ); +sm_service_group_member_table.c: snprintf( service_group_member->service_name, +sm_service_group_member_table.c: sizeof(service_group_member->service_name), +sm_service_group_member_table.c: "%s", db_service_group_member->service_name ); +sm_service_group_member_table.c: service_group_member->service_state = SM_SERVICE_STATE_INITIAL; +sm_service_group_member_table.c: service_group_member->service_status = SM_SERVICE_STATUS_NONE; +sm_service_group_member_table.c: service_group_member->service_condition = SM_SERVICE_CONDITION_NONE; +sm_service_group_member_table.c: service_group_member->service_failure_impact +sm_service_group_member_table.c: = db_service_group_member->service_failure_impact; +sm_service_group_member_table.c: service_group_member->service_failure_timestamp = 0; +sm_service_group_member_table.c: service_group_member->id = db_service_group_member->id; +sm_service_group_member_table.c: service_group_member->service_failure_impact +sm_service_group_member_table.c: = db_service_group_member->service_failure_impact; +sm_service_group_member_table.c: db_service_group_member.id = service_group_member->id; +sm_service_group_member_table.c: "%s", service_group_member->name ); +sm_service_group_member_table.c: "%s", service_group_member->service_name ); +sm_service_group_member_table.c: = service_group_member->service_failure_impact; diff --git a/service-mgmt/sm-1.0.0/src/sm_alarm.c b/service-mgmt/sm-1.0.0/src/sm_alarm.c new file mode 100644 index 00000000..08e3f313 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_alarm.c @@ -0,0 +1,770 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_alarm.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_node_utils.h" +#include "sm_alarm_thread.h" + +#define SM_ALARM_ENTRY_INUSE 0xA5A5A5A5 + +typedef enum +{ + SM_ALARM_STATE_UNKNOWN, + SM_ALARM_STATE_CLEARING, + SM_ALARM_STATE_RAISING, + SM_ALARM_STATE_MAX, +} SmAlarmStateT; + +typedef struct +{ + uint32_t inuse; + SmAlarmT alarm; + SmAlarmStateT alarm_state; + SmAlarmNodeNameT alarm_node_name; + SmAlarmDomainNameT alarm_domain_name; + SmAlarmEntityNameT alarm_entity_name; + bool alarm_data_valid; + SmAlarmDataT alarm_data; +} SmAlarmEntryT; + +static int _server_fd = -1; +static int _client_fd = -1; +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static SmAlarmEntryT _alarms[SM_ALARMS_MAX]; + +// **************************************************************************** +// Alarm - Find Empty +// ================== +static SmAlarmEntryT* sm_alarm_find_empty( void ) +{ + SmAlarmEntryT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_ALARMS_MAX > entry_i; ++entry_i ) + { + entry = &(_alarms[entry_i]); + + if( SM_ALARM_ENTRY_INUSE != entry->inuse ) + return( entry ); + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Find +// ============ +static SmAlarmEntryT* sm_alarm_find( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmDomainNameT domain_name, + const SmAlarmEntityNameT entity_name ) +{ + SmAlarmEntryT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_ALARMS_MAX > entry_i; ++entry_i ) + { + entry = &(_alarms[entry_i]); + + if( SM_ALARM_ENTRY_INUSE != entry->inuse ) + continue; + + if(( alarm == entry->alarm )&& + ( 0 == strcmp( node_name, entry->alarm_node_name ) )&& + ( 0 == strcmp( domain_name, entry->alarm_domain_name ) )&& + ( 0 == strcmp( entity_name, entry->alarm_entity_name ) )) + return( entry ); + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Throttle +// ================ +static bool sm_alarm_throttle( const SmAlarmT alarm, SmAlarmStateT alarm_state, + const SmAlarmNodeNameT node_name, const SmAlarmDomainNameT domain_name, + const SmAlarmEntityNameT entity_name, SmAlarmDataT* data ) +{ + bool throttle = false; + SmAlarmEntryT* entry; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + abort(); + } + + entry = sm_alarm_find( alarm, node_name, domain_name, entity_name ); + if( NULL == entry ) + { + entry = sm_alarm_find_empty(); + if( NULL == entry ) + { + DPRINTFE( "Failed to store alarm, no more room." ); + goto RELEASE_MUTEX; + } + + memset( entry, 0, sizeof(SmAlarmEntryT) ); + + entry->inuse = SM_ALARM_ENTRY_INUSE; + entry->alarm = alarm; + snprintf( entry->alarm_node_name, sizeof(entry->alarm_node_name), + "%s", node_name ); + snprintf( entry->alarm_domain_name, sizeof(entry->alarm_domain_name), + "%s", domain_name ); + snprintf( entry->alarm_entity_name, sizeof(entry->alarm_entity_name), + "%s", entity_name ); + + } else if( alarm_state == entry->alarm_state ) { + if(( NULL == data )&&( !(entry->alarm_data_valid) )) + { + throttle = true; + + } else if(( NULL != data )&&( entry->alarm_data_valid )) { + if( 0 == memcmp( &(entry->alarm_data), data, sizeof(SmAlarmDataT) ) ) + { + throttle = true; + } + } + } + + if( !throttle ) + { + entry->alarm_state = alarm_state; + + if( NULL == data ) + { + entry->alarm_data_valid = false; + memset( &(entry->alarm_data), 0, sizeof(SmAlarmDataT) ); + } else { + entry->alarm_data_valid = true; + memcpy( &(entry->alarm_data), data, sizeof(SmAlarmDataT) ); + } + } + +RELEASE_MUTEX: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + abort(); + } + + return( throttle ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Write Alarm Additional Text +// =================================== +bool sm_alarm_write_alarm_additional_text( const char data[], + char alarm_additional_text[], int alarm_additional_text_size, int reserve ) +{ + bool have_space = true; + + if( '\0' == alarm_additional_text[0] ) + { + snprintf( alarm_additional_text, alarm_additional_text_size, + "%s", data ); + } else { + int len = strlen(alarm_additional_text); + int left = alarm_additional_text_size - len - 1; + int data_len = (int) strlen(data); + + if( left > (data_len + reserve + 16) ) // reserve extra room + { + snprintf( &(alarm_additional_text[len]), left, ", %s", data ); + } else { + snprintf( &(alarm_additional_text[len]), left, ", ..." ); + have_space = false; + } + } + + return( have_space ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise +// ============= +static void sm_alarm_raise( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmDomainNameT domain_name, + const SmAlarmEntityNameT entity_name, SmAlarmDataT* data ) +{ + SmAlarmThreadMsgT msg; + SmAlarmThreadMsgRaiseAlarmT* raise_alarm = &(msg.u.raise_alarm); + int result; + + if( sm_alarm_throttle( alarm, SM_ALARM_STATE_RAISING, node_name, + domain_name, entity_name, data ) ) + { + DPRINTFD( "Already raising alarm (%i) for node (%s) domain (%s) " + "entity (%s).", alarm, node_name, domain_name, + entity_name ); + return; + } + + DPRINTFD( "Raise alarm (%i) for node (%s) domain (%s) entity (%s).", + alarm, node_name, domain_name, entity_name ); + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_ALARM_THREAD_MSG_RAISE_ALARM; + + clock_gettime( CLOCK_REALTIME, &(raise_alarm->ts_real) ); + + raise_alarm->alarm = alarm; + + snprintf( raise_alarm->node_name, sizeof(raise_alarm->node_name), + "%s", node_name ); + snprintf( raise_alarm->domain_name, sizeof(raise_alarm->domain_name), + "%s", domain_name ); + snprintf( raise_alarm->entity_name, sizeof(raise_alarm->entity_name), + "%s", entity_name ); + + memcpy( &(raise_alarm->data), data, sizeof(SmAlarmDataT) ); + + result = send( _client_fd, &msg, sizeof(msg), 0 ); + if( 0 > result ) + { + DPRINTFE( "Failed to raise alarm (%i) for domain (%s) entity (%s), " + "error=%s.", alarm, domain_name, entity_name, + strerror( errno ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise State Alarm +// ========================= +void sm_alarm_raise_state_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmDomainNameT domain_name, + const SmAlarmEntityNameT entity_name, const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, const char entity_state[], + const char entity_status[], const char entity_condition[], + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ) +{ + SmAlarmDataT data; + + memset( &data, 0, sizeof(SmAlarmDataT) ); + + data.event_type = SM_ALARM_EVENT_TYPE_PROCESSING_ERROR_ALARM; + data.probable_cause = probable_cause; + + snprintf( data.specific_problem_text, sizeof(data.specific_problem_text), + "%s", specific_problem_text ); + + data.perceived_severity = severity; + data.trend_indication = SM_ALARM_TREND_INDICATION_NO_CHANGE; + + data.state_info.applicable = true; + snprintf( data.state_info.state, sizeof(data.state_info.state), + "%s", entity_state ); + snprintf( data.state_info.status, sizeof(data.state_info.status), + "%s", entity_status ); + snprintf( data.state_info.condition, sizeof(data.state_info.condition), + "%s", entity_condition ); + + data.threshold_info.applicable = false; + + if( '\0' == proposed_repair_action[0] ) + { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), + "contact next level of support" ); + } else { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), "%s", + proposed_repair_action ); + } + + snprintf( data.additional_text, sizeof(data.additional_text), "%s", + additional_text ); + + data.service_affecting = true; + data.suppression_allowed = suppression_allowed; + + sm_alarm_raise( alarm, node_name, domain_name, entity_name, &data ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise Threshold Alarm +// ============================= +void sm_alarm_raise_threshold_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmDomainNameT domain_name, + const SmAlarmEntityNameT entity_name, const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, + const unsigned int threshold_value, const unsigned int observed_value, + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ) +{ + SmAlarmDataT data; + + memset( &data, 0, sizeof(SmAlarmDataT) ); + + data.event_type = SM_ALARM_EVENT_TYPE_PROCESSING_ERROR_ALARM; + data.probable_cause = probable_cause; + + snprintf( data.specific_problem_text, sizeof(data.specific_problem_text), + "%s", specific_problem_text ); + + data.perceived_severity = severity; + data.trend_indication = SM_ALARM_TREND_INDICATION_NO_CHANGE; + data.state_info.applicable = false; + + data.threshold_info.applicable = true; + data.threshold_info.threshold_value = threshold_value; + data.threshold_info.observed_value = observed_value; + + if( '\0' == proposed_repair_action[0] ) + { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), + "contact next level of support" ); + } else { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), "%s", + proposed_repair_action ); + } + + snprintf( data.additional_text, sizeof(data.additional_text), "%s", + additional_text ); + + data.service_affecting = true; + data.suppression_allowed = suppression_allowed; + + sm_alarm_raise( alarm, node_name, domain_name, entity_name, &data ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise Node Alarm +// ======================== +void sm_alarm_raise_node_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ) +{ + SmAlarmDataT data; + SmAlarmDomainNameT domain_name = ""; + SmAlarmEntityNameT entity_name = ""; + + memset( &data, 0, sizeof(SmAlarmDataT) ); + + data.event_type = SM_ALARM_EVENT_TYPE_PROCESSING_ERROR_ALARM; + data.probable_cause = probable_cause; + + snprintf( data.specific_problem_text, sizeof(data.specific_problem_text), + "%s", specific_problem_text ); + + data.perceived_severity = severity; + data.trend_indication = SM_ALARM_TREND_INDICATION_NO_CHANGE; + data.state_info.applicable = false; + data.threshold_info.applicable = false; + + if( '\0' == proposed_repair_action[0] ) + { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), + "contact next level of support" ); + } else { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), "%s", + proposed_repair_action ); + } + + snprintf( data.additional_text, sizeof(data.additional_text), "%s", + additional_text ); + + data.service_affecting = true; + data.suppression_allowed = suppression_allowed; + + sm_alarm_raise( alarm, node_name, domain_name, entity_name, &data ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise Software Alarm +// ============================ +void sm_alarm_raise_software_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ) +{ + SmAlarmDataT data; + SmAlarmDomainNameT domain_name = ""; + SmAlarmEntityNameT entity_name = ""; + + memset( &data, 0, sizeof(SmAlarmDataT) ); + + data.event_type = SM_ALARM_EVENT_TYPE_PROCESSING_ERROR_ALARM; + data.probable_cause = probable_cause; + + snprintf( data.specific_problem_text, sizeof(data.specific_problem_text), + "%s", specific_problem_text ); + + data.perceived_severity = severity; + data.trend_indication = SM_ALARM_TREND_INDICATION_NO_CHANGE; + data.state_info.applicable = false; + data.threshold_info.applicable = false; + + if( '\0' == proposed_repair_action[0] ) + { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), + "contact next level of support" ); + } else { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), "%s", + proposed_repair_action ); + } + + snprintf( data.additional_text, sizeof(data.additional_text), "%s", + additional_text ); + + data.service_affecting = true; + data.suppression_allowed = suppression_allowed; + + sm_alarm_raise( alarm, node_name, domain_name, entity_name, &data ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise Communication Alarm +// ================================= +void sm_alarm_raise_communication_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmEntityNameT entity_name, + const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ) +{ + SmAlarmDataT data; + SmAlarmDomainNameT domain_name = ""; + + memset( &data, 0, sizeof(SmAlarmDataT) ); + + data.event_type = SM_ALARM_EVENT_TYPE_COMMUNICATIONS_ALARM; + data.probable_cause = probable_cause; + + snprintf( data.specific_problem_text, sizeof(data.specific_problem_text), + "%s", specific_problem_text ); + + data.perceived_severity = severity; + data.trend_indication = SM_ALARM_TREND_INDICATION_NO_CHANGE; + data.state_info.applicable = false; + data.threshold_info.applicable = false; + + if( '\0' == proposed_repair_action[0] ) + { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), + "contact next level of support" ); + } else { + snprintf( data.proposed_repair_action, + sizeof(data.proposed_repair_action), "%s", + proposed_repair_action ); + } + + snprintf( data.additional_text, sizeof(data.additional_text), "%s", + additional_text ); + + data.service_affecting = true; + data.suppression_allowed = suppression_allowed; + + sm_alarm_raise( alarm, node_name, domain_name, entity_name, &data ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Clear +// ============= +void sm_alarm_clear( const SmAlarmT alarm, const SmAlarmNodeNameT node_name, + const SmAlarmDomainNameT domain_name, const SmAlarmEntityNameT entity_name ) +{ + SmAlarmThreadMsgT msg; + SmAlarmThreadMsgClearAlarmT* clear_alarm = &(msg.u.clear_alarm); + int result; + + if( sm_alarm_throttle( alarm, SM_ALARM_STATE_CLEARING, node_name, + domain_name, entity_name, NULL ) ) + { + DPRINTFD( "Already clearing alarm (%i) for node (%s) domain (%s) " + "entity (%s).", alarm, node_name, domain_name, + entity_name ); + return; + } + + DPRINTFD( "Clear alarm (%i) for node (%s) domain (%s) entity (%s).", + alarm, node_name, domain_name, entity_name ); + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_ALARM_THREAD_MSG_CLEAR_ALARM; + + clock_gettime( CLOCK_REALTIME, &(clear_alarm->ts_real) ); + + clear_alarm->alarm = alarm; + + snprintf( clear_alarm->node_name, sizeof(clear_alarm->node_name), + "%s", node_name ); + snprintf( clear_alarm->domain_name, sizeof(clear_alarm->domain_name), + "%s", domain_name ); + snprintf( clear_alarm->entity_name, sizeof(clear_alarm->entity_name), + "%s", entity_name ); + + result = send( _client_fd, &msg, sizeof(msg), 0 ); + if( 0 > result ) + { + DPRINTFE( "Failed to clear alarm (%i) for domain (%s) entity (%s), " + "error=%s.", alarm, domain_name, entity_name, + strerror( errno ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Clear All +// ================= +void sm_alarm_clear_all( const SmAlarmDomainNameT domain_name ) +{ + SmAlarmThreadMsgT msg; + SmAlarmThreadMsgClearAllAlarmsT* clear_all_alarms = &(msg.u.clear_all_alarms); + int result; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + abort(); + } + + memset( _alarms, 0, sizeof(_alarms) ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + abort(); + } + + DPRINTFD( "Clear all alarms." ); + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_ALARM_THREAD_MSG_CLEAR_ALL_ALARMS; + + clock_gettime( CLOCK_REALTIME, &(clear_all_alarms->ts_real) ); + + snprintf( clear_all_alarms->domain_name, + sizeof(clear_all_alarms->domain_name), "%s", domain_name ); + + result = send( _client_fd, &msg, sizeof(msg), 0 ); + if( 0 > result ) + { + DPRINTFE( "Failed to clear all alarms for domain (%s), error=%s.", + domain_name, strerror( errno ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Manage Domain Alarms +// ============================ +void sm_alarm_manage_domain_alarms( const SmAlarmDomainNameT domain_name, + bool manage ) +{ + SmAlarmThreadMsgT msg; + SmAlarmThreadMsgManageDomainAlarmsT* manage_alarms = &(msg.u.manage_alarms); + int result; + + DPRINTFD( "Manage domain (%s) alarms, set_to=%s.", domain_name, + (manage) ? "yes" : "no" ); + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_ALARM_THREAD_MSG_MANAGE_DOMAIN_ALARMS; + + manage_alarms->manage = manage; + snprintf( manage_alarms->domain_name, sizeof(manage_alarms->domain_name), + "%s", domain_name ); + + result = send( _client_fd, &msg, sizeof(msg), 0 ); + if( 0 > result ) + { + DPRINTFE( "Failed to set manage alarms for domain (%s), error=%s.", + domain_name, strerror( errno ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Initialize +// ================== +SmErrorT sm_alarm_initialize( void ) +{ + int flags; + int sockets[2]; + int buffer_len = 1048576; + int result; + SmErrorT error; + + DPRINTFD( "Alarm message size is %i bytes.", + (int) sizeof(SmAlarmThreadMsgT) ); + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + abort(); + } + + memset( _alarms, 0, sizeof(_alarms) ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + abort(); + } + + result = socketpair( AF_UNIX, SOCK_DGRAM, 0, sockets ); + if( 0 > result ) + { + DPRINTFE( "Failed to create alarm communication sockets, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + int socket_i; + for( socket_i=0; socket_i < 2; ++socket_i ) + { + flags = fcntl( sockets[socket_i] , F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get alarm communication socket (%i) flags, " + "error=%s.", socket_i, strerror( errno ) ); + return( SM_FAILED ); + } + + result = fcntl( sockets[socket_i], F_SETFL, flags | O_NONBLOCK ); + if( 0 > result ) + { + DPRINTFE( "Failed to set alarm communication socket (%i) to " + "non-blocking, error=%s.", socket_i, + strerror( errno ) ); + return( SM_FAILED ); + } + + result = setsockopt( sockets[socket_i], SOL_SOCKET, SO_SNDBUF, + &buffer_len, sizeof(buffer_len) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set alarm communication socket (%i) " + "send buffer length (%i), error=%s.", socket_i, + buffer_len, strerror( errno ) ); + return( SM_FAILED ); + } + + result = setsockopt( sockets[socket_i], SOL_SOCKET, SO_RCVBUF, + &buffer_len, sizeof(buffer_len) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set alarm communication socket (%i) " + "receive buffer length (%i), error=%s.", socket_i, + buffer_len, strerror( errno ) ); + return( SM_FAILED ); + } + } + + _server_fd = sockets[0]; + _client_fd = sockets[1]; + + error = sm_alarm_thread_start( _server_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start alarm thread, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Finalize +// ================ +SmErrorT sm_alarm_finalize( void ) +{ + SmErrorT error; + + error = sm_alarm_thread_stop(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop alarm thread, error=%s.", + sm_error_str( error ) ); + } + + if( -1 < _server_fd ) + { + close( _server_fd ); + _server_fd = -1; + } + + if( -1 < _client_fd ) + { + close( _client_fd ); + _client_fd = -1; + } + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + abort(); + } + + memset( _alarms, 0, sizeof(_alarms) ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + abort(); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_alarm.h b/service-mgmt/sm-1.0.0/src/sm_alarm.h new file mode 100644 index 00000000..ef2e3536 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_alarm.h @@ -0,0 +1,127 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_ALARM_H__ +#define __SM_ALARM_H__ + +#include + +#include "sm_types.h" +#include "sm_alarm_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Alarm - Write Alarm Additional Text +// =================================== +extern bool sm_alarm_write_alarm_additional_text( const char data[], + char alarm_additional_text[], int alarm_additional_text_size, int reserve ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise State Alarm +// ========================= +extern void sm_alarm_raise_state_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmDomainNameT domain_name, + const SmAlarmEntityNameT entity_name, const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, const char entity_state[], + const char entity_status[], const char entity_condition[], + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise Threshold Alarm +// ============================= +extern void sm_alarm_raise_threshold_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmDomainNameT domain_name, + const SmAlarmEntityNameT entity_name, const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, + const unsigned int threshold_value, const unsigned int observed_value, + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise Node Alarm +// ======================== +extern void sm_alarm_raise_node_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise Software Alarm +// ============================ +extern void sm_alarm_raise_software_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Raise Communication Alarm +// ================================= +extern void sm_alarm_raise_communication_alarm( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmEntityNameT entity_name, + const SmAlarmSeverityT severity, + const SmAlarmProbableCauseT probable_cause, + const SmAlarmSpecificProblemTextT specific_problem_text, + const SmAlarmAdditionalTextT additional_text, + const SmAlarmProposedRepairActionT proposed_repair_action, + bool suppression_allowed ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Clear +// ============= +extern void sm_alarm_clear( const SmAlarmT alarm, + const SmAlarmNodeNameT node_name, const SmAlarmDomainNameT domain_name, + const SmAlarmEntityNameT entity_name ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Clear All +// ================= +extern void sm_alarm_clear_all( const SmAlarmDomainNameT domain_name ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Manage Domain Alarms +// ============================ +extern void sm_alarm_manage_domain_alarms( const SmAlarmDomainNameT domain_name, + bool manage ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Initialize +// ================== +extern SmErrorT sm_alarm_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Alarm - Finalize +// ================ +extern SmErrorT sm_alarm_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_ALARM_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_alarm_defs.h b/service-mgmt/sm-1.0.0/src/sm_alarm_defs.h new file mode 100644 index 00000000..0a6ee3c0 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_alarm_defs.h @@ -0,0 +1,132 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_ALARM_DEFINITIONS_H__ +#define __SM_ALARM_DEFINITIONS_H__ + +#include + +#include "sm_limits.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// X.731 - Systems Management: State Management Function +// X.732 - Systems Management: Attributes for Representing Relationships +// X.733 - Systems Management: Alarm Reporting Function +// RFC 4628 - Entity State MIB + +typedef char SmAlarmNodeNameT[SM_NODE_NAME_MAX_CHAR]; + +typedef char SmAlarmDomainNameT[SM_ALARM_DOMAIN_NAME_MAX_CHAR]; + +typedef char SmAlarmEntityNameT[SM_ALARM_ENTITY_NAME_MAX_CHAR]; + +typedef enum +{ + SM_ALARM_EVENT_TYPE_UNKNOWN, + SM_ALARM_EVENT_TYPE_COMMUNICATIONS_ALARM, + SM_ALARM_EVENT_TYPE_PROCESSING_ERROR_ALARM, + SM_ALARM_EVENT_TYPE_ENVIRONMENTAL_ALARM, + SM_ALARM_EVENT_TYPE_QUALITY_OF_SERVICE_ALARM, + SM_ALARM_EVENT_TYPE_EQUIPMENT_ALARM, + SM_ALARM_EVENT_TYPE_INTEGRITY_VIOLATION, + SM_ALARM_EVENT_TYPE_OPERATIONAL_VIOLATION, + SM_ALARM_EVENT_TYPE_PHYSICAL_VIOLATION, + SM_ALARM_EVENT_TYPE_SECURITY_SERVICE_VIOLATION, + SM_ALARM_EVENT_TYPE_MECHANISM_VIOLATION, + SM_ALARM_EVENT_TYPE_TIME_DOMAIN_VIOLATION, + SM_ALARM_EVENT_TYPE_MAX +} SmAlarmEventTypeT; + +typedef enum +{ + SM_ALARM_PROBABLE_CAUSE_UNKNOWN, + SM_ALARM_PROBABLE_CAUSE_INDETERMINATE, + SM_ALARM_PROBABLE_CAUSE_SOFTWARE_ERROR, + SM_ALARM_PROBABLE_CAUSE_SOFTWARE_PROGRAM_ERROR, + SM_ALARM_PROBABLE_CAUSE_UNDERLYING_RESOURCE_UNAVAILABLE, + SM_ALARM_PROBABLE_CAUSE_KEY_EXPIRED, + SM_ALARM_PROBABLE_CAUSE_MAX +} SmAlarmProbableCauseT; + +typedef enum +{ + SM_ALARM_SEVERITY_UNKNOWN, + SM_ALARM_SEVERITY_CLEARED, + SM_ALARM_SEVERITY_INDETERMINATE, + SM_ALARM_SEVERITY_WARNING, + SM_ALARM_SEVERITY_MINOR, + SM_ALARM_SEVERITY_MAJOR, + SM_ALARM_SEVERITY_CRITICAL, + SM_ALARM_SEVERITY_MAX +} SmAlarmSeverityT; + +typedef enum +{ + SM_ALARM_TREND_INDICATION_UNKNOWN, + SM_ALARM_TREND_INDICATION_LESS_SEVERE, + SM_ALARM_TREND_INDICATION_NO_CHANGE, + SM_ALARM_TREND_INDICATION_MORE_SEVERE, + SM_ALARM_TREND_INDICATION_MAX +} SmAlarmTrendIndicationT; + +typedef struct +{ + bool applicable; + char state[SM_ALARM_ENTITY_STATE_MAX_CHAR]; + char status[SM_ALARM_ENTITY_STATUS_MAX_CHAR]; + char condition[SM_ALARM_ENTITY_CONDITION_MAX_CHAR]; +} SmAlarmStateInfoT; + +typedef struct +{ + bool applicable; + unsigned int threshold_value; + unsigned int observed_value; +} SmAlarmThresholdInfoT; + +typedef char SmAlarmProposedRepairActionT[SM_ALARM_PROPOSED_REPAIR_ACTION_MAX_CHAR]; + +typedef char SmAlarmSpecificProblemTextT[SM_ALARM_SPECIFIC_PROBLEM_TEXT_MAX_CHAR]; + +typedef char SmAlarmAdditionalTextT[SM_ALARM_ADDITIONAL_TEXT_MAX_CHAR]; + +typedef enum +{ + SM_ALARM_UNKNOWN, + SM_ALARM_SERVICE_GROUP_STATE, + SM_ALARM_SERVICE_GROUP_REDUNDANCY, + SM_ALARM_SOFTWARE_MODIFICATION, + SM_ALARM_COMMUNICATION_FAILURE, + SM_ALARM_MAX +} SmAlarmT; + +#define SM_ALARM_SERVICE_GROUP_STATE_ALARM_ID "400.001" +#define SM_ALARM_SERVICE_GROUP_REDUNDANCY_ALARM_ID "400.002" +#define SM_ALARM_SOFTWARE_MODIFICATION_ALARM_ID "400.004" +#define SM_ALARM_COMMUNICATION_FAILURE_ALARM_ID "400.005" + +typedef struct +{ + SmAlarmEventTypeT event_type; + SmAlarmProbableCauseT probable_cause; + SmAlarmSpecificProblemTextT specific_problem_text; + SmAlarmSeverityT perceived_severity; + SmAlarmTrendIndicationT trend_indication; + SmAlarmStateInfoT state_info; + SmAlarmThresholdInfoT threshold_info; + SmAlarmProposedRepairActionT proposed_repair_action; + SmAlarmAdditionalTextT additional_text; + bool service_affecting; + bool suppression_allowed; +} SmAlarmDataT; + +#ifdef __cplusplus +} +#endif + +#endif // __SM_ALARM_DEFINITIONS_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_alarm_thread.c b/service-mgmt/sm-1.0.0/src/sm_alarm_thread.c new file mode 100644 index 00000000..4301065a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_alarm_thread.c @@ -0,0 +1,1819 @@ +// +// Copyright (c) 2014 -2016 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_alarm_thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fm_api_wrapper.h" + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_time.h" +#include "sm_debug.h" +#include "sm_trap.h" +#include "sm_timer.h" +#include "sm_selobj.h" +#include "sm_node_utils.h" +#include "sm_thread_health.h" + +#define SM_ALARM_THREAD_NAME "sm_alarm" +#define SM_ALARM_THREAD_ALARM_REPORT_TIMER_IN_MS 5000 +#define SM_ALARM_THREAD_ALARM_AUDIT_TIMER_IN_MS 60000 +#define SM_ALARM_THREAD_TICK_INTERVAL_IN_MS 5000 +#define SM_ALARM_CUSTOMER_LOG_FILE "/var/log/sm-customer.alarm" + +#define SM_ALARM_ENTRY_INUSE 0xFDFDFDFD +#define SM_ALARM_DOMAIN_ENTRY_INUSE 0xFDFDFDFD + +typedef enum +{ + SM_ALARM_STATE_UNKNOWN, + SM_ALARM_STATE_INITIAL, + SM_ALARM_STATE_CLEARING, + SM_ALARM_STATE_CLEARED, + SM_ALARM_STATE_RAISING, + SM_ALARM_STATE_RAISED, + SM_ALARM_STATE_MAX, +} SmAlarmStateT; + +typedef struct +{ + uint32_t inuse; + SmAlarmT alarm; + SmAlarmStateT alarm_state; + SmAlarmNodeNameT alarm_node_name; + SmAlarmDomainNameT alarm_domain_name; + SmAlarmEntityNameT alarm_entity_name; + SmAlarmDataT alarm_data; + + // Alarm Timestamps + struct timespec alarm_raised_time; + struct timespec alarm_changed_time; + struct timespec alarm_cleared_time; + + // External FM Alarm Data + fm_uuid_t fm_uuid; + SFmAlarmDataT fm_alarm_data; +} SmAlarmEntryT; + +typedef struct +{ + uint32_t inuse; + bool manage; + SmAlarmDomainNameT alarm_domain_name; +} SmAlarmDomainEntryT; + +static sig_atomic_t _stay_on; +static bool _thread_created = false; +static pthread_t _alarm_thread; +static SmTimerIdT _alarm_report_timer_id = SM_TIMER_ID_INVALID; +static SmTimerIdT _alarm_audit_timer_id = SM_TIMER_ID_INVALID; +static int _server_fd = -1; +static bool _server_fd_registered = false; +static SmAlarmEntryT _alarms[SM_ALARMS_MAX]; +static SmAlarmDomainEntryT _alarm_domains[SM_ALARM_DOMAINS_MAX]; +static uint64_t _customer_alarm_log_id = 0; +static FILE * _customer_alarm_log = NULL; + +// **************************************************************************** +// Alarm Thread - Event Type String +// ================================ +static const char * sm_alarm_thread_event_type_str( + SmAlarmEventTypeT event_type ) +{ + switch( event_type ) + { + case SM_ALARM_EVENT_TYPE_UNKNOWN: + return( "unknown" ); + break; + + case SM_ALARM_EVENT_TYPE_COMMUNICATIONS_ALARM: + return( "communications alarm" ); + break; + + case SM_ALARM_EVENT_TYPE_PROCESSING_ERROR_ALARM: + return( "processing error alarm" ); + break; + + case SM_ALARM_EVENT_TYPE_ENVIRONMENTAL_ALARM: + return( "environmental alarm" ); + break; + + case SM_ALARM_EVENT_TYPE_QUALITY_OF_SERVICE_ALARM: + return( "quality of service alarm" ); + break; + + case SM_ALARM_EVENT_TYPE_EQUIPMENT_ALARM: + return( "equipment alarm" ); + break; + + case SM_ALARM_EVENT_TYPE_INTEGRITY_VIOLATION: + return( "integrity violation" ); + break; + + case SM_ALARM_EVENT_TYPE_OPERATIONAL_VIOLATION: + return( "operational violation" ); + break; + + case SM_ALARM_EVENT_TYPE_PHYSICAL_VIOLATION: + return( "physical violation" ); + break; + + case SM_ALARM_EVENT_TYPE_SECURITY_SERVICE_VIOLATION: + return( "security service violation" ); + break; + + case SM_ALARM_EVENT_TYPE_MECHANISM_VIOLATION: + return( "mechanism violation" ); + break; + + case SM_ALARM_EVENT_TYPE_TIME_DOMAIN_VIOLATION: + return( "time domain violation" ); + break; + + default: + return ( "???" ); + break; + } + + return( "???" ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Probable Cause String +// ==================================== +static const char * sm_alarm_thread_probable_cause_str( + SmAlarmProbableCauseT probable_cause ) +{ + switch( probable_cause ) + { + case SM_ALARM_PROBABLE_CAUSE_UNKNOWN: + return( "unknown" ); + break; + + case SM_ALARM_PROBABLE_CAUSE_INDETERMINATE: + return( "indeterminate" ); + break; + + case SM_ALARM_PROBABLE_CAUSE_SOFTWARE_ERROR: + return( "software error" ); + break; + + case SM_ALARM_PROBABLE_CAUSE_SOFTWARE_PROGRAM_ERROR: + return( "software program error" ); + break; + + case SM_ALARM_PROBABLE_CAUSE_UNDERLYING_RESOURCE_UNAVAILABLE: + return( "underlying resource unavailable" ); + break; + + case SM_ALARM_PROBABLE_CAUSE_KEY_EXPIRED: + return( "key expired" ); + break; + + default: + return ( "???" ); + break; + } + + return( "???" ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Severity String +// ============================== +static const char * sm_alarm_thread_severity_str( SmAlarmSeverityT severity ) +{ + switch( severity ) + { + case SM_ALARM_SEVERITY_UNKNOWN: + return( "unknown" ); + break; + + case SM_ALARM_SEVERITY_CLEARED: + return( "cleared" ); + break; + + case SM_ALARM_SEVERITY_INDETERMINATE: + return( "indeterminate" ); + break; + + case SM_ALARM_SEVERITY_WARNING: + return( "warning" ); + break; + + case SM_ALARM_SEVERITY_MINOR: + return( "minor" ); + break; + + case SM_ALARM_SEVERITY_MAJOR: + return( "major" ); + break; + + case SM_ALARM_SEVERITY_CRITICAL: + return( "critical" ); + break; + + default: + return ( "???" ); + break; + } + + return( "???" ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Trend String +// =========================== +static const char * sm_alarm_thread_trend_str( SmAlarmTrendIndicationT trend ) +{ + switch( trend ) + { + case SM_ALARM_TREND_INDICATION_UNKNOWN: + return( "unknown" ); + break; + + case SM_ALARM_TREND_INDICATION_LESS_SEVERE: + return( "less severe" ); + break; + + case SM_ALARM_TREND_INDICATION_NO_CHANGE: + return( "no change" ); + break; + + case SM_ALARM_TREND_INDICATION_MORE_SEVERE: + return( "more severe" ); + break; + + default: + return ( "???" ); + break; + } + + return( "???" ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Alarm String +// =========================== +static const char * sm_alarm_thread_alarm_str( SmAlarmT alarm ) +{ + switch( alarm ) + { + case SM_ALARM_UNKNOWN: + return( "unknown" ); + break; + + case SM_ALARM_SERVICE_GROUP_STATE: + return( "service-group-state" ); + break; + + case SM_ALARM_SERVICE_GROUP_REDUNDANCY: + return( "service-group-redundancy" ); + break; + + case SM_ALARM_SOFTWARE_MODIFICATION: + return( "software-modification" ); + break; + + case SM_ALARM_COMMUNICATION_FAILURE: + return( "communication-failure" ); + break; + + default: + return ( "???" ); + break; + } + + return( "???" ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Log +// ================== +static void sm_alarm_thread_log( SmAlarmEntryT* entry ) +{ + char date_str[32]; + struct tm t_real; + + fprintf( _customer_alarm_log, "alarm-log-id: %"PRIu64"\n", + ++_customer_alarm_log_id ); + fprintf( _customer_alarm_log, "alarm-type: %s\n", + sm_alarm_thread_alarm_str( entry->alarm ) ); + + if( '\0' != entry->alarm_node_name[0] ) + { + fprintf( _customer_alarm_log, "alarm-node: %s\n", + entry->alarm_node_name ); + } + + fprintf( _customer_alarm_log, "alarm-domain: %s\n", + entry->alarm_domain_name ); + fprintf( _customer_alarm_log, "alarm-entity: %s\n", + entry->alarm_entity_name ); + fprintf( _customer_alarm_log, "alarm-event-type: %s\n", + sm_alarm_thread_event_type_str( entry->alarm_data.event_type ) ); + fprintf( _customer_alarm_log, "alarm-probable-cause: %s\n", + sm_alarm_thread_probable_cause_str( entry->alarm_data.probable_cause ) ); + + if( '\0' != entry->alarm_data.specific_problem_text[0] ) + { + fprintf( _customer_alarm_log, "alarm-specific-problem-text: %s\n", + entry->alarm_data.specific_problem_text ); + } + + fprintf( _customer_alarm_log, "alarm-perceived-severity: %s\n", + sm_alarm_thread_severity_str( entry->alarm_data.perceived_severity ) ); + + if( SM_ALARM_SEVERITY_CLEARED != entry->alarm_data.perceived_severity ) + { + fprintf( _customer_alarm_log, "alarm-trend-indication: %s\n", + sm_alarm_thread_trend_str( entry->alarm_data.trend_indication ) ); + } + + if( entry->alarm_data.state_info.applicable ) + { + fprintf( _customer_alarm_log, "alarm-entity-state: %s\n", + entry->alarm_data.state_info.state ); + fprintf( _customer_alarm_log, "alarm-entity-status: %s\n", + entry->alarm_data.state_info.status ); + fprintf( _customer_alarm_log, "alarm-entity-condition: %s\n", + entry->alarm_data.state_info.condition ); + } + + if( entry->alarm_data.threshold_info.applicable ) + { + fprintf( _customer_alarm_log, "alarm-threshold-value: %i\n", + entry->alarm_data.threshold_info.threshold_value ); + fprintf( _customer_alarm_log, "alarm-observed_value: %i\n", + entry->alarm_data.threshold_info.observed_value ); + } + + if( '\0' != entry->alarm_data.proposed_repair_action[0] ) + { + fprintf( _customer_alarm_log, "alarm-proposed-repair-action: %s\n", + entry->alarm_data.proposed_repair_action ); + } + + if( '\0' != entry->alarm_data.additional_text[0] ) + { + fprintf( _customer_alarm_log, "alarm-additional-text: %s\n", + entry->alarm_data.additional_text ); + } + + if( SM_ALARM_SEVERITY_CLEARED != entry->alarm_data.perceived_severity ) + { + fprintf( _customer_alarm_log, "alarm-service-affecting: %s\n", + entry->alarm_data.service_affecting ? "yes" : "no" ); + fprintf( _customer_alarm_log, "alarm-suppression-allowed: %s\n", + entry->alarm_data.suppression_allowed ? "yes" : "no" ); + } + + if( 0 != entry->alarm_raised_time.tv_sec ) + { + if( NULL == localtime_r( &(entry->alarm_raised_time.tv_sec), &t_real ) ) + { + fprintf( _customer_alarm_log, "alarm-raised-time: " + "YYYY:MM:DD HH:MM:SS.xxx\n" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + fprintf( _customer_alarm_log, "alarm-raised-time: " + "%s.%03ld\n", date_str, + entry->alarm_raised_time.tv_nsec/1000000 ); + } + } + + if( 0 != entry->alarm_changed_time.tv_sec ) + { + if( NULL == localtime_r( &(entry->alarm_changed_time.tv_sec), &t_real ) ) + { + fprintf( _customer_alarm_log, "alarm-changed-time: " + "YYYY:MM:DD HH:MM:SS.xxx\n" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + fprintf( _customer_alarm_log, "alarm-changed-time: " + "%s.%03ld\n", date_str, + entry->alarm_changed_time.tv_nsec/1000000 ); + } + } + + if( 0 != entry->alarm_cleared_time.tv_sec ) + { + if( NULL == localtime_r( &(entry->alarm_cleared_time.tv_sec), &t_real ) ) + { + fprintf( _customer_alarm_log, "alarm-cleared-time: " + "YYYY:MM:DD HH:MM:SS.xxx\n" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + fprintf( _customer_alarm_log, "alarm-cleared-time: " + "%s.%03ld\n", date_str, + entry->alarm_cleared_time.tv_nsec/1000000 ); + } + } + + fprintf( _customer_alarm_log, "\n" ); + fflush( _customer_alarm_log ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Find Empty Domain +// ================================ +static SmAlarmDomainEntryT* sm_alarm_thread_find_empty_domain( void ) +{ + SmAlarmDomainEntryT* domain_entry; + + int domain_i; + for( domain_i=0; SM_ALARM_DOMAINS_MAX > domain_i; ++domain_i ) + { + domain_entry = &(_alarm_domains[domain_i]); + + if( SM_ALARM_DOMAIN_ENTRY_INUSE != domain_entry->inuse ) + { + return( domain_entry ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Find Domain +// ========================== +static SmAlarmDomainEntryT* sm_alarm_thread_find_domain( + SmAlarmDomainNameT domain_name ) +{ + SmAlarmDomainEntryT* domain_entry; + + int domain_i; + for( domain_i=0; SM_ALARM_DOMAINS_MAX > domain_i; ++domain_i ) + { + domain_entry = &(_alarm_domains[domain_i]); + + if( SM_ALARM_DOMAIN_ENTRY_INUSE == domain_entry->inuse ) + { + if( 0 == strcmp( domain_name, domain_entry->alarm_domain_name ) ) + { + return( domain_entry ); + } + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Domain Managed +// ============================= +static bool sm_alarm_thread_domain_managed( SmAlarmT alarm ) +{ + switch( alarm ) + { + case SM_ALARM_SERVICE_GROUP_STATE: + return( true ); + break; + + case SM_ALARM_SERVICE_GROUP_REDUNDANCY: + return( true ); + break; + + case SM_ALARM_SOFTWARE_MODIFICATION: + return( false ); + break; + + case SM_ALARM_COMMUNICATION_FAILURE: + return( false ); + break; + + default: + DPRINTFE( "Unknown alarm (%i).", alarm ); + return( false ); + break; + } + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Find Empty +// ========================= +static SmAlarmEntryT* sm_alarm_thread_find_empty( void ) +{ + SmAlarmEntryT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_ALARMS_MAX > entry_i; ++entry_i ) + { + entry = &(_alarms[entry_i]); + + if( SM_ALARM_ENTRY_INUSE != entry->inuse ) + return( entry ); + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Find +// =================== +static SmAlarmEntryT* sm_alarm_thread_find( SmAlarmT alarm, + SmAlarmNodeNameT node_name, SmAlarmDomainNameT domain_name, + SmAlarmEntityNameT entity_name ) +{ + SmAlarmEntryT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_ALARMS_MAX > entry_i; ++entry_i ) + { + entry = &(_alarms[entry_i]); + + if( SM_ALARM_ENTRY_INUSE != entry->inuse ) + continue; + + if(( alarm == entry->alarm )&& + ( 0 == strcmp( node_name, entry->alarm_node_name ) )&& + ( 0 == strcmp( domain_name, entry->alarm_domain_name ) )&& + ( 0 == strcmp( entity_name, entry->alarm_entity_name ) )) + return( entry ); + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Add +// ================== +static void sm_alarm_thread_add( struct timespec* ts_real, SmAlarmT alarm, + SmAlarmNodeNameT node_name, SmAlarmDomainNameT domain_name, + SmAlarmEntityNameT entity_name, SmAlarmDataT* data ) +{ + bool raise_alarm = false; + SmAlarmEntryT* entry; + + entry = sm_alarm_thread_find( alarm, node_name, domain_name, entity_name ); + if( NULL == entry ) + { + entry = sm_alarm_thread_find_empty(); + if( NULL == entry ) + { + DPRINTFE( "Failed to store alarm, no more room." ); + return; + + } else { + // New alarm entry. + memset( entry, 0, sizeof(SmAlarmEntryT) ); + + entry->inuse = SM_ALARM_ENTRY_INUSE; + entry->alarm = alarm; + entry->alarm_state = SM_ALARM_STATE_INITIAL; + snprintf( entry->alarm_node_name, sizeof(entry->alarm_node_name), + "%s", node_name ); + snprintf( entry->alarm_domain_name, sizeof(entry->alarm_domain_name), + "%s", domain_name ); + snprintf( entry->alarm_entity_name, sizeof(entry->alarm_entity_name), + "%s", entity_name ); + } + } + + switch( entry->alarm_state ) + { + case SM_ALARM_STATE_INITIAL: + case SM_ALARM_STATE_CLEARING: + case SM_ALARM_STATE_CLEARED: + memcpy( &(entry->alarm_raised_time), ts_real, sizeof(struct timespec) ); + memset( &(entry->alarm_changed_time), 0, sizeof(struct timespec) ); + memset( &(entry->alarm_cleared_time), 0, sizeof(struct timespec) ); + raise_alarm = true; + break; + + case SM_ALARM_STATE_RAISING: + case SM_ALARM_STATE_RAISED: + if( 0 != memcmp( &(entry->alarm_data), data, sizeof(SmAlarmDataT) ) ) + { + memcpy( &(entry->alarm_changed_time), ts_real, sizeof(struct timespec) ); + memset( &(entry->alarm_cleared_time), 0, sizeof(struct timespec) ); + raise_alarm = true; + } + break; + + default: + // Ignore. + break; + } + + if( raise_alarm ) + { + entry->alarm_state = SM_ALARM_STATE_RAISING; + memcpy( &(entry->alarm_data), data, sizeof(entry->alarm_data) ); + DPRINTFI( "Raising alarm (%s) for node (%s) domain (%s) entity (%s).", + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Delete +// ===================== +static void sm_alarm_thread_delete( struct timespec* ts_real, SmAlarmT alarm, + SmAlarmNodeNameT node_name, SmAlarmDomainNameT domain_name, + SmAlarmEntityNameT entity_name ) +{ + SmAlarmEntryT* entry; + + entry = sm_alarm_thread_find( alarm, node_name, domain_name, entity_name ); + if( NULL == entry ) + { + DPRINTFD( "No alarm (%s) raised for node (%s) domain (%s) entity (%s) " + "found.", sm_alarm_thread_alarm_str( alarm ), node_name, + domain_name, entity_name ); + return; + } + + if( SM_ALARM_STATE_CLEARED != entry->alarm_state ) + { + memcpy( &(entry->alarm_cleared_time), ts_real, sizeof(struct timespec) ); + entry->alarm_state = SM_ALARM_STATE_CLEARING; + DPRINTFI( "Clearing alarm (%s) for node (%s) domain (%s) entity (%s).", + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name ); + }else + { + DPRINTFI( "Removed cleared alarm (%s) for node (%s) domain (%s) entity (%s).", + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name ); + entry->inuse = 0; //This alarm has reached the end of its lifecycle + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Get Alarm Identifier +// =================================== +static void sm_alarm_thread_get_alarm_id( SFmAlarmDataT* fm_alarm, + SmAlarmT* alarm, SmAlarmNodeNameT alarm_node_name, + SmAlarmDomainNameT alarm_domain_name, SmAlarmEntityNameT alarm_entity_name ) +{ + char fm_entity_instance_id[FM_MAX_BUFFER_LENGTH]; + int len; + + *alarm = SM_ALARM_UNKNOWN; + alarm_node_name[0] = '\0'; + alarm_domain_name[0] = '\0'; + alarm_entity_name[0] = '\0'; + + len = snprintf( fm_entity_instance_id, sizeof(fm_entity_instance_id), + "%s", fm_alarm->entity_instance_id ); + + int char_i; + for( char_i=0; len > char_i; ++char_i ) + { + if( '.' == fm_entity_instance_id[char_i] ) + { + fm_entity_instance_id[char_i] = ' '; + } + } + + if( 0 == strcmp( fm_alarm->alarm_id, + SM_ALARM_SERVICE_GROUP_STATE_ALARM_ID ) ) + { + *alarm = SM_ALARM_SERVICE_GROUP_STATE; + sscanf( fm_entity_instance_id, + "service_domain=%s service_group=%s host=%s", + alarm_domain_name, alarm_entity_name, alarm_node_name ); + return; + } + + if( 0 == strcmp( fm_alarm->alarm_id, + SM_ALARM_SERVICE_GROUP_REDUNDANCY_ALARM_ID ) ) + { + *alarm = SM_ALARM_SERVICE_GROUP_REDUNDANCY; + sscanf( fm_entity_instance_id, + "service_domain=%s service_group=%s", + alarm_domain_name, alarm_entity_name ); + return; + } + + if( 0 == strcmp( fm_alarm->alarm_id, + SM_ALARM_SOFTWARE_MODIFICATION_ALARM_ID ) ) + { + *alarm = SM_ALARM_SOFTWARE_MODIFICATION; + sscanf( fm_entity_instance_id, "host=%s", alarm_node_name ); + return; + } + + if( 0 == strcmp( fm_alarm->alarm_id, + SM_ALARM_COMMUNICATION_FAILURE_ALARM_ID ) ) + { + *alarm = SM_ALARM_COMMUNICATION_FAILURE; + sscanf( fm_entity_instance_id, "host=%s network=%s", + alarm_node_name, alarm_entity_name ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Get Fault Management Alarm Identifier +// ==================================================== +static SmErrorT sm_alarm_thread_get_fm_alarm_id( SmAlarmT alarm, + const SmAlarmNodeNameT alarm_node_name, + const SmAlarmDomainNameT alarm_domain_name, + const SmAlarmEntityNameT alarm_entity_name, char fm_alarm_id[], + char fm_entity_type_id[], char fm_entity_instance_id[] ) +{ + switch( alarm ) + { + case SM_ALARM_SERVICE_GROUP_STATE: + snprintf( fm_alarm_id, FM_MAX_BUFFER_LENGTH, + SM_ALARM_SERVICE_GROUP_STATE_ALARM_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, + "service_domain.service_group.host" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "service_domain=%s.service_group=%s.host=%s", + alarm_domain_name, alarm_entity_name, alarm_node_name ); + break; + + case SM_ALARM_SERVICE_GROUP_REDUNDANCY: + snprintf( fm_alarm_id, FM_MAX_BUFFER_LENGTH, + SM_ALARM_SERVICE_GROUP_REDUNDANCY_ALARM_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, + "service_domain.service_group" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "service_domain=%s.service_group=%s", + alarm_domain_name, alarm_entity_name ); + break; + + case SM_ALARM_SOFTWARE_MODIFICATION: + snprintf( fm_alarm_id, FM_MAX_BUFFER_LENGTH, + SM_ALARM_SOFTWARE_MODIFICATION_ALARM_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, "host" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "host=%s", alarm_node_name ); + break; + + case SM_ALARM_COMMUNICATION_FAILURE: + snprintf( fm_alarm_id, FM_MAX_BUFFER_LENGTH, + SM_ALARM_COMMUNICATION_FAILURE_ALARM_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, + "host.network" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "host=%s.network=%s", alarm_node_name, + alarm_entity_name ); + break; + + default: + DPRINTFE( "Unknown alarm (%i).", alarm ); + return( SM_FAILED ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Get Fault Management Alarm Type +// ============================================== +static EFmAlarmTypeT sm_alarm_thread_get_fm_alarm_type( SmAlarmEntryT* entry ) +{ + switch( entry->alarm_data.event_type ) + { + case SM_ALARM_EVENT_TYPE_UNKNOWN: + return( FM_ALARM_TYPE_UNKNOWN ); + break; + + case SM_ALARM_EVENT_TYPE_COMMUNICATIONS_ALARM: + return( FM_ALARM_COMM ); + break; + + case SM_ALARM_EVENT_TYPE_PROCESSING_ERROR_ALARM: + return( FM_ALARM_PROCESSING_ERROR ); + break; + + case SM_ALARM_EVENT_TYPE_ENVIRONMENTAL_ALARM: + return( FM_ALARM_ENVIRONMENTAL ); + break; + + case SM_ALARM_EVENT_TYPE_QUALITY_OF_SERVICE_ALARM: + return( FM_ALARM_QOS ); + break; + + case SM_ALARM_EVENT_TYPE_EQUIPMENT_ALARM: + return( FM_ALARM_EQUIPMENT ); + break; + + case SM_ALARM_EVENT_TYPE_INTEGRITY_VIOLATION: + return( FM_ALARM_INTERGRITY ); + break; + + case SM_ALARM_EVENT_TYPE_OPERATIONAL_VIOLATION: + return( FM_ALARM_OPERATIONAL ); + break; + + case SM_ALARM_EVENT_TYPE_PHYSICAL_VIOLATION: + return( FM_ALARM_PHYSICAL ); + break; + + case SM_ALARM_EVENT_TYPE_SECURITY_SERVICE_VIOLATION: + return( FM_ALARM_SECURITY ); + break; + + case SM_ALARM_EVENT_TYPE_MECHANISM_VIOLATION: + return( FM_ALARM_SECURITY ); + break; + + case SM_ALARM_EVENT_TYPE_TIME_DOMAIN_VIOLATION: + return( FM_ALARM_TIME ); + break; + + default: + DPRINTFI( "Unknown event type (%i) for alarm (%s) " + "entity (%s).", entry->alarm_data.event_type, + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_entity_name ); + return( FM_ALARM_TYPE_UNKNOWN ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Get Fault Management Severity +// ============================================ +static EFmAlarmSeverityT sm_alarm_thread_get_fm_severity( SmAlarmEntryT* entry ) +{ + switch( entry->alarm_data.perceived_severity ) + { + case SM_ALARM_SEVERITY_CLEARED: + return( FM_ALARM_SEVERITY_CLEAR ); + break; + + case SM_ALARM_SEVERITY_INDETERMINATE: + DPRINTFI( "Indeterminate severity for alarm (%s) entity (%s) " + "mapped to critical.", + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_entity_name ); + return( FM_ALARM_SEVERITY_CRITICAL ); + break; + + case SM_ALARM_SEVERITY_WARNING: + return( FM_ALARM_SEVERITY_WARNING ); + break; + + case SM_ALARM_SEVERITY_MINOR: + return( FM_ALARM_SEVERITY_MINOR ); + break; + + case SM_ALARM_SEVERITY_MAJOR: + return( FM_ALARM_SEVERITY_MAJOR ); + break; + + case SM_ALARM_SEVERITY_CRITICAL: + return( FM_ALARM_SEVERITY_CRITICAL ); + break; + + default: + DPRINTFI( "Unknown severity (%i) for alarm (%s) entity (%s) " + "mapped to warning.", + entry->alarm_data.perceived_severity, + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_entity_name ); + return( FM_ALARM_SEVERITY_WARNING ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm - Get Fault Management Probable Cause +// =========================================== +static EFmAlarmProbableCauseT sm_alarm_thread_get_fm_probable_cause( + SmAlarmEntryT* entry ) +{ + switch( entry->alarm_data.probable_cause ) + { + case SM_ALARM_PROBABLE_CAUSE_UNKNOWN: + return( FM_ALARM_CAUSE_UNKNOWN ); + break; + + case SM_ALARM_PROBABLE_CAUSE_INDETERMINATE: + return( FM_ALARM_CAUSE_UNKNOWN ); + break; + + case SM_ALARM_PROBABLE_CAUSE_SOFTWARE_ERROR: + return( FM_ALARM_SOFTWARE_ERROR ); + break; + + case SM_ALARM_PROBABLE_CAUSE_SOFTWARE_PROGRAM_ERROR: + return( FM_ALARM_PROGRAM_ERROR ); + break; + + case SM_ALARM_PROBABLE_CAUSE_UNDERLYING_RESOURCE_UNAVAILABLE: + return( FM_ALARM_UNDERLYING_RESOURCE_UNAVAILABLE ); + break; + + case SM_ALARM_PROBABLE_CAUSE_KEY_EXPIRED: + return( FM_ALARM_KEY_EXPIRED ); + break; + + default: + DPRINTFI( "Unknown probable cause (%i) for alarm (%s) " + "entity (%s).", entry->alarm_data.probable_cause, + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_entity_name ); + return( FM_ALARM_CAUSE_UNKNOWN ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Build Fault Management Alarm Data +// ================================================ +static SmErrorT sm_alarm_thread_build_fm_alarm_data( SmAlarmEntryT* entry ) +{ + SFmAlarmDataT* fm_alarm_data = &(entry->fm_alarm_data); + SmErrorT error; + + error = sm_alarm_thread_get_fm_alarm_id( entry->alarm, + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name, fm_alarm_data->alarm_id, + fm_alarm_data->entity_type_id, + fm_alarm_data->entity_instance_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get alarm (%s) data for node (%s) domain (%s) " + "entity (%s), error=%s.", + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name, sm_error_str( error ) ); + return( error ); + } + + fm_alarm_data->alarm_state = FM_ALARM_STATE_SET; + + fm_alarm_data->severity = sm_alarm_thread_get_fm_severity( entry ); + + // FM only has a reason text field. Need to concatenate the + // specific_problem_text and addition text fields. + // Capitalize the first character. + if( '\0' == entry->alarm_data.additional_text[0] ) + { + snprintf( fm_alarm_data->reason_text, + sizeof(fm_alarm_data->reason_text), "%s", + entry->alarm_data.specific_problem_text ); + } else { + snprintf( fm_alarm_data->reason_text, + sizeof(fm_alarm_data->reason_text), "%s; %s", + entry->alarm_data.specific_problem_text, + entry->alarm_data.additional_text ); + } + + if( isalpha( fm_alarm_data->reason_text[0] ) ) + { + fm_alarm_data->reason_text[0] + = toupper( fm_alarm_data->reason_text[0] ); + } + + fm_alarm_data->alarm_type = sm_alarm_thread_get_fm_alarm_type( entry ); + fm_alarm_data->probable_cause = sm_alarm_thread_get_fm_probable_cause( entry ); + + // Capitalize the first character. + snprintf( fm_alarm_data->proposed_repair_action, + sizeof(fm_alarm_data->proposed_repair_action), + "%s", entry->alarm_data.proposed_repair_action ); + + if( isalpha( fm_alarm_data->proposed_repair_action[0] ) ) + { + fm_alarm_data->proposed_repair_action[0] + = toupper( fm_alarm_data->proposed_repair_action[0] ); + } + + if( entry->alarm_data.service_affecting ) + { + fm_alarm_data->service_affecting = FM_TRUE; + } else { + fm_alarm_data->service_affecting = FM_FALSE; + } + + if( entry->alarm_data.suppression_allowed ) + { + fm_alarm_data->suppression = FM_TRUE; + } else { + fm_alarm_data->suppression = FM_FALSE; + } + + fm_alarm_data->inhibit_alarms = FM_FALSE; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Raise Alarm +// ========================== +static void sm_alarm_thread_raise_alarm( SmAlarmEntryT* entry ) +{ + EFmErrorT fm_error; + SmErrorT error; + + if( SM_ALARM_SEVERITY_CLEARED == entry->alarm_data.perceived_severity ) + { + DPRINTFE( "Attempting to raise a cleared alarm." ); + return; + } + + error = sm_alarm_thread_build_fm_alarm_data( entry ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to build alarm (%s) data for node (%s) domain (%s) " + "entity (%s), error=%s.", + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name, sm_error_str( error ) ); + return; + } + + fm_error = fm_set_fault_wrapper( &(entry->fm_alarm_data), + &(entry->fm_uuid) ); + if( FM_ERR_OK != fm_error ) + { + DPRINTFE( "Failed to set alarm (%s) for node (%s) domain (%s) " + "entity (%s), error=%i", + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name, fm_error ); + return; + } + + DPRINTFI( "Raised alarm (%s) for node (%s) domain (%s) entity (%s), " + "fm_uuid=%s.", sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name, entry->fm_uuid ); + + entry->alarm_state = SM_ALARM_STATE_RAISED; + + sm_alarm_thread_log( entry ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Clear Alarm +// ========================== +static void sm_alarm_thread_clear_alarm( SmAlarmEntryT* entry ) +{ + AlarmFilter fm_filter; + char fm_entity_type_id[FM_MAX_BUFFER_LENGTH]; + EFmErrorT fm_error; + SmErrorT error; + + error = sm_alarm_thread_get_fm_alarm_id( entry->alarm, + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name, fm_filter.alarm_id, + fm_entity_type_id, fm_filter.entity_instance_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get alarm (%s) data for entity (%s), " + "error=%s.", sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_entity_name, sm_error_str( error ) ); + return; + } + + fm_error = fm_clear_fault_wrapper( &fm_filter ); + if(( FM_ERR_OK != fm_error )&&( FM_ERR_ENTITY_NOT_FOUND != fm_error )) + { + DPRINTFE( "Failed to clear alarm (%s) for node (%s) domain (%s) " + "entity (%s), error=%i", + sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name, fm_error ); + return; + } + + DPRINTFI( "Cleared alarm (%s) for node (%s) domain (%s) entity (%s), " + "fm_uuid=%s.", sm_alarm_thread_alarm_str( entry->alarm ), + entry->alarm_node_name, entry->alarm_domain_name, + entry->alarm_entity_name, entry->fm_uuid ); + + entry->alarm_state = SM_ALARM_STATE_CLEARED; + entry->alarm_data.perceived_severity = SM_ALARM_SEVERITY_CLEARED; + entry->alarm_data.state_info.applicable = false; + entry->alarm_data.threshold_info.applicable = false; + entry->alarm_data.proposed_repair_action[0] = '\0'; + entry->alarm_data.additional_text[0] = '\0'; + + sm_alarm_thread_log( entry ); + entry->inuse = 0; //This alarm has reached the end of its lifecycle +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Clear All +// ======================== +static void sm_alarm_thread_clear_all( struct timespec* ts_real, + SmAlarmDomainNameT domain_name ) +{ + char date_str[32]; + struct tm t_real; + char fm_entity_instance_id[FM_MAX_BUFFER_LENGTH]; + EFmErrorT fm_error; + SmAlarmEntryT* entry = NULL; + + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "service_domain=%s", domain_name ); + + fm_error = fm_clear_all_wrapper( &fm_entity_instance_id ); + if(( FM_ERR_OK != fm_error )&&( FM_ERR_ENTITY_NOT_FOUND != fm_error )) + { + DPRINTFE( "Failed to clear service domain (%s) alarms, error=%i", + domain_name, fm_error ); + } + + DPRINTFI( "Cleared all alarms." ); + + unsigned int entry_i; + for( entry_i=0; SM_ALARMS_MAX > entry_i; ++entry_i ) + { + entry = &(_alarms[entry_i]); + + if( SM_ALARM_ENTRY_INUSE != entry->inuse ) + continue; + + if( 0 == strcmp( domain_name, entry->alarm_domain_name ) ) + { + memset( entry, 0, sizeof(SmAlarmEntryT) ); + } + } + + if( NULL == localtime_r( &(ts_real->tv_sec), &t_real ) ) + { + fprintf( _customer_alarm_log, + "----- all alarms cleared for %s -----\n\n", + domain_name ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + fprintf( _customer_alarm_log, "----- all alarms cleared for %s at " + "%s.%03ld -----\n\n", domain_name, date_str, + ts_real->tv_nsec/1000000 ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Manage Domain Alarms +// =================================== +static void sm_alarm_thread_manage_domain_alarms( + SmAlarmDomainNameT domain_name, bool manage ) +{ + SmAlarmEntryT* entry; + SmAlarmDomainEntryT* domain_entry; + + domain_entry = sm_alarm_thread_find_domain( domain_name ); + if( NULL == domain_entry ) + { + domain_entry = sm_alarm_thread_find_empty_domain(); + if( NULL == domain_entry ) + { + DPRINTFE( "Alarm domain allocation failure, no free alarm " + "domain entries." ); + return; + } + + domain_entry->inuse = SM_ALARM_DOMAIN_ENTRY_INUSE; + domain_entry->manage = manage; + snprintf( domain_entry->alarm_domain_name, + sizeof(domain_entry->alarm_domain_name), "%s", + domain_name ); + } else { + domain_entry->manage = manage; + } + + if( manage ) + { + DPRINTFI( "Managing alarms for domain (%s).", domain_name ); + + } else { + DPRINTFI( "No longer managing alarms for domain (%s).", domain_name ); + + unsigned int entry_i; + for( entry_i=0; SM_ALARMS_MAX > entry_i; ++entry_i ) + { + entry = &(_alarms[entry_i]); + + if( SM_ALARM_ENTRY_INUSE == entry->inuse ) + { + if( sm_alarm_thread_domain_managed( entry->alarm ) ) + { + memset( entry, 0, sizeof(SmAlarmEntryT) ); + } + } + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Report +// ===================== +static void sm_alarm_thread_report( void ) +{ + SmAlarmEntryT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_ALARMS_MAX > entry_i; ++entry_i ) + { + entry = &(_alarms[entry_i]); + + if( SM_ALARM_ENTRY_INUSE != entry->inuse ) + continue; + + // Call Fault Management. + if( SM_ALARM_STATE_CLEARING == entry->alarm_state ) + { + sm_alarm_thread_clear_alarm( entry ); + + } else if( SM_ALARM_STATE_RAISING == entry->alarm_state ) { + sm_alarm_thread_raise_alarm( entry ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Audit +// ==================== +static void sm_alarm_thread_audit( const char entity_instance[] ) +{ + bool found; + char fm_entity_instance_id[FM_MAX_BUFFER_LENGTH]; + SFmAlarmDataT fm_alarm_data[SM_ALARMS_MAX]; + unsigned fm_total_alarms = SM_ALARMS_MAX; + SFmAlarmDataT* fm_alarm; + EFmErrorT fm_error; + SmAlarmT alarm; + SmAlarmNodeNameT node_name; + SmAlarmDomainNameT domain_name; + SmAlarmEntityNameT entity_name; + SmAlarmEntryT* entry; + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmErrorT error; + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return; + } + + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, entity_instance ); + + fm_error = fm_get_faults_wrapper( &fm_entity_instance_id, fm_alarm_data, + &fm_total_alarms ); + if(( FM_ERR_OK != fm_error )&&( FM_ERR_ENTITY_NOT_FOUND != fm_error )) + { + DPRINTFE( "Failed to get all alarms, error=%i", fm_error ); + return; + } + + unsigned int fm_alarm_i; + for( fm_alarm_i=0; fm_total_alarms > fm_alarm_i; ++fm_alarm_i ) + { + found = false; + fm_alarm = &(fm_alarm_data[fm_alarm_i]); + + sm_alarm_thread_get_alarm_id( fm_alarm, &alarm, node_name, + domain_name, entity_name ); + + DPRINTFD( "Looking at fm_alarm_id=%s, fm_entity_instance_id=%s, " + "alarm=%i, node_name=%s, domain_name=%s, entity_name=%s.", + fm_alarm->alarm_id, fm_alarm->entity_instance_id, alarm, + node_name, domain_name, entity_name ); + + if( SM_ALARM_UNKNOWN == alarm ) + { + continue; + } + + if( sm_alarm_thread_domain_managed( alarm ) ) + { + SmAlarmDomainEntryT* domain_entry; + + domain_entry = sm_alarm_thread_find_domain( domain_name ); + if( NULL == domain_entry ) + { + DPRINTFD( "Alarm domain (%s) not found.", domain_name ); + continue; + } + + if( !domain_entry->manage ) + { + DPRINTFD( "Not managing alarm domain (%s).", domain_name ); + continue; + } + } else if( 0 != strcmp( hostname, node_name ) ) { + DPRINTFD( "Not our alarm, node_name=%s.", node_name ); + continue; + } + + entry = sm_alarm_thread_find( alarm, node_name, domain_name, + entity_name ); + if( NULL != entry ) + { + if( SM_ALARM_STATE_RAISING == entry->alarm_state + || SM_ALARM_STATE_RAISED == entry->alarm_state ) + { + // only when a matching record locally to be considered as "found" + found = true; + entry->alarm_state = SM_ALARM_STATE_RAISED; + }else + { + // found a record, but not in raising/raised mode, alarm need to be cleared + } + } + + if( !found ) + { + AlarmFilter fm_filter; + + snprintf( fm_filter.alarm_id, sizeof(fm_filter.alarm_id), "%s", + fm_alarm->alarm_id ); + snprintf( fm_filter.entity_instance_id, + sizeof(fm_filter.entity_instance_id), "%s", + fm_alarm->entity_instance_id ); + + fm_error = fm_clear_fault_wrapper( &fm_filter ); + if(( FM_ERR_OK != fm_error )&&( FM_ERR_ENTITY_NOT_FOUND != fm_error )) + { + DPRINTFE( "Failed to clear stale alarm (fm_alarm_id=%s, " + "fm_entity_instance_id=%s), error=%i", + fm_alarm->alarm_id, fm_alarm->entity_instance_id, + fm_error ); + } + + if ( NULL != entry ) + { + //alarm is cleared, retire the record + entry->inuse = 0; + DPRINTFI( "Removed cleared alarm, fm_alarm_id=%s, " + "fm_entity_instance_id=%s, fm_uuid=%s.", + fm_alarm->alarm_id, fm_alarm->entity_instance_id, + fm_alarm->uuid ); + }else + { + DPRINTFI( "Deleted stale alarm, fm_alarm_id=%s, " + "fm_entity_instance_id=%s, fm_uuid=%s.", + fm_alarm->alarm_id, fm_alarm->entity_instance_id, + fm_alarm->uuid ); + } + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Report Timer +// =========================== +static bool sm_alarm_thread_report_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + sm_alarm_thread_report(); + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Audit Timer +// ========================== +static bool sm_alarm_thread_audit_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + SmAlarmEntryT* entry; + + // Set raised alarms to raising, the audit will set them + // to raised, if FM really has them. + unsigned int entry_i; + for( entry_i=0; SM_ALARMS_MAX > entry_i; ++entry_i ) + { + entry = &(_alarms[entry_i]); + + if( SM_ALARM_ENTRY_INUSE != entry->inuse ) + continue; + + if( SM_ALARM_STATE_RAISED == entry->alarm_state ) + { + entry->alarm_state = SM_ALARM_STATE_RAISING; + } + } + + sm_alarm_thread_audit( "service_domain" ); + sm_alarm_thread_audit( "host" ); + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Dispatch +// ======================= +static void sm_alarm_thread_dispatch( int selobj, int64_t user_data ) +{ + int bytes_read; + SmAlarmThreadMsgT msg; + SmAlarmThreadMsgRaiseAlarmT* raise_alarm = &(msg.u.raise_alarm); + SmAlarmThreadMsgClearAlarmT* clear_alarm = &(msg.u.clear_alarm); + SmAlarmThreadMsgClearAllAlarmsT* clear_all_alarms = &(msg.u.clear_all_alarms); + SmAlarmThreadMsgManageDomainAlarmsT* manage_alarms = &(msg.u.manage_alarms); + bool report_alarm = false; + + memset( &msg, 0, sizeof(msg) ); + + int retry_count; + for( retry_count = 5; retry_count != 0; --retry_count ) + { + bytes_read = recv( selobj, &msg, sizeof(msg), 0 ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_count, strerror( errno ) ); + } + + switch( msg.type ) + { + case SM_ALARM_THREAD_MSG_RAISE_ALARM: + sm_alarm_thread_add( &(raise_alarm->ts_real), raise_alarm->alarm, + raise_alarm->node_name, raise_alarm->domain_name, + raise_alarm->entity_name, &(raise_alarm->data) ); + report_alarm = true; + break; + + case SM_ALARM_THREAD_MSG_CLEAR_ALARM: + sm_alarm_thread_delete( &(clear_alarm->ts_real), clear_alarm->alarm, + clear_alarm->node_name, clear_alarm->domain_name, + clear_alarm->entity_name ); + report_alarm = true; + break; + + case SM_ALARM_THREAD_MSG_CLEAR_ALL_ALARMS: + sm_alarm_thread_clear_all( &(clear_alarm->ts_real), + clear_all_alarms->domain_name ); + break; + + case SM_ALARM_THREAD_MSG_MANAGE_DOMAIN_ALARMS: + sm_alarm_thread_manage_domain_alarms( manage_alarms->domain_name, + manage_alarms->manage ); + break; + + default: + DPRINTFE( "Unknown message (%i) received.", msg.type ); + return; + break; + } + + if( report_alarm ) + sm_alarm_thread_report(); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Initialize Thread +// ================================ +static SmErrorT sm_alarm_thread_initialize_thread( void ) +{ + SmErrorT error; + + _server_fd_registered = false; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + if( -1 < _server_fd ) + { + error = sm_selobj_register( _server_fd, sm_alarm_thread_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + _server_fd_registered = true; + } + + error = sm_timer_initialize( SM_ALARM_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_register( "alarm report", + SM_ALARM_THREAD_ALARM_REPORT_TIMER_IN_MS, + sm_alarm_thread_report_timer, 0, + &_alarm_report_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create alarm report timer, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_register( "alarm audit", + SM_ALARM_THREAD_ALARM_AUDIT_TIMER_IN_MS, + sm_alarm_thread_audit_timer, 0, + &_alarm_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create alarm audit timer, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + if( NULL != _customer_alarm_log ) + { + fflush( _customer_alarm_log ); + fclose( _customer_alarm_log ); + _customer_alarm_log = NULL; + } + + _customer_alarm_log = fopen( SM_ALARM_CUSTOMER_LOG_FILE, "a" ); + if( NULL == _customer_alarm_log ) + { + DPRINTFE( "Failed to open customer alarm log file (%s).", + SM_ALARM_CUSTOMER_LOG_FILE ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Finalize Thread +// ============================== +static SmErrorT sm_alarm_thread_finalize_thread( void ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != _alarm_report_timer_id ) + { + error = sm_timer_deregister( _alarm_report_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel alarm report timer, error=%s.", + sm_error_str( error ) ); + } + + _alarm_report_timer_id = SM_TIMER_ID_INVALID; + } + + if( SM_TIMER_ID_INVALID != _alarm_audit_timer_id ) + { + error = sm_timer_deregister( _alarm_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel alarm audit timer, error=%s.", + sm_error_str( error ) ); + } + + _alarm_audit_timer_id = SM_TIMER_ID_INVALID; + } + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize timer module, error=%s.", + sm_error_str( error ) ); + } + + if( _server_fd_registered ) + { + error = sm_selobj_deregister( _server_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + _server_fd_registered = false; + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + if( NULL != _customer_alarm_log ) + { + fflush( _customer_alarm_log ); + fclose( _customer_alarm_log ); + _customer_alarm_log = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Main +// =================== +static void* sm_alarm_thread_main( void* arguments ) +{ + SmErrorT error; + + pthread_setname_np( pthread_self(), SM_ALARM_THREAD_NAME ); + sm_debug_set_thread_info(); + sm_trap_set_thread_info(); + + DPRINTFI( "Starting" ); + + // Warn after 2 minutes, fail after 16 minutes. + error = sm_thread_health_register( SM_ALARM_THREAD_NAME, 120000, 1000000 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register alarm thread, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + error = sm_alarm_thread_initialize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize alarm thread, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + DPRINTFI( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_ALARM_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + + error = sm_thread_health_update( SM_ALARM_THREAD_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update alarm thread health, error=%s.", + sm_error_str(error) ); + } + } + + DPRINTFI( "Shutting down." ); + + error = sm_alarm_thread_finalize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize alarm thread, error=%s.", + sm_error_str( error ) ); + } + + error = sm_thread_health_deregister( SM_ALARM_THREAD_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister alarm thread, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Start +// ==================== +SmErrorT sm_alarm_thread_start( int server_fd ) +{ + int result; + + memset( _alarms, 0, sizeof(_alarms) ); + memset( _alarm_domains, 0, sizeof(_alarm_domains) ); + + _stay_on = 1; + _thread_created = false; + _server_fd = server_fd; + + result = pthread_create( &_alarm_thread, NULL, sm_alarm_thread_main, NULL ); + if( 0 != result ) + { + DPRINTFE( "Failed to start alarm thread, error=%s.", + strerror(result) ); + return( SM_FAILED ); + } + + _thread_created = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Stop +// =================== +SmErrorT sm_alarm_thread_stop( void ) +{ + _stay_on = 0; + + if( _thread_created ) + { + long ms_expired; + SmTimeT time_prev; + int result; + + sm_time_get( &time_prev ); + + while( true ) + { + result = pthread_tryjoin_np( _alarm_thread, NULL ); + if(( 0 != result )&&( EBUSY != result )) + { + if(( ESRCH != result )&&( EINVAL != result )) + { + DPRINTFE( "Failed to wait for alarm thread exit, " + "sending kill signal, error=%s.", + strerror(result) ); + pthread_kill( _alarm_thread, SIGKILL ); + } + break; + } + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( 5000 <= ms_expired ) + { + DPRINTFE( "Failed to stop alarm thread, sending " + "kill signal." ); + pthread_kill( _alarm_thread, SIGKILL ); + break; + } + + usleep( 250000 ); // 250 milliseconds. + } + } + + _server_fd = -1; + _thread_created = false; + + memset( _alarms, 0, sizeof(_alarms) ); + memset( _alarm_domains, 0, sizeof(_alarm_domains) ); + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_alarm_thread.h b/service-mgmt/sm-1.0.0/src/sm_alarm_thread.h new file mode 100644 index 00000000..004795d6 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_alarm_thread.h @@ -0,0 +1,84 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_ALARM_THREAD_H__ +#define __SM_ALARM_THREAD_H__ + +#include "sm_types.h" +#include "sm_alarm_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + SM_ALARM_THREAD_MSG_RAISE_ALARM, + SM_ALARM_THREAD_MSG_CLEAR_ALARM, + SM_ALARM_THREAD_MSG_CLEAR_ALL_ALARMS, + SM_ALARM_THREAD_MSG_MANAGE_DOMAIN_ALARMS, +} SmAlarmThreadMsgTypeT; + +typedef struct +{ + struct timespec ts_real; + SmAlarmT alarm; + SmAlarmNodeNameT node_name; + SmAlarmDomainNameT domain_name; + SmAlarmEntityNameT entity_name; + SmAlarmDataT data; +} SmAlarmThreadMsgRaiseAlarmT; + +typedef struct +{ + struct timespec ts_real; + SmAlarmT alarm; + SmAlarmNodeNameT node_name; + SmAlarmDomainNameT domain_name; + SmAlarmEntityNameT entity_name; +} SmAlarmThreadMsgClearAlarmT; + +typedef struct +{ + struct timespec ts_real; + SmAlarmDomainNameT domain_name; +} SmAlarmThreadMsgClearAllAlarmsT; + +typedef struct +{ + bool manage; + SmAlarmDomainNameT domain_name; +} SmAlarmThreadMsgManageDomainAlarmsT; + +typedef struct +{ + SmAlarmThreadMsgTypeT type; + + union + { + SmAlarmThreadMsgRaiseAlarmT raise_alarm; + SmAlarmThreadMsgClearAlarmT clear_alarm; + SmAlarmThreadMsgClearAllAlarmsT clear_all_alarms; + SmAlarmThreadMsgManageDomainAlarmsT manage_alarms; + }u; +} SmAlarmThreadMsgT; + +// **************************************************************************** +// Alarm Thread - Start +// ==================== +extern SmErrorT sm_alarm_thread_start( int server_fd ); +// **************************************************************************** + +// **************************************************************************** +// Alarm Thread - Stop +// =================== +extern SmErrorT sm_alarm_thread_stop( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_ALARM_THREAD_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_api.c b/service-mgmt/sm-1.0.0/src/sm_api.c new file mode 100644 index 00000000..c63eaf38 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_api.c @@ -0,0 +1,631 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_api.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_timer.h" +#include "sm_selobj.h" + +#define SM_API_MSG_SERVER_ADDRESS "/tmp/.sm_server_api" +#define SM_API_MSG_CLIENT_ADDRESS "/tmp/.sm_client_api" + +#define SM_API_MSG_VERSION "1" +#define SM_API_MSG_REVISION "1" +#define SM_API_MSG_TYPE_SET_NODE "SET_NODE" +#define SM_API_MSG_TYPE_SET_NODE_ACK "SET_NODE_ACK" +#define SM_API_MSG_TYPE_RESTART_SERVICE "RESTART_SERVICE" +#define SM_API_MSG_SKIP_DEP_CHECK "skip-dep" + +#define SM_API_MSG_NODE_ACTION_UNKNOWN "unknown" +#define SM_API_MSG_NODE_ACTION_LOCK "lock" +#define SM_API_MSG_NODE_ACTION_UNLOCK "unlock" +#define SM_API_MSG_NODE_ACTION_SWACT "swact" +#define SM_API_MSG_NODE_ACTION_SWACT_FORCE "swact-force" +#define SM_API_MSG_NODE_ACTION_EVENT "event" + +#define SM_API_MSG_NODE_ADMIN_STATE_UNKNOWN "unknown" +#define SM_API_MSG_NODE_ADMIN_STATE_LOCKED "locked" +#define SM_API_MSG_NODE_ADMIN_STATE_UNLOCKED "unlocked" + +#define SM_API_MSG_NODE_OPER_STATE_UNKNOWN "unknown" +#define SM_API_MSG_NODE_OPER_STATE_ENABLED "enabled" +#define SM_API_MSG_NODE_OPER_STATE_DISABLED "disabled" + +#define SM_API_MSG_NODE_AVAIL_STATUS_UNKNOWN "unknown" +#define SM_API_MSG_NODE_AVAIL_STATUS_NONE "none" +#define SM_API_MSG_NODE_AVAIL_STATUS_AVAILABLE "available" +#define SM_API_MSG_NODE_AVAIL_STATUS_DEGRADED "degraded" +#define SM_API_MSG_NODE_AVAIL_STATUS_FAILED "failed" + +#define SM_API_MSG_VERSION_FIELD 0 +#define SM_API_MSG_REVISION_FIELD 1 +#define SM_API_MSG_SEQNO_FIELD 2 +#define SM_API_MSG_TYPE_FIELD 3 +#define SM_API_MSG_ORIGIN_FIELD 4 +#define SM_API_MSG_NODE_NAME_FIELD 5 +#define SM_API_MSG_NODE_ACTION_FIELD 6 +#define SM_API_MSG_NODE_ADMIN_FIELD 7 +#define SM_API_MSG_NODE_OPER_FIELD 8 +#define SM_API_MSG_NODE_AVAIL_FIELD 9 + +#define SM_API_MSG_SERVICE_NAME_FIELD 5 +#define SM_API_MSG_PARAM 6 + +#define SM_API_MAX_MSG_SIZE 2048 + +static int _sm_api_socket = -1; +static struct sockaddr_un _sm_api_client_address = {0}; +static socklen_t _sm_api_client_address_len = 0; +static char _tx_buffer[SM_API_MAX_MSG_SIZE] __attribute__((aligned)); +static char _rx_buffer[SM_API_MAX_MSG_SIZE] __attribute__((aligned)); +static SmApiCallbacksT _callbacks = {0}; + +// **************************************************************************** +// API - Register Callbacks +// ======================== +SmErrorT sm_api_register_callbacks( SmApiCallbacksT* callbacks ) +{ + memcpy( &_callbacks, callbacks, sizeof(SmApiCallbacksT) ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// API - Deregister Callbacks +// ========================== +SmErrorT sm_api_deregister_callbacks( SmApiCallbacksT* callbacks ) +{ + memset( &_callbacks, 0, sizeof(SmApiCallbacksT) ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// API - Node Set Action String +// ============================ +static const char* sm_api_node_action_string( SmNodeSetActionT action ) +{ + switch( action ) + { + case SM_NODE_SET_ACTION_LOCK: + return( SM_API_MSG_NODE_ACTION_LOCK ); + break; + case SM_NODE_SET_ACTION_UNLOCK: + return( SM_API_MSG_NODE_ACTION_UNLOCK ); + break; + case SM_NODE_SET_ACTION_SWACT: + return( SM_API_MSG_NODE_ACTION_SWACT ); + break; + case SM_NODE_SET_ACTION_SWACT_FORCE: + return( SM_API_MSG_NODE_ACTION_SWACT_FORCE ); + break; + case SM_NODE_SET_ACTION_EVENT: + return( SM_API_MSG_NODE_ACTION_EVENT ); + break; + default: + return( SM_API_MSG_NODE_ACTION_UNKNOWN ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// API - Node Set Action Value +// =========================== +static SmNodeSetActionT sm_api_node_action_value( const char* action_str ) +{ + if( 0 == strcmp( SM_API_MSG_NODE_ACTION_LOCK, action_str ) ) + { + return( SM_NODE_SET_ACTION_LOCK ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_ACTION_UNLOCK, action_str ) ) { + return( SM_NODE_SET_ACTION_UNLOCK ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_ACTION_SWACT, action_str ) ) { + return( SM_NODE_SET_ACTION_SWACT ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_ACTION_SWACT_FORCE, action_str ) ) { + return( SM_NODE_SET_ACTION_SWACT_FORCE ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_ACTION_EVENT, action_str ) ) { + return( SM_NODE_SET_ACTION_EVENT ); + + } else { + return( SM_NODE_SET_ACTION_UNKNOWN ); + } +} +// **************************************************************************** + +// **************************************************************************** +// API - Node Administrative State String +// ====================================== +static const char* sm_api_node_admin_state_string( + SmNodeAdminStateT admin_state ) +{ + switch( admin_state ) + { + case SM_NODE_ADMIN_STATE_LOCKED: + return( SM_API_MSG_NODE_ADMIN_STATE_LOCKED ); + break; + case SM_NODE_ADMIN_STATE_UNLOCKED: + return( SM_API_MSG_NODE_ADMIN_STATE_UNLOCKED ); + break; + default: + return( SM_API_MSG_NODE_ADMIN_STATE_UNKNOWN ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// API - Node Administrative State Value +// ===================================== +static SmNodeAdminStateT sm_api_node_admin_state_value( + const char* state_str ) +{ + if( 0 == strcmp( SM_API_MSG_NODE_ADMIN_STATE_LOCKED, state_str ) ) + { + return( SM_NODE_ADMIN_STATE_LOCKED ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_ADMIN_STATE_UNLOCKED, + state_str ) ) + { + return( SM_NODE_ADMIN_STATE_UNLOCKED ); + + } else { + return( SM_NODE_ADMIN_STATE_UNKNOWN ); + } +} +// **************************************************************************** + +// **************************************************************************** +// API - Node Operational State String +// =================================== +static const char* sm_api_node_oper_state_string( + SmNodeOperationalStateT oper_state ) +{ + switch( oper_state ) + { + case SM_NODE_OPERATIONAL_STATE_ENABLED: + return( SM_API_MSG_NODE_OPER_STATE_ENABLED ); + break; + case SM_NODE_OPERATIONAL_STATE_DISABLED: + return( SM_API_MSG_NODE_OPER_STATE_DISABLED ); + break; + default: + return( SM_API_MSG_NODE_OPER_STATE_UNKNOWN ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// API - Node Operational State Value +// ================================== +static SmNodeOperationalStateT sm_api_node_oper_state_value( + const char* state_str ) +{ + if( 0 == strcmp( SM_API_MSG_NODE_OPER_STATE_ENABLED, state_str ) ) + { + return( SM_NODE_OPERATIONAL_STATE_ENABLED ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_OPER_STATE_DISABLED, + state_str ) ) + { + return( SM_NODE_OPERATIONAL_STATE_DISABLED ); + + } else { + return( SM_NODE_OPERATIONAL_STATE_UNKNOWN ); + } +} +// **************************************************************************** + +// **************************************************************************** +// API - Node Availability Status String +// ===================================== +static const char* sm_api_node_avail_status_string( + SmNodeAvailStatusT avail_status ) +{ + switch( avail_status ) + { + case SM_NODE_AVAIL_STATUS_NONE: + return( SM_API_MSG_NODE_AVAIL_STATUS_NONE ); + break; + case SM_NODE_AVAIL_STATUS_AVAILABLE: + return( SM_API_MSG_NODE_AVAIL_STATUS_AVAILABLE ); + break; + case SM_NODE_AVAIL_STATUS_DEGRADED: + return( SM_API_MSG_NODE_AVAIL_STATUS_DEGRADED ); + break; + case SM_NODE_AVAIL_STATUS_FAILED: + return( SM_API_MSG_NODE_AVAIL_STATUS_FAILED ); + break; + default: + return( SM_API_MSG_NODE_AVAIL_STATUS_UNKNOWN ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// API - Node Availability Status Value +// ==================================== +static SmNodeAvailStatusT sm_api_node_avail_status_value( + const char* state_str ) +{ + if( 0 == strcmp( SM_API_MSG_NODE_AVAIL_STATUS_NONE, state_str ) ) + { + return( SM_NODE_AVAIL_STATUS_NONE ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_AVAIL_STATUS_AVAILABLE, + state_str ) ) + { + return( SM_NODE_AVAIL_STATUS_AVAILABLE ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_AVAIL_STATUS_DEGRADED, + state_str ) ) + { + return( SM_NODE_AVAIL_STATUS_DEGRADED ); + + } else if( 0 == strcmp( SM_API_MSG_NODE_AVAIL_STATUS_FAILED, + state_str ) ) + { + return( SM_NODE_AVAIL_STATUS_FAILED ); + + } else { + return( SM_NODE_AVAIL_STATUS_UNKNOWN ); + } +} +// **************************************************************************** + +// **************************************************************************** +// API - Send Node Set +// =================== +SmErrorT sm_api_send_node_set( char node_name[], SmNodeSetActionT action, + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status, int seqno ) +{ + const char* action_str = sm_api_node_action_string(action); + const char* admin_state_str = sm_api_node_admin_state_string(admin_state); + const char* oper_state_str = sm_api_node_oper_state_string(oper_state); + const char* avail_status_str = sm_api_node_avail_status_string(avail_status); + int bytes_written; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + bytes_written = snprintf( _tx_buffer, sizeof(_tx_buffer), + "%s,%s,%i,%s,%s,%s,%s,%s,%s,%s", + SM_API_MSG_VERSION, SM_API_MSG_REVISION, + seqno, SM_API_MSG_TYPE_SET_NODE, "sm", + node_name, action_str, admin_state_str, + oper_state_str, avail_status_str ); + if( 0 < bytes_written ) + { + if( 0 > sendto( _sm_api_socket, &_tx_buffer, bytes_written, 0, + (struct sockaddr*) &_sm_api_client_address, + _sm_api_client_address_len ) ) + { + DPRINTFE( "Failed to send node (%s) set, error=%s", + node_name, strerror( errno ) ); + return( SM_FAILED ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// API - Send Node Set Ack +// ======================= +SmErrorT sm_api_send_node_set_ack( char node_name[], SmNodeSetActionT action, + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status, int seqno ) +{ + const char* action_str = sm_api_node_action_string(action); + const char* admin_state_str = sm_api_node_admin_state_string(admin_state); + const char* oper_state_str = sm_api_node_oper_state_string(oper_state); + const char* avail_status_str = sm_api_node_avail_status_string(avail_status); + int bytes_written; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + bytes_written = snprintf( _tx_buffer, sizeof(_tx_buffer), + "%s,%s,%i,%s,%s,%s,%s,%s,%s,%s", + SM_API_MSG_VERSION, SM_API_MSG_REVISION, + seqno, SM_API_MSG_TYPE_SET_NODE_ACK, "sm", + node_name, action_str, admin_state_str, + oper_state_str, avail_status_str ); + if( 0 < bytes_written ) + { + if( 0 > sendto( _sm_api_socket, &_tx_buffer, bytes_written, 0, + (struct sockaddr*) &_sm_api_client_address, + _sm_api_client_address_len ) ) + { + DPRINTFE( "Failed to send node (%s) set ack, error=%s", + node_name, strerror( errno ) ); + return( SM_FAILED ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// API - Dispatch +// ============== +static void sm_api_dispatch( int selobj, int64_t user_data ) +{ + int seqno; + char* node_name; + char* service_name; + gchar** params; + int bytes_read; + SmNodeSetActionT action; + SmNodeAdminStateT admin_state; + SmNodeOperationalStateT oper_state; + SmNodeAvailStatusT avail_status; + int action_flag = 0; + + int retry_count; + for( retry_count = 5; retry_count != 0; --retry_count ) + { + memset( _rx_buffer, 0, sizeof(_rx_buffer) ); + + bytes_read = recv( selobj, &_rx_buffer, sizeof(_rx_buffer), 0 ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_count, strerror( errno ) ); + } + + params = g_strsplit( _rx_buffer, ",", -1 ); + if( params[SM_API_MSG_VERSION_FIELD] == NULL ) + { + DPRINTFE( "Missing version field in received message." ); + goto ERROR; + } + + if( 0 != strcmp( SM_API_MSG_VERSION, params[SM_API_MSG_VERSION_FIELD] ) ) + { + DPRINTFE( "Unsupported version (%s) received, expected=%s.", + params[SM_API_MSG_VERSION_FIELD], SM_API_MSG_VERSION ); + goto ERROR; + } + + if( params[SM_API_MSG_REVISION_FIELD] == NULL ) + { + DPRINTFE( "Missing revision field in received message." ); + goto ERROR; + } + + if( params[SM_API_MSG_SEQNO_FIELD] == NULL ) + { + DPRINTFE( "Missing seqno field in received message." ); + goto ERROR; + } + + seqno = atoi( params[SM_API_MSG_SEQNO_FIELD] ); + + if( params[SM_API_MSG_TYPE_FIELD] == NULL ) + { + DPRINTFE( "Missing message-type field in received message." ); + goto ERROR; + } + + if( 0 == strcmp( SM_API_MSG_TYPE_SET_NODE, params[SM_API_MSG_TYPE_FIELD] ) ) + { + if( params[SM_API_MSG_ORIGIN_FIELD] == NULL ) + { + DPRINTFE( "Missing origin field in received message." ); + goto ERROR; + } + + if( params[SM_API_MSG_NODE_NAME_FIELD] == NULL ) + { + DPRINTFE( "Missing node-name field in received message." ); + goto ERROR; + } + + node_name = (char*) params[SM_API_MSG_NODE_NAME_FIELD]; + + if( params[SM_API_MSG_NODE_ACTION_FIELD] == NULL ) + { + DPRINTFE( "Missing node-action field in received message." ); + goto ERROR; + } + + action = sm_api_node_action_value( + (char*) params[SM_API_MSG_NODE_ACTION_FIELD]); + + if( params[SM_API_MSG_NODE_ADMIN_FIELD] == NULL ) + { + DPRINTFE( "Missing node-admin-state field in received message." ); + goto ERROR; + } + + admin_state = sm_api_node_admin_state_value( + (char*) params[SM_API_MSG_NODE_ADMIN_FIELD]); + + if( params[SM_API_MSG_NODE_OPER_FIELD] == NULL ) + { + DPRINTFE( "Missing node-oper-state field in received message." ); + goto ERROR; + } + + oper_state = sm_api_node_oper_state_value( + (char*) params[SM_API_MSG_NODE_OPER_FIELD]); + + if( params[SM_API_MSG_NODE_AVAIL_FIELD] == NULL ) + { + DPRINTFE( "Missing node-avail-status field in received message." ); + goto ERROR; + } + + avail_status = sm_api_node_avail_status_value( + (char*) params[SM_API_MSG_NODE_AVAIL_FIELD]); + + if( NULL != _callbacks.node_set ) + { + _callbacks.node_set( node_name, action, admin_state, oper_state, + avail_status, seqno ); + } + } + else if( 0 == strcmp( SM_API_MSG_TYPE_RESTART_SERVICE, + params[SM_API_MSG_TYPE_FIELD] ) ) + { + if( params[SM_API_MSG_ORIGIN_FIELD] == NULL ) + { + DPRINTFE( "Missing origin field in received message." ); + goto ERROR; + } + + if( params[SM_API_MSG_SERVICE_NAME_FIELD] == NULL ) + { + DPRINTFE( "Missing service-name field in received message." ); + goto ERROR; + } + + service_name = (char*) params[SM_API_MSG_SERVICE_NAME_FIELD]; + if ( params[SM_API_MSG_PARAM] != NULL && + 0 == strcmp( SM_API_MSG_SKIP_DEP_CHECK, params[SM_API_MSG_PARAM]) ) + { + DPRINTFI( "Confirm restart-safe request is received." ); + action_flag = SM_SVC_RESTART_NO_DEP; + }else + { + action_flag = 0; + } + + if( NULL != _callbacks.service_restart ) + { + _callbacks.service_restart( service_name, seqno, action_flag); + } + } else { + DPRINTFE( "Unknown/unsupported message-type (%s) received.", + params[SM_API_MSG_TYPE_FIELD] ); + goto ERROR; + } + + g_strfreev( params ); + return; + +ERROR: + g_strfreev( params ); + return; +} +// *************************************************************************** + +// *************************************************************************** +// API - Initialize +// ================ +SmErrorT sm_api_initialize( void ) +{ + int sock; + socklen_t len; + struct sockaddr_un src_addr; + struct sockaddr_un client_addr; + int result; + SmErrorT error; + + memset( &src_addr, 0, sizeof(src_addr) ); + + src_addr.sun_family = AF_UNIX; + snprintf( src_addr.sun_path, sizeof(src_addr.sun_path), + SM_API_MSG_SERVER_ADDRESS ); + + sock = socket( AF_LOCAL, SOCK_DGRAM, 0 ); + if( 0 > sock ) + { + DPRINTFE( "Failed to create socket for sm-api, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + unlink( src_addr.sun_path ); + + len = strlen(src_addr.sun_path) + sizeof(src_addr.sun_family); + + result = bind( sock, (struct sockaddr *) &src_addr, len ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind address (%s) to socket for sm-api, " + "error=%s.", src_addr.sun_path, strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + memset( &client_addr, 0, sizeof(client_addr) ); + + client_addr.sun_family = AF_UNIX; + snprintf( client_addr.sun_path, sizeof(client_addr.sun_path), + SM_API_MSG_CLIENT_ADDRESS ); + len = strlen(client_addr.sun_path) + sizeof(client_addr.sun_family); + + _sm_api_socket = sock; + _sm_api_client_address = client_addr; + _sm_api_client_address_len = len; + + error = sm_selobj_register( _sm_api_socket, sm_api_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// API - Finalize +// ============== +SmErrorT sm_api_finalize( void ) +{ + SmErrorT error; + + memset( &_callbacks, 0, sizeof(_callbacks) ); + + if( -1 < _sm_api_socket ) + { + error = sm_selobj_deregister( _sm_api_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + } + + return( SM_OKAY ); +} +// *************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_api.h b/service-mgmt/sm-1.0.0/src/sm_api.h new file mode 100644 index 00000000..66c38414 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_api.h @@ -0,0 +1,85 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_API_H__ +#define __SM_API_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + SM_NODE_SET_ACTION_UNKNOWN, + SM_NODE_SET_ACTION_LOCK, + SM_NODE_SET_ACTION_UNLOCK, + SM_NODE_SET_ACTION_SWACT, + SM_NODE_SET_ACTION_SWACT_FORCE, + SM_NODE_SET_ACTION_EVENT, + SM_NODE_SET_ACTION_MAX +} SmNodeSetActionT; + +typedef void (*SmApiNodeSetCallbackT) ( char node_name[], + SmNodeSetActionT action, SmNodeAdminStateT admin_state, + SmNodeOperationalStateT oper_state, SmNodeAvailStatusT avail_status, + int seqno ); + +typedef void (*SmApiServiceRestartCallbackT) ( char service_name[], + int seqno, int flag ); + +typedef struct +{ + SmApiNodeSetCallbackT node_set; + SmApiServiceRestartCallbackT service_restart; +} SmApiCallbacksT; + +// **************************************************************************** +// API - Register Callbacks +// ======================== +extern SmErrorT sm_api_register_callbacks( SmApiCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// API - Deregister Callbacks +// ========================== +extern SmErrorT sm_api_deregister_callbacks( SmApiCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// API - Send Node Set +// =================== +extern SmErrorT sm_api_send_node_set( char node_name[], + SmNodeSetActionT action, SmNodeAdminStateT admin_state, + SmNodeOperationalStateT oper_state, SmNodeAvailStatusT avail_status ); +// **************************************************************************** + +// **************************************************************************** +// API - Send Node Set Ack +// ======================= +extern SmErrorT sm_api_send_node_set_ack( char node_name[], + SmNodeSetActionT action, SmNodeAdminStateT admin_state, + SmNodeOperationalStateT oper_state, SmNodeAvailStatusT avail_status, + int seqno ); +// **************************************************************************** + +// *************************************************************************** +// API - Initialize +// ================ +extern SmErrorT sm_api_initialize( void ); +// *************************************************************************** + +// *************************************************************************** +// API - Finalize +// ============== +extern SmErrorT sm_api_finalize( void ); +// *************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_API_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_configuration_table.c b/service-mgmt/sm-1.0.0/src/sm_configuration_table.c new file mode 100644 index 00000000..78aeffb7 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_configuration_table.c @@ -0,0 +1,93 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_configuration_table.h" + +#include +#include +#include + +#include "sm_db_foreach.h" +#include "sm_db_configuration.h" +#include "sm_debug.h" + + +// **************************************************************************** +// count number of records found +// ================================== +static SmErrorT sm_configuration_table_add(void* user_data[], void* record) +{ + int& count = *(int*)user_data[0]; + count ++; + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Configuration Table - Get +// ================================== +SmErrorT sm_configuration_table_get( const char* key, char* buf, unsigned int buf_size ) +{ + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbConfigurationT value; + SmErrorT error; + int count = 0; + void* user_data[1] = {&count}; + unsigned int cx; + + cx = snprintf( db_query, sizeof(db_query), "%s = '%s'", + SM_CONFIGURATION_TABLE_COLUMN_KEY, key ); + + if( sizeof(db_query) <= cx ) + { + DPRINTFE( "Unexpected query too long %s ='%s', length %d", + SM_CONFIGURATION_TABLE_COLUMN_KEY, key, cx + ); + buf[0] = '\0'; + return SM_FAILED; + } + + error = sm_db_foreach( SM_DATABASE_NAME, + SM_CONFIGURATION_TABLE_NAME, db_query, + &value, sm_db_configuration_convert, + sm_configuration_table_add, user_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over configuration in " + "database, error=%s.", sm_error_str( error ) ); + return( error ); + } + + if( 0 != count ) + { + snprintf( buf, buf_size, value.value ); + }else + { + buf[0] = '\0'; + } + + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Configuration Table - Initialize +// ======================================== +SmErrorT sm_configuration_table_initialize( void ) +{ + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Configuration Table - Finalize +// ====================================== +SmErrorT sm_configuration_table_finalize( void ) +{ + return SM_OKAY; +} +// **************************************************************************** + + diff --git a/service-mgmt/sm-1.0.0/src/sm_configuration_table.h b/service-mgmt/sm-1.0.0/src/sm_configuration_table.h new file mode 100644 index 00000000..f8dc0330 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_configuration_table.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_CONFIGURATION_TABLE_H__ +#define __SM_CONFIGURATION_TABLE_H__ + +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Configuration Table - Get +// ================================== +extern SmErrorT sm_configuration_table_get( const char* key, char* buf, unsigned int buf_size ); +// **************************************************************************** + +// **************************************************************************** +// Configuration Table - Initialize +// ======================================== +extern SmErrorT sm_configuration_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Configuration Table - Finalize +// ====================================== +extern SmErrorT sm_configuration_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_CONFIGURATION_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_failover.c b/service-mgmt/sm-1.0.0/src/sm_failover.c new file mode 100644 index 00000000..ddf451ec --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_failover.c @@ -0,0 +1,1541 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_failover.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_service_domain_interface_table.h" +#include "sm_debug.h" +#include "sm_hw.h" +#include "sm_node_utils.h" +#include "sm_db_nodes.h" +#include "sm_timer.h" +#include "sm_service_group_table.h" +#include "sm_node_api.h" +#include "sm_utils.h" +#include "sm_node_fsm.h" +#include "sm_service_domain_scheduler.h" +#include "sm_service_domain_table.h" +#include "sm_service_domain_assignment_table.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_neighbor_fsm.h" +#include "sm_service_domain_member_table.h" +#include "sm_service_domain_interface_fsm.h" +#include "sm_heartbeat_msg.h" +#include "sm_node_swact_monitor.h" +#include "sm_util_types.h" + +typedef enum +{ + SM_FAILOVER_INTERFACE_UNKNOWN, + SM_FAILOVER_INTERFACE_OK, + SM_FAILOVER_INTERFACE_MISSING_HEARTBEAT, + SM_FAILOVER_INTERFACE_DOWN, + SM_FAILOVER_INTERFACE_RECOVERING +}SmFailoverInterfaceStateT; + +typedef enum +{ + SM_FAILOVER_ACTION_NO_ACTION = 0, + SM_FAILOVER_ACTION_DISABLE_STANDBY = 1, + SM_FAILOVER_ACTION_DISABLE = 2, + SM_FAILOVER_ACTION_SWACT = 4, + SM_FAILOVER_ACTION_DEGRADE = 8, + SM_FAILOVER_ACTION_ACTIVATE = 16, + SM_FAILOVER_ACTION_FAIL_NODE = 32, + SM_FAILOVER_ACTION_UNDEFINED = 64 +}SmFailoverActionT; + +#define SM_FAILOVER_STATE_TRANSITION_TIME_IN_MS 2000 +#define SM_FAILOVER_MULTI_FAILURE_WAIT_TIMER_IN_MS 2000 +#define SM_FAILOVER_RECOVERY_INTERVAL_IN_SEC 100 +#define SM_FAILOVER_INTERFACE_STATE_REPORT_INTERVAL_MS 20000 + +typedef enum +{ + SM_FAILOVER_ACTION_RESULT_OK, + SM_FAILOVER_ACTION_RESULT_NO_ACTION, + SM_FAILOVER_ACTION_RESULT_FAILED, +}SmFailoverActionResultT; + +typedef struct +{ + int active_controller_action; + int standby_controller_action; +}SmFailoverActionPairT; + +class SmFailoverInterfaceInfo +{ + private: + SmServiceDomainInterfaceT* interface; + SmFailoverInterfaceStateT state; + struct timespec last_update; + public: + SmFailoverInterfaceInfo() + { + this->interface = NULL; + this->state = SM_FAILOVER_INTERFACE_UNKNOWN; + } + virtual ~SmFailoverInterfaceInfo() + { + } + + void set_interface(SmServiceDomainInterfaceT* interface) + { + this->interface = interface; + clock_gettime( CLOCK_MONOTONIC_RAW, &(this->last_update) ); + } + + SmServiceDomainInterfaceT* get_interface() const + { + return this->interface; + } + + SmFailoverInterfaceStateT get_state() const + { + return this->state; + } + + bool set_state(SmFailoverInterfaceStateT state) + { + if(this->state != state) + { + this->state = state; + clock_gettime( CLOCK_MONOTONIC_RAW, &(this->last_update) ); + return true; + } + return false; + } + + bool state_in_transition() const + { + return (SM_FAILOVER_STATE_TRANSITION_TIME_IN_MS < this->time_since_last_state_change_ms()); + } + + int time_since_last_state_change_ms() const + { + struct timespec now; + int sec, nsec; + clock_gettime( CLOCK_MONOTONIC_RAW, &now ); + sec = now.tv_sec - this->last_update.tv_sec; + nsec = now.tv_nsec - this->last_update.tv_nsec; + return (sec * 1000000000 + nsec) / 1000000; + } +}; + +typedef enum +{ + SM_FAILOVER_INFRA_DOWN = 1, + SM_FAILOVER_MGMT_DOWN = 2, + SM_FAILOVER_OAM_DOWN = 4, + SM_FAILOVER_HEARTBEAT_ALIVE = 8, + SM_FAILOVER_HELLO_MSG_ALIVE = 16, + SM_FAILOVER_PEER_DISABLED = 0x4000, +}SmFailoverCommFaultBitFlagT; + +SmTimerIdT failover_audit_timer_id; +static char _host_name[SM_NODE_NAME_MAX_CHAR]; +static char _peer_name[SM_NODE_NAME_MAX_CHAR]; +static SmHeartbeatMsgIfStateT _peer_if_state = 0; +static SmHeartbeatMsgIfStateT _peer_if_state_at_last_action = 0; +static bool _retry = true; +static bool _recheck = true; + +static int _degraded_flag = 0; + +static SmFailoverInterfaceInfo *_end_of_list = NULL; +static SmFailoverInterfaceInfo _my_if_list[SM_INTERFACE_MAX]; +static unsigned int _total_interfaces; +static SmFailoverInterfaceInfo* _oam_interface_info = NULL; +static SmFailoverInterfaceInfo* _mgmt_interface_info = NULL; +static SmFailoverInterfaceInfo* _infra_interface_info = NULL; +static SmFailoverInterfaceInfo _peer_if_list[SM_INTERFACE_MAX]; +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static SmDbHandleT* _sm_db_handle = NULL; + +static SmNodeScheduleStateT _host_state; +static SmNodeScheduleStateT _host_state_at_last_action; // host state when action was taken last time +static int64_t _node_comm_state = -1; +static bool _to_disable_peer = false; //set flag for failover thread to send http request to mtce to disable peer +static int _prev_if_state_flag = -1; +time_t _last_if_state_ms = 0; +static SmNodeScheduleStateT _prev_host_state= SM_NODE_STATE_UNKNOWN; + +static bool _hello_msg_alive = true; +static SmSystemModeT _system_mode; +static time_t _last_report_ts = 0; +static int _heartbeat_count = 0; + +// std 2+2/2+2+x failover actions +SmFailoverActionPairT action_map_std_infra[16] = +{ + //Active action standby action if_state + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_ACTIVATE}, //0 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //1 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //2 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //3 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_ACTIVATE}, //4 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //5 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //6 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //7 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //8 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //9 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //10 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //11 + {SM_FAILOVER_ACTION_SWACT, SM_FAILOVER_ACTION_DEGRADE}, //12 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //13 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //14 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED} //15 +}; + +SmFailoverActionPairT action_map_std_no_infra[16] = +{ + //Active action standby action if_state + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_ACTIVATE}, //0 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //1 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //2 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //3 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_ACTIVATE}, //4 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //5 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //6 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //7 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //8 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //9 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //10 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //11 + {SM_FAILOVER_ACTION_SWACT, SM_FAILOVER_ACTION_NO_ACTION}, //12 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //13 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //14 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED} //15 +}; + +// cpe duplex failover actions +SmFailoverActionPairT *action_map_cpe_infra = action_map_std_infra; +SmFailoverActionPairT *action_map_cpe_no_infra = action_map_std_no_infra; + +// cpe duplex-direct failover actions +SmFailoverActionPairT action_map_cpe_dc_infra[16] = +{ + //Active action standby action if_state + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //0 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //1 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //2 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //3 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //4 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //5 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //6 + {SM_FAILOVER_ACTION_FAIL_NODE, SM_FAILOVER_ACTION_FAIL_NODE}, //7 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //8 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_NO_ACTION}, //9 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_NO_ACTION}, //10 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_NO_ACTION}, //11 + {SM_FAILOVER_ACTION_SWACT, SM_FAILOVER_ACTION_DEGRADE}, //12 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_NO_ACTION}, //13 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_NO_ACTION}, //14 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED} //15 +}; + +SmFailoverActionPairT action_map_cpe_dc_no_infra[16] = +{ + //Active action standby action if_state + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //0 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //1 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //2 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //3 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_ACTIVATE}, //4 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //5 + {SM_FAILOVER_ACTION_FAIL_NODE, SM_FAILOVER_ACTION_ACTIVATE}, //6 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //7 + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, //8 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //9 + {SM_FAILOVER_ACTION_DISABLE_STANDBY, SM_FAILOVER_ACTION_NO_ACTION}, //10 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //11 + {SM_FAILOVER_ACTION_SWACT, SM_FAILOVER_ACTION_DEGRADE}, //12 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //13 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED}, //14 + {SM_FAILOVER_ACTION_UNDEFINED, SM_FAILOVER_ACTION_UNDEFINED} //15 +}; + +SmFailoverActionPairT action_map_simplex[16] = +{ + //Active action standby action + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION}, + {SM_FAILOVER_ACTION_NO_ACTION, SM_FAILOVER_ACTION_NO_ACTION} +}; +SmFailoverActionPairT *action_maps_no_infra[SM_SYSTEM_MODE_MAX] = {0}; +SmFailoverActionPairT *action_maps_infra[SM_SYSTEM_MODE_MAX] = {0}; + +SmErrorT sm_exec_json_command(const char* cmd, char result_buf[], int result_len); +SmErrorT sm_failover_get_node_oper_state(char* node_name, SmNodeOperationalStateT *state); +void _log_nodes_state(int action); + +// **************************************************************************** +// Failover - interface check +// ================== +static void sm_failover_interface_check( void* user_data[], + SmServiceDomainInterfaceT* interface ) +{ + unsigned int* count = (unsigned int*)user_data[0]; + if (*count < sizeof(_my_if_list)) + { + if( 0 == strcmp(SM_SERVICE_DOMAIN_OAM_INTERFACE, interface->service_domain_interface )) + { + sm_node_utils_get_oam_interface( interface->interface_name ); + _my_if_list[*count].set_interface(interface); + _oam_interface_info = _my_if_list + (*count); + (*count) ++; + }else if( 0 == strcmp(SM_SERVICE_DOMAIN_MGMT_INTERFACE, interface->service_domain_interface )) + { + sm_node_utils_get_mgmt_interface( interface->interface_name ); + _my_if_list[*count].set_interface(interface); + _mgmt_interface_info = _my_if_list + (*count); + (*count) ++; + }else if( 0 == strcmp(SM_SERVICE_DOMAIN_INFRA_INTERFACE, interface->service_domain_interface )) + { + SmErrorT error = sm_node_utils_get_infra_interface(interface->interface_name); + if(SM_OKAY == error) + { + _my_if_list[*count].set_interface(interface); + _infra_interface_info = _my_if_list + (*count); + (*count) ++; + } else if (SM_NOT_FOUND != error ) + { + DPRINTFE( "Failed to look up infrastructure interface, error=%s.", + sm_error_str(error) ); + } + }else + { + DPRINTFE( "Unknown interface %s", interface->interface_name ); + } + } + else + { + DPRINTFE("More domain interfaces than it was expected."); + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - find interface info +// ================== +static SmFailoverInterfaceInfo* find_interface_info( SmFailoverInterfaceT* interface ) +{ + SmServiceDomainInterfaceT* domain_interface = sm_service_domain_interface_table_read( + interface->service_domain, + interface->service_domain_interface + ); + if ( NULL == domain_interface ) + { + DPRINTFE("Unknown interface (%s %s)", interface->service_domain, interface->service_domain_interface); + return NULL; + } + + int64_t if_id = domain_interface->id; + + SmFailoverInterfaceInfo* iter; + for(iter = _my_if_list; iter < _my_if_list + _total_interfaces; iter ++) + { + if(iter->get_interface()->id == if_id) + { + return iter; + } + } + DPRINTFE("Unknown interface id (%u)", if_id); + return NULL; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - lost Hello msg +// ================== +void sm_failover_lost_hello_msg() +{ + mutex_holder holder(&_mutex); + + if(_hello_msg_alive) + { + DPRINTFI( "Neighbor (%s) declared dead.", _peer_name ); + _hello_msg_alive = false; + } +} + +// **************************************************************************** +// Failover - Hello msg restor +// ================== +void sm_failover_hello_msg_restore() +{ + mutex_holder holder(&_mutex); + + SmFailoverInterfaceInfo* iter; + for(iter = _my_if_list; iter < _end_of_list; iter ++) + { + if ( SM_FAILOVER_INTERFACE_OK == iter->get_state() ) + { + _hello_msg_alive = true; + break; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - lost heartbeat +// ================== +void sm_failover_lost_heartbeat( SmFailoverInterfaceT* interface ) +{ + mutex_holder holder(&_mutex); + + SmFailoverInterfaceInfo* if_info = find_interface_info( interface ); + if ( NULL == if_info ) + { + return; + } + + SmFailoverInterfaceStateT state = if_info->get_state(); + if( SM_FAILOVER_INTERFACE_MISSING_HEARTBEAT == state ) + { + return; + } + else if( SM_FAILOVER_INTERFACE_DOWN == state ) + { + return; + } + + if(if_info->set_state(SM_FAILOVER_INTERFACE_MISSING_HEARTBEAT)) + { + DPRINTFI("Interface %s lose heartbeat.", interface->interface_name); + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - heartbeat restore +// ================== +void sm_failover_heartbeat_restore( SmFailoverInterfaceT* interface ) +{ + mutex_holder holder(&_mutex); + + SmFailoverInterfaceInfo* if_info = find_interface_info( interface ); + if ( NULL == if_info ) + { + return; + } + + SmFailoverInterfaceStateT state = if_info->get_state(); + if( SM_FAILOVER_INTERFACE_OK == state ) + { + return; + } + else if( SM_FAILOVER_INTERFACE_DOWN == state ) + { + // need to wait for if up + return; + } + + if(if_info->set_state(SM_FAILOVER_INTERFACE_OK)) + { + DPRINTFI("Interface %s heartbeat is OK.", interface->interface_name); + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - interface down +// ================== +void sm_failover_interface_down( const char* const interface_name ) +{ + mutex_holder holder(&_mutex); + + SmFailoverInterfaceInfo* iter; + int impacted = 0; + for(iter = _my_if_list; iter < _end_of_list; iter ++) + { + SmServiceDomainInterfaceT* interface = iter->get_interface(); + if( 0 == strcmp(interface_name, interface->interface_name) ) + { + impacted ++; + if(iter->set_state(SM_FAILOVER_INTERFACE_DOWN)) + { + DPRINTFI("Domain interface %s is down, due to i/f %s is down.", + interface->service_domain_interface, interface_name); + } + } + } + + if( 0 == impacted ) + { + DPRINTFD("No domain interface is impacted as i/f %s is down.", + interface_name); + } + else + { + DPRINTFI("%d domain interfaces are impacted as i/f %s is down.", + impacted, interface_name); + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - interface up +// ================== +void sm_failover_interface_up( const char* const interface_name ) +{ + mutex_holder holder(&_mutex); + + SmFailoverInterfaceInfo* iter; + int impacted = 0; + for(iter = _my_if_list; iter < _my_if_list + _total_interfaces; iter ++) + { + SmServiceDomainInterfaceT* interface = iter->get_interface(); + if( 0 == strcmp(interface_name, interface->interface_name) ) + { + impacted ++; + if(iter->set_state(SM_FAILOVER_INTERFACE_RECOVERING)) + { + DPRINTFI("Domain interface %s is recovering, as i/f %s is now up.", + interface->service_domain_interface, interface_name); + } + } + } + + if( 0 == impacted ) + { + DPRINTFI("No domain interface is impacted as i/f %s is up.", + interface_name); + } + else + { + DPRINTFI("%d domain interfaces are impacted as i/f %s is up.", + impacted, interface_name); + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - degrade +// ================== +SmErrorT sm_failover_degrade(SmFailoverDegradeSourceT source) +{ + _degraded_flag |= source; + if(0 != _degraded_flag) + { + return sm_utils_indicate_degraded(); + } + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - degraded clear +// ================== +SmErrorT sm_failover_degrade_clear(SmFailoverDegradeSourceT source) +{ + if(_degraded_flag) + { + _degraded_flag &= (~source); + if(0 == _degraded_flag) + { + DPRINTFI("Degrade clear"); + return sm_utils_clear_degraded(); + } + } + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - peer interface state update +// ================== +void sm_failover_if_state_update(const char node_name[], SmHeartbeatMsgIfStateT if_state) +{ + if( 0 == strcmp(node_name, _peer_name) ) + { + mutex_holder holder(&_mutex); + + if( _peer_if_state != if_state ) + { + DPRINTFI("%s I/F state changed %d => %d", node_name, _peer_if_state, if_state); + _peer_if_state = if_state; + } + }else + { + DPRINTFE("If state updated by unknown host %s", node_name); + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - is infra configured +// ================== +bool is_infra_configured() +{ + if (NULL == _infra_interface_info || + _infra_interface_info->get_interface()->service_domain_interface[0] == '\0' ) + { + return false; + } + + return true; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - get interface state +// ================== +int _failover_get_if_state() +{ + SmFailoverInterfaceStateT mgmt_state = _mgmt_interface_info->get_state(); + SmFailoverInterfaceStateT oam_state = _oam_interface_info->get_state(); + SmFailoverInterfaceStateT infra_state; + int if_state_flag = 0; + if ( is_infra_configured() ) + { + infra_state = _infra_interface_info->get_state(); + if( SM_FAILOVER_INTERFACE_OK == infra_state ) + { + if_state_flag |= SM_FAILOVER_HEARTBEAT_ALIVE; + } + else if ( SM_FAILOVER_INTERFACE_DOWN == infra_state ) + { + if_state_flag |= SM_FAILOVER_INFRA_DOWN; + } + } + + if( SM_FAILOVER_INTERFACE_OK == mgmt_state ) + { + if_state_flag |= SM_FAILOVER_HEARTBEAT_ALIVE; + } + else if ( SM_FAILOVER_INTERFACE_DOWN == mgmt_state ) + { + if_state_flag |= SM_FAILOVER_MGMT_DOWN; + } + + if( SM_FAILOVER_INTERFACE_OK == oam_state ) + { + if_state_flag |= SM_FAILOVER_HEARTBEAT_ALIVE; + } + else if ( SM_FAILOVER_INTERFACE_DOWN == oam_state ) + { + if_state_flag |= SM_FAILOVER_OAM_DOWN; + } + + return if_state_flag; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - get interface state +// ================== +SmErrorT sm_failover_if_state_get(SmHeartbeatMsgIfStateT *if_state) +{ + mutex_holder holder(&_mutex); + + int if_state_flag = _failover_get_if_state(); + *if_state = (if_state_flag & 0b0111); //the lower 3 bits i/f state flag + return SM_OKAY; +} +// **************************************************************************** + + +// **************************************************************************** +// Failover - get interface state +// ================== +void service_domain_member_foreach_cb(void* user_data[], SmServiceDomainMemberT* member) +{ + if( 0 == strcmp(member->service_group_aggregate, "controller-aggregate")) + { + SmServiceDomainAssignmentT* assignment = sm_service_domain_assignment_table_read( + member->name, + _host_name, + member->service_group_name + ); + + bool* is_active = (bool*) user_data[0]; + bool* is_standby = (bool*) user_data[1]; + bool* is_init = (bool*) user_data[2]; + bool* is_failed = (bool*) user_data[3]; + if( NULL == assignment ) + { + *is_init = true; + DPRINTFD("Waiting for service assignments being scheduled."); + return; + } + if( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->desired_state ) + { + *is_active = true; + }else if (SM_SERVICE_GROUP_STATE_STANDBY == assignment->desired_state ) + { + *is_standby = true; + }else if ( SM_SERVICE_GROUP_STATE_DISABLED == assignment->desired_state) + { + *is_failed = true; + }else if ( SM_SERVICE_GROUP_STATE_INITIAL == assignment->desired_state ) + { + *is_init = true; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - callback for service domain table loop +// ================== +static void service_domain_table_each_callback(void* user_data[], SmServiceDomainT* domain) +{ + sm_service_domain_member_table_foreach( + domain->name, + user_data, + service_domain_member_foreach_cb); +} +// **************************************************************************** + +// **************************************************************************** +// Failover - get controller state +// ================== +SmNodeScheduleStateT get_controller_state() +{ + SmNodeScheduleStateT state = SM_NODE_STATE_UNKNOWN; + bool is_active = false; + bool is_standby = false; + bool is_init = false; + bool is_failed = false; + void* user_data[] = {(void*) &is_active, (void*) &is_standby, (void*) &is_init, (void*) &is_failed}; + sm_service_domain_table_foreach( user_data, service_domain_table_each_callback); + if( is_init ) + { + state = SM_NODE_STATE_INIT; + } + else if ( is_standby ) + { + state = SM_NODE_STATE_STANDBY; + } + else if ( is_active ) + { + state = SM_NODE_STATE_ACTIVE; + } + return state; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - is active controller +// ================== +bool is_active_controller() +{ + return SM_NODE_STATE_ACTIVE == _host_state; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - interface is in transit state +// ================== +bool sm_failover_if_transit_state(SmFailoverInterfaceInfo* if_info) +{ + SmFailoverInterfaceStateT if_state = if_info->get_state(); + if( SM_FAILOVER_INTERFACE_RECOVERING == if_state ) + { + const SmServiceDomainInterfaceT* interface = if_info->get_interface(); + if ( if_info->state_in_transition() ) + { + DPRINTFI( "If %s is reconvering, wait for either trun OK or missing heartbeat", + interface->service_domain_interface); + return true; + }else + { + if_info->set_state(SM_FAILOVER_INTERFACE_MISSING_HEARTBEAT); + DPRINTFI( "If %s missing heartbeat", interface->service_domain_interface); + return false; + } + } + return false; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - swact controller +// ================== +SmFailoverActionResultT sm_failover_swact() +{ + SmUuidT request_uuid; + sm_uuid_create( request_uuid ); + DPRINTFI("Uncontrolled swact start"); + + SmErrorT error = sm_node_api_swact(_host_name, true); + if (SM_OKAY == error) + { + return SM_FAILOVER_ACTION_RESULT_OK; + } + return SM_FAILOVER_ACTION_RESULT_FAILED; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - fail self +// ================== +SmFailoverActionResultT sm_failover_fail_self() +{ + DPRINTFI("To disable %s", _host_name); + SmErrorT error = sm_node_fsm_event_handler( + _host_name, SM_NODE_EVENT_DISABLED, NULL, "Host is isolated" ); + if( SM_OKAY != error ) + { + DPRINTFE("Failed to disable %s, error: %s", _host_name, sm_error_str(error)); + return SM_FAILOVER_ACTION_RESULT_FAILED; + } + + sm_node_utils_set_unhealthy(); + + error = sm_node_api_fail_node( _host_name ); + if (SM_OKAY == error ) + { + return SM_FAILOVER_ACTION_RESULT_OK; + } + else + { + DPRINTFE("Failed to set %s failed, error %s.", _host_name, sm_error_str(error)); + return SM_FAILOVER_ACTION_RESULT_FAILED; + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - disable node +// ================== +SmFailoverActionResultT sm_failover_disable_node(char* node_name) +{ + DPRINTFI("To disable %s", node_name); + + SmErrorT error; + error = sm_node_fsm_event_handler( + node_name, SM_NODE_EVENT_DISABLED, NULL, "Host is isolated" ); + + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disable node %s, error=%s.", + node_name, sm_error_str( error ) ); + return SM_FAILOVER_ACTION_RESULT_FAILED; + } + _to_disable_peer = true; + return SM_FAILOVER_ACTION_RESULT_OK; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - active self callback +// ======================= +static void active_self_callback(void* user_data[], SmServiceDomainT* domain) +{ + char reason_text[] = "Neighbor dead"; + + sm_service_domain_neighbor_fsm_event_handler(_peer_name, domain->name, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DOWN, NULL, reason_text); + sm_service_domain_utils_service_domain_active_self(domain->name); +} +// **************************************************************************** + +// **************************************************************************** +// Failover - active self +// ======================= +SmFailoverActionResultT sm_failover_activate_self() +{ + DPRINTFI("Uncontrolled swact start (active local only)"); + SmNodeSwactMonitor::SwactStart(SM_NODE_STATE_ACTIVE); + sm_service_domain_table_foreach( NULL, active_self_callback); + + return SM_FAILOVER_ACTION_RESULT_OK; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - get node +// ======================= +SmErrorT sm_failover_get_node(char* node_name, SmDbNodeT& node) +{ + char query[SM_DB_QUERY_STATEMENT_MAX_CHAR] = {0}; + snprintf(query, sizeof(query), "%s == '%s'", SM_NODES_TABLE_COLUMN_NAME, node_name); + SmErrorT error = sm_db_nodes_query(_sm_db_handle, query, &node); + return error; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - get node operational state +// ======================= +SmErrorT sm_failover_get_node_oper_state(char* node_name, SmNodeOperationalStateT *state) +{ + SmDbNodeT node; + SmErrorT error = sm_failover_get_node(node_name, node); + if( SM_OKAY == error ) + { + *state = node.oper_state; + } + else if( SM_NOT_FOUND != error ) + { + DPRINTFE("Failed to read node table. %s", sm_error_str(error)); + } + + return error; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - is node enabled +// ======================= +bool _is_node_enabled(char* node_name) +{ + SmNodeOperationalStateT state; + if (SM_OKAY == sm_failover_get_node_oper_state(node_name, &state)) + { + return state == SM_NODE_OPERATIONAL_STATE_ENABLED; + } + return false; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - is peer enabled +// ======================= +bool peer_controller_enabled() +{ + return _is_node_enabled(_peer_name); +} +// **************************************************************************** + +// **************************************************************************** +// Failover - is this controller enabled +// ======================= +bool this_controller_enabled() +{ + return _is_node_enabled(_host_name); +} +// **************************************************************************** + +// **************************************************************************** +// Failover - get node admin state +// ======================= +SmErrorT sm_failover_get_node_admin_state(char* node_name, SmNodeAdminStateT *admin_state) +{ + char query[SM_DB_QUERY_STATEMENT_MAX_CHAR] = {0}; + SmDbNodeT node; + snprintf(query, sizeof(query), "%s == '%s'", SM_NODES_TABLE_COLUMN_NAME, node_name); + SmErrorT error = sm_db_nodes_query(_sm_db_handle, query, &node); + if( SM_OKAY == error ) + { + *admin_state = node.admin_state; + } + else if( SM_NOT_FOUND != error ) + { + DPRINTFE("Failed to read node table. %s", sm_error_str(error)); + } + + return error; + +} +// **************************************************************************** + +// **************************************************************************** +// Failover - is node unlocked +// ======================= +bool _is_node_unlocked(char* node_name) +{ + SmNodeAdminStateT admin_state; + if (SM_OKAY == sm_failover_get_node_admin_state(node_name, &admin_state)) + { + return admin_state == SM_NODE_ADMIN_STATE_UNLOCKED; + } + return false; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - is peer unlocked +// ======================= +bool peer_controller_unlocked() +{ + return _is_node_unlocked(_peer_name); +} +// **************************************************************************** + +// **************************************************************************** +// Failover - is this controller unlocked +// ======================= +bool this_controller_unlocked() +{ + return _is_node_unlocked(_host_name); +} +// **************************************************************************** + +// **************************************************************************** +// Failover - audit +// ======================= +void sm_failover_audit() +{ + mutex_holder holder(&_mutex); + + timespec now; + time_t now_ms; + clock_gettime( CLOCK_MONOTONIC_RAW, &now ); + now_ms = now.tv_sec * 1000 + now.tv_nsec / 1000000; + _host_state = get_controller_state(); + if( SM_NODE_STATE_INIT == _host_state || + SM_NODE_STATE_UNKNOWN == _host_state ) + { + if ( _prev_host_state != _host_state ) + { + DPRINTFD("Wait for scheduler to decided my role. host state = %d", _host_state); + _prev_host_state = _host_state; + } + return; + } + + if ( _prev_host_state != _host_state ) + { + DPRINTFI("host state is %d", _host_state); + _prev_host_state = _host_state; + } + + bool is_active = is_active_controller(); + bool in_transition = false; + bool infra_configured = is_infra_configured(); + in_transition = in_transition && + sm_failover_if_transit_state(_mgmt_interface_info); + in_transition = in_transition && + sm_failover_if_transit_state(_oam_interface_info); + if( infra_configured ) + { + in_transition = in_transition && + sm_failover_if_transit_state(_infra_interface_info); + } + + if(in_transition) + { + //if state in transition, wait for next audit + return; + } + + SmFailoverActionPairT* actions; + int action; + + SmFailoverActionPairT *action_map = NULL; + + SmFailoverActionPairT **action_map_mode_list = action_maps_no_infra; + if(infra_configured) + { + action_map_mode_list = action_maps_infra; + } + + action_map = action_map_mode_list[(int) _system_mode]; + + int if_state_flag = _failover_get_if_state(); + if(if_state_flag & SM_FAILOVER_HEARTBEAT_ALIVE) + { + _heartbeat_count ++; + } + else + { + _heartbeat_count = 0; + } + if( _prev_if_state_flag != if_state_flag) + { + _last_report_ts = now_ms; + DPRINTFI("Interface state flag %d", if_state_flag); + + if( SM_FAILOVER_MULTI_FAILURE_WAIT_TIMER_IN_MS > now_ms - _last_if_state_ms ) + { + DPRINTFD("interface state just changed. wait %d ms for concurrent changes", + SM_FAILOVER_MULTI_FAILURE_WAIT_TIMER_IN_MS); + return; + }else + { + _last_if_state_ms = now_ms; + _prev_if_state_flag = if_state_flag; + } + } + + if(now_ms - _last_report_ts > SM_FAILOVER_INTERFACE_STATE_REPORT_INTERVAL_MS) + { + _last_report_ts = now_ms; + DPRINTFD("Interface state flag %d", if_state_flag); + } + + if(!peer_controller_enabled()) + { + _recheck = true; + if( 1 != _heartbeat_count ) + { + return; + } + } + if (!this_controller_enabled() || !this_controller_unlocked()) + { + _recheck = true; + DPRINTFD("This controller isn't unlocked, no action is taken."); + return; + } + + int64_t curr_node_state = if_state_flag; + + if( _hello_msg_alive ) + { + curr_node_state = curr_node_state | SM_FAILOVER_HELLO_MSG_ALIVE; + } + + if( !_retry && !_recheck && + ( _node_comm_state == curr_node_state && + _host_state == _host_state_at_last_action && + _peer_if_state == _peer_if_state_at_last_action )) + { + return; + } + + _recheck = false; + _retry = false; + + _node_comm_state = curr_node_state; + _host_state_at_last_action = _host_state; + _peer_if_state_at_last_action = _peer_if_state; + + actions = &(action_map[if_state_flag & 0xf]); + if(is_active) + { + action = actions->active_controller_action; + if(if_state_flag & SM_FAILOVER_OAM_DOWN) + { + if(_peer_if_state & SM_FAILOVER_OAM_DOWN) + { + DPRINTFI("No swact, oam down on both controllers"); + action &= (~SM_FAILOVER_ACTION_SWACT); + } + else + { + DPRINTFI("Swact to %s, it's oam is UP", _peer_name); + action &= SM_FAILOVER_ACTION_SWACT; + } + } + } + else + { + action = actions->standby_controller_action; + } + + _log_nodes_state(action); + + DPRINTFI("Action to take %d", action); + if (action & SM_FAILOVER_ACTION_ACTIVATE) + { + DPRINTFI("ACTIVE"); + _retry |= ( SM_FAILOVER_ACTION_RESULT_OK != sm_failover_activate_self()); + } + + if(action & SM_FAILOVER_ACTION_DEGRADE) { + DPRINTFI("DEGRADE"); + _retry |= ( SM_OKAY != sm_failover_degrade(SM_FAILOVER_DEGRADE_SOURCE_IF_DOWN) ); + } + else + { + _retry |= ( SM_OKAY != sm_failover_degrade_clear(SM_FAILOVER_DEGRADE_SOURCE_IF_DOWN) ); + } + + if(action & SM_FAILOVER_ACTION_SWACT) + { + DPRINTFI("SWACT"); + _retry |= ( SM_FAILOVER_ACTION_RESULT_OK != sm_failover_swact() ); + } + + if(action & SM_FAILOVER_ACTION_DISABLE) + { + DPRINTFI("DISABLE"); + _retry |= (SM_FAILOVER_ACTION_RESULT_OK != sm_failover_disable_node(_host_name)); + } + + if(action & SM_FAILOVER_ACTION_FAIL_NODE) + { + DPRINTFI("FAIL SELF"); + _retry |= (SM_FAILOVER_ACTION_RESULT_OK != sm_failover_fail_self()); + } + + if(action & SM_FAILOVER_ACTION_DISABLE_STANDBY) { + DPRINTFI("DISABLE STANDBY"); + _retry |= (SM_FAILOVER_ACTION_RESULT_OK != sm_failover_disable_node(_peer_name)); + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - audit timeout callback +// ======================= +static bool sm_failover_audit_timeout(SmTimerIdT timer_id, + int64_t user_data ) +{ + sm_failover_audit(); + return true; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - exec mtce command +// ======================= +SmErrorT sm_exec_mtce_command(const char cmd[], char result_buf[], int result_len) +{ + FILE* fp; + DPRINTFD("Executing command:\n%s\n", cmd); + fp = popen(cmd, "r"); + if(NULL == fp) + { + DPRINTFE("Failed to run command \n%s\n", cmd); + return SM_FAILED; + } + + SmErrorT result = SM_FAILED; + if( NULL != fgets(result_buf, result_len, fp) ) + { + struct json_object *raw_obj = json_tokener_parse( result_buf ); + if( !raw_obj ) + { + DPRINTFE("Mtce api returns invalid result. [%s]", result_buf); + result = SM_FAILED; + } + else + { + json_object_object_foreach(raw_obj, key, val) + { + const char status_key[] = "status"; + if( 0 == strncmp(status_key, key, sizeof(status_key)) ) + { + const char* val_str = json_object_get_string(val); + const char pass_val[] = "pass"; + if( 0 == strncmp(pass_val, val_str, sizeof(pass_val))) + { + DPRINTFI("Mtce api completed successfully."); + result = SM_OKAY; + } + } + } + if(result != SM_OKAY) + { + const char* json_string = json_object_get_string(raw_obj); + DPRINTFE("Mtce api return error. [%s]", json_string); + } + } + } + else + { + DPRINTFE("Mtce api not available, will retry in next cycle."); + } + fclose(fp); + return result; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - log current state +// ======================= +void _log_nodes_state(int action) +{ + SmDbNodeT host, peer; + SmErrorT error = sm_failover_get_node(_host_name, host); + SmErrorT error2 = sm_failover_get_node(_peer_name, peer); + if (SM_OKAY == error && SM_OKAY == error2) + { + DPRINTFI("%s %s-%s-%s, %s %s-%s-%s", + _host_name, + sm_node_admin_state_str(host.admin_state), + sm_node_oper_state_str(host.oper_state), + sm_node_avail_status_str(host.avail_status), + _peer_name, + sm_node_admin_state_str(peer.admin_state), + sm_node_oper_state_str(peer.oper_state), + sm_node_avail_status_str(peer.avail_status) + ); + } + DPRINTFI("Host state %d, I/F state %d, peer I/F state %d, action %d", + _node_comm_state, + _peer_if_state, + _host_state, + action + ); +} +// **************************************************************************** + +// **************************************************************************** +// Failover - failover action +// ======================= +SmErrorT sm_failover_action() +{ + //This runs in failover thread for long action + // so main thread and hello msg are not blocked + bool *flag = NULL; + char result_buf[1024]; + char cmd_buf[1024]; + bool to_disable_peer; + { + mutex_holder holder(&_mutex); + + to_disable_peer = _to_disable_peer; + } + + if ( to_disable_peer ) + { + flag = &_to_disable_peer; + snprintf(cmd_buf, sizeof(cmd_buf), "curl --header \"Content-Type:application/json\" " + "--header \"Accept: application/json\" --header \"User-Agent: sm/1.0\" " + "--data '{\"action\": \"event\", \"hostname\":\"%s\", \"operational\": \"disabled\", \"availability\": \"failed\"}' " + "\"http://localhost:2112/v1/hosts/%s/\"", _peer_name, _peer_name); + + SmErrorT error = sm_exec_mtce_command(cmd_buf, result_buf, sizeof(result_buf)); + if (SM_OKAY != error ) + { + return SM_FAILED; + } + } + + if( flag ) + { + mutex_holder holder(&_mutex); + * flag = false; + } + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - Initialize +// ====================== +SmErrorT sm_failover_initialize( void ) +{ + void* user_data[1] = {&_total_interfaces}; + bool enabled; + SmErrorT error; + _system_mode = sm_node_utils_get_system_mode(); + DPRINTFI("System mode %s", sm_system_mode_str(_system_mode)); + + action_maps_no_infra[SM_SYSTEM_MODE_STANDARD] = action_map_std_no_infra; + action_maps_no_infra[SM_SYSTEM_MODE_CPE_DUPLEX] = action_map_cpe_no_infra; + action_maps_no_infra[SM_SYSTEM_MODE_CPE_DUPLEX_DC] = action_map_cpe_dc_no_infra; + action_maps_no_infra[SM_SYSTEM_MODE_CPE_SIMPLEX] = action_map_simplex; + + action_maps_infra[SM_SYSTEM_MODE_STANDARD] = action_map_std_infra; + action_maps_infra[SM_SYSTEM_MODE_CPE_DUPLEX] = action_map_cpe_infra; + action_maps_infra[SM_SYSTEM_MODE_CPE_DUPLEX_DC] = action_map_cpe_dc_infra; + action_maps_infra[SM_SYSTEM_MODE_CPE_SIMPLEX] = action_map_simplex; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_node_utils_get_hostname( _host_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return error; + } + + if( 0 == strcmp( SM_NODE_CONTROLLER_0_NAME, _host_name ) ) + { + snprintf( _peer_name, sizeof(_peer_name), "%s", SM_NODE_CONTROLLER_1_NAME ); + }else if ( 0 == strcmp( SM_NODE_CONTROLLER_1_NAME, _host_name ) ) + { + snprintf( _peer_name, sizeof(_peer_name), "%s", SM_NODE_CONTROLLER_0_NAME ); + }else + { + DPRINTFE( "Unknown host name (not one of [%s, %s]", + SM_NODE_CONTROLLER_0_NAME, SM_NODE_CONTROLLER_1_NAME); + return SM_FAILED; + } + + _total_interfaces = 0; + sm_service_domain_interface_table_foreach( + user_data, + sm_failover_interface_check + ); + + if ( _oam_interface_info == NULL || _mgmt_interface_info == NULL ) + { + DPRINTFE( "%s and %s must be configured.", + SM_SERVICE_DOMAIN_MGMT_INTERFACE, SM_SERVICE_DOMAIN_OAM_INTERFACE ); + return SM_FAILED; + } + + _end_of_list = _my_if_list + _total_interfaces; + DPRINTFI("Total domain interfaces %d", _total_interfaces); + SmFailoverInterfaceInfo *iter; + int i = 0; + for( iter = _my_if_list; iter < _end_of_list; iter ++) + { + const SmServiceDomainInterfaceT* interface = iter->get_interface(); + + DPRINTFI( "interface[%d]: %s %s", i, interface->service_domain_interface, interface->interface_name ); + i ++; + } + + for( iter = _my_if_list; iter < _end_of_list; iter ++) + { + const SmServiceDomainInterfaceT* interface = iter->get_interface(); + error = sm_hw_get_if_state(interface->interface_name, &enabled); + if(SM_OKAY != error) + { + DPRINTFE("Couldn't get interface (%s) state. ", interface->interface_name); + } + else + { + if(enabled) + { + if(iter->set_state(SM_FAILOVER_INTERFACE_OK)) + { + DPRINTFI("Interface %d [%s, %s] is UP", + interface->id, + interface->service_domain_interface, + sm_path_type_str(interface->path_type)); + } + } + else + { + if(iter->set_state(SM_FAILOVER_INTERFACE_DOWN)) + { + DPRINTFE("Interface %d [%s, %s] is DOWN", + interface->id, + interface->service_domain_interface, + sm_path_type_str(interface->path_type)); + } + } + } + } + + error = sm_timer_register( "failover audit", 1000, + sm_failover_audit_timeout, + 0, &failover_audit_timer_id ); + + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Failover - Finalize +// ==================== +SmErrorT sm_failover_finalize( void ) +{ + _total_interfaces = 0; + + SmErrorT error; + sm_timer_deregister( failover_audit_timer_id ); + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +/* code below is for debugging only. There is no real feature/function +*******************************************************************************/ +#define MAX_MAPPING_STR_LEN 40 +typedef struct +{ + int value; + char str[MAX_MAPPING_STR_LEN]; +} KeyStringMapT; + +static const char* get_map_str( KeyStringMapT mappings[], + unsigned int num_mappings, int value ) +{ + unsigned int map_i; + for( map_i=0; num_mappings > map_i; ++map_i ) + { + if( value == mappings[map_i].value ) + { + return( &(mappings[map_i].str[0]) ); + } + } + + return( "???" ); +} + +void dump_host_state(FILE* fp) +{ + const char* state = sm_node_schedule_state_str(_host_state); + fprintf(fp, " host state: %s\n", state); +} + +static KeyStringMapT if_state_map[] = { + {SM_FAILOVER_INTERFACE_UNKNOWN, "Unknown"}, + {SM_NODE_STATE_ACTIVE, "Active"}, + {SM_FAILOVER_INTERFACE_MISSING_HEARTBEAT, "Missing heartbeat"}, + {SM_FAILOVER_INTERFACE_DOWN, "Down"}, + {SM_FAILOVER_INTERFACE_RECOVERING, "Recovering" } +}; + +void dump_if_state(FILE* fp, SmFailoverInterfaceInfo* interface, const char* if_name ) +{ + const char* state; + if(interface) + { + state = get_map_str( if_state_map, + sizeof(if_state_map) / sizeof(KeyStringMapT), + interface->get_state() ); + } + else + { + state = "Not configured"; + } + fprintf(fp, " %s Interface: %s\n", if_name, state); +} + +void dump_interfaces_state(FILE* fp) +{ + dump_if_state(fp, _oam_interface_info, " OAM"); + dump_if_state(fp, _mgmt_interface_info, " MGMT"); + dump_if_state(fp, _infra_interface_info, "INFRA"); +} + +void dump_peer_if_state(FILE* fp) +{ + fprintf(fp, " Peer Interface state: %d\n", _peer_if_state); +} + +// **************************************************************************** +// Failover - dump state +// ====================== +void sm_failover_dump_state(FILE* fp) +{ + fprintf( fp, "Failover \n\n" ); + dump_host_state(fp); + dump_interfaces_state(fp); + dump_peer_if_state(fp); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_failover.h b/service-mgmt/sm-1.0.0/src/sm_failover.h new file mode 100644 index 00000000..0ba1f7ab --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_failover.h @@ -0,0 +1,143 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_FAILOVER_H__ +#define __SM_FAILOVER_H__ +#include +#include "sm_types.h" +#include "sm_service_domain_interface_table.h" +#include "sm_db_nodes.h" +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + char* service_domain; + char* service_domain_interface; + char* interface_name; + SmInterfaceStateT interface_state; +}SmFailoverInterfaceT; + + +typedef enum +{ + SM_FAILOVER_DEGRADE_SOURCE_SERVICE_GROUP = 1, + SM_FAILOVER_DEGRADE_SOURCE_IF_DOWN = 2 +}SmFailoverDegradeSourceT; + +// **************************************************************************** +// Failover - check +// ================== +extern void sm_failover_check(); +// **************************************************************************** + +// **************************************************************************** +// Failover - audit +// ================== +extern void sm_failover_audit(bool recheck); +// **************************************************************************** + +// **************************************************************************** +// Failover - lost hello msg +// ================== +extern void sm_failover_lost_hello_msg(); +// **************************************************************************** + + +// **************************************************************************** +// Failover - hello msg restore +// ================== +extern void sm_failover_hello_msg_restore(); +// **************************************************************************** + +// **************************************************************************** +// Failover - lost heartbeat +// ================== +extern void sm_failover_lost_heartbeat( SmFailoverInterfaceT* interface ); +// **************************************************************************** + + +// **************************************************************************** +// Failover - heartbeat restore +// ================== +extern void sm_failover_heartbeat_restore( SmFailoverInterfaceT* interface ); +// **************************************************************************** + + +// **************************************************************************** +// Failover - interface down +// ================== +extern void sm_failover_interface_down( const char* const interface_name ); +// **************************************************************************** + + +// **************************************************************************** +// Failover - interface down +// ================== +extern void sm_failover_interface_up( const char* const interface_name ); +// **************************************************************************** + +// **************************************************************************** +// Failover - interface state update for peer +extern void sm_failover_if_state_update(const char node_name[], + SmHeartbeatMsgIfStateT if_state); +// **************************************************************************** + +// **************************************************************************** +// Failover - get local interface state +extern SmErrorT sm_failover_if_state_get(SmHeartbeatMsgIfStateT*); +// **************************************************************************** + +// **************************************************************************** +// Failover - action +// ================== +SmErrorT sm_failover_action( void ); +// **************************************************************************** + +// **************************************************************************** +// Failover - degrade +// ================== +SmErrorT sm_failover_degrade(SmFailoverDegradeSourceT source); +// **************************************************************************** + +// **************************************************************************** +// Failover - degraded clear +// ================== +SmErrorT sm_failover_degrade_clear(SmFailoverDegradeSourceT source); +// **************************************************************************** + +// **************************************************************************** +// Failover - get node +// ================== +SmErrorT sm_failover_get_node(char* node_name, SmDbNodeT& node); +// **************************************************************************** + +// **************************************************************************** +// Failover - dump state +// ================== +extern void sm_failover_dump_state(FILE* fp); +// **************************************************************************** + +// **************************************************************************** +// Failover - Initialize +// ====================== +extern SmErrorT sm_failover_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Failover - Finalize +// ==================== +extern SmErrorT sm_failover_finalize( void ); +// **************************************************************************** + +SmNodeScheduleStateT get_controller_state(); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/service-mgmt/sm-1.0.0/src/sm_failover_thread.c b/service-mgmt/sm-1.0.0/src/sm_failover_thread.c new file mode 100644 index 00000000..69715fd6 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_failover_thread.c @@ -0,0 +1,244 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_failover_thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_failover.h" +#include "sm_types.h" +#include "sm_time.h" +#include "sm_debug.h" +#include "sm_trap.h" +#include "sm_selobj.h" +#include "sm_thread_health.h" +#include "sm_hw.h" +#include "sm_timer.h" + +#define SM_FAILOVER_THREAD_TICK_INTERVAL_IN_MS 1000 + +static const char sm_failover_thread_name[] = "sm_failover"; +static const int sm_failover_tick_interval_in_ms = 1000; + +static sig_atomic_t _stay_on = 1; +static bool _thread_created = false; +static pthread_t _failover_thread; + +static void sm_failover_interface_change_callback( + SmHwInterfaceChangeDataT* if_change ) +{ + switch ( if_change->interface_state ) + { + case SM_INTERFACE_STATE_DISABLED: + DPRINTFI("Interface %s is down", if_change->interface_name); + sm_failover_interface_down(if_change->interface_name); + break; + case SM_INTERFACE_STATE_ENABLED: + DPRINTFI("Interface %s is up", if_change->interface_name); + sm_failover_interface_up(if_change->interface_name); + break; + default: + DPRINTFI("Interface %s state changed to %d", + if_change->interface_name, if_change->interface_state); + break; + } +} + +// **************************************************************************** +// Failover Thread - Initialize Thread +// ============================================ +SmErrorT sm_failover_thread_initialize_thread( void ) +{ + SmErrorT error; + SmHwCallbacksT callbacks; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_initialize( SM_FAILOVER_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + memset( &callbacks, 0, sizeof(callbacks) ); + callbacks.interface_change = sm_failover_interface_change_callback; + error = sm_hw_initialize( &callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize hardware module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + + +// **************************************************************************** +// Failover Thread - Finalize Thread +// ========================================== +SmErrorT sm_failover_thread_finalize_thread( void ) +{ + SmErrorT error; + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize timer module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + + +// **************************************************************************** +// Failover Thread - Main +// =============================== +static void* sm_failover_thread_main( void* arguments ) +{ + SmErrorT error; + + pthread_setname_np( pthread_self(), sm_failover_thread_name ); + sm_debug_set_thread_info(); + sm_trap_set_thread_info(); + + DPRINTFI( "Starting" ); + + error = sm_failover_thread_initialize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failover thread initialize failed, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + DPRINTFI( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( sm_failover_tick_interval_in_ms ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + + sm_failover_action(); + } + + DPRINTFI( "Shutting down." ); + + error = sm_failover_thread_finalize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failover finalize thread failed, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Failover Thread - Start +// ================================ +SmErrorT sm_failover_thread_start( void ) +{ + int result; + + _stay_on = 1; + _thread_created = false; + + result = pthread_create( &_failover_thread, NULL, + sm_failover_thread_main, NULL ); + if( 0 != result ) + { + DPRINTFE( "Failed to start failover thread, error=%s.", + strerror(result) ); + return( SM_FAILED ); + } + + _thread_created = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Failover Thread - Stop +// =============================== +SmErrorT sm_failover_thread_stop( void ) +{ + _stay_on = 0; + + if( _thread_created ) + { + long ms_expired; + SmTimeT time_prev; + int result; + + sm_time_get( &time_prev ); + + while( true ) + { + result = pthread_tryjoin_np( _failover_thread, NULL ); + if(( 0 != result )&&( EBUSY != result )) + { + if(( ESRCH != result )&&( EINVAL != result )) + { + DPRINTFE( "Failed to wait for failover thread " + "exit, sending kill signal, error=%s.", + strerror(result) ); + pthread_kill( _failover_thread, SIGKILL ); + } + break; + } + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( 12000 <= ms_expired ) + { + DPRINTFE( "Failed to stop failover thread, sending " + "kill signal." ); + pthread_kill( _failover_thread, SIGKILL ); + break; + } + + usleep( 250000 ); // 250 milliseconds. + } + } + + _thread_created = false; + + return( SM_OKAY ); +} +// **************************************************************************** \ No newline at end of file diff --git a/service-mgmt/sm-1.0.0/src/sm_failover_thread.h b/service-mgmt/sm-1.0.0/src/sm_failover_thread.h new file mode 100644 index 00000000..6bf5b457 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_failover_thread.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_FAILOVER_THREAD_H__ +#define __SM_FAILOVER_THREAD_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +// **************************************************************************** +// Failover Thread - Start +// ================================ +extern SmErrorT sm_failover_thread_start( void ); +// **************************************************************************** + +// **************************************************************************** +// Failover Thread - Stop +// =============================== +extern SmErrorT sm_failover_thread_stop( void ); +// **************************************************************************** + + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/service-mgmt/sm-1.0.0/src/sm_heartbeat.c b/service-mgmt/sm-1.0.0/src/sm_heartbeat.c new file mode 100644 index 00000000..0deea670 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_heartbeat.c @@ -0,0 +1,137 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_heartbeat.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_heartbeat_thread.h" + +// **************************************************************************** +// Heartbeat - Enable +// ================== +void sm_heartbeat_enable( void ) +{ + sm_heartbeat_thread_enable(); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Disable +// =================== +void sm_heartbeat_disable( void ) +{ + sm_heartbeat_thread_disable(); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Add Interface +// ========================= +SmErrorT sm_heartbeat_add_interface( SmServiceDomainInterfaceT* interface ) +{ + if ( NULL == interface ) + { + DPRINTFE( "Domain interface is NULL" ); + return SM_FAILED; + } + + return( sm_heartbeat_thread_add_interface( *interface ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Delete Interface +// ============================ +SmErrorT sm_heartbeat_delete_interface( SmServiceDomainInterfaceT* interface ) +{ + return( sm_heartbeat_thread_delete_interface( interface->id ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Add Peer Interface +// ============================== +SmErrorT sm_heartbeat_add_peer_interface( int64_t id, char interface_name[], + SmNetworkAddressT* network_address, int network_port, int dead_interval ) +{ + return( sm_heartbeat_thread_add_peer_interface( id, interface_name, + network_address, network_port, dead_interval ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Delete Peer Interface +// ================================= +SmErrorT sm_heartbeat_delete_peer_interface( char interface_name[], + SmNetworkAddressT* network_address, int network_port ) +{ + return( sm_heartbeat_thread_delete_peer_interface( interface_name, + network_address, network_port ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Peer Alive In Period +// ================================ +bool sm_heartbeat_peer_alive_in_period( char node_name[], + unsigned int period_in_ms ) +{ + return( sm_heartbeat_thread_peer_alive_in_period( node_name, + period_in_ms ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Initialize +// ====================== +SmErrorT sm_heartbeat_initialize( void ) +{ + SmErrorT error; + + error = sm_heartbeat_thread_start(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start heartbeat thread, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Finalize +// ==================== +SmErrorT sm_heartbeat_finalize( void ) +{ + SmErrorT error; + + error = sm_heartbeat_thread_stop(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop heartbeat thread, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_heartbeat.h b/service-mgmt/sm-1.0.0/src/sm_heartbeat.h new file mode 100644 index 00000000..3fec9b93 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_heartbeat.h @@ -0,0 +1,82 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_HEARTBEAT_H__ +#define __SM_HEARTBEAT_H__ + +#include + +#include "sm_types.h" +#include "sm_service_domain_interface_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Heartbeat - Enable +// ================== +extern void sm_heartbeat_enable( void ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Disable +// =================== +extern void sm_heartbeat_disable( void ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Add Interface +// ========================= +extern SmErrorT sm_heartbeat_add_interface( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Delete Interface +// ============================ +extern SmErrorT sm_heartbeat_delete_interface( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Add Peer Interface +// ============================== +extern SmErrorT sm_heartbeat_add_peer_interface( int64_t id, + char interface_name[], SmNetworkAddressT* network_address, + int network_port, int dead_interval ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Delete Peer Interface +// ================================= +extern SmErrorT sm_heartbeat_delete_peer_interface( char interface_name[], + SmNetworkAddressT* network_address, int network_port ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Peer Alive In Period +// ================================ +extern bool sm_heartbeat_peer_alive_in_period( char node_name[], + unsigned int period_in_ms ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Initialize +// ====================== +extern SmErrorT sm_heartbeat_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat - Finalize +// ==================== +extern SmErrorT sm_heartbeat_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_HEARTBEAT_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.c b/service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.c new file mode 100644 index 00000000..76129dad --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.c @@ -0,0 +1,1333 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_heartbeat_msg.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_selobj.h" +#include "sm_hw.h" +#include "sm_sha512.h" +#include "sm_failover.h" + +#define SM_HEARTBEAT_MSG_MAX_SIZE 128 +#define SM_HEARTBEAT_MSG_BUFFER_MAX_SIZE 512 + +typedef enum +{ + SM_HEARTBEAT_MSG_TYPE_UNKNOWN, + SM_HEARTBEAT_MSG_TYPE_ALIVE, +} SmHeartbeatMsgTypeT; + +typedef struct +{ + uint16_t version; + uint16_t revision; + uint16_t msg_len; + uint16_t msg_type; + char node_name[SM_NODE_NAME_MAX_CHAR]; + uint32_t auth_type; + uint8_t auth_vector[SM_AUTHENTICATION_VECTOR_MAX_CHAR]; +} __attribute__ ((packed)) SmHeartbeatMsgHeaderT; + +typedef struct +{ +} __attribute__ ((packed)) SmHeartbeatMsgAliveT; + +typedef struct +{ + uint16_t msg_size; + uint32_t if_state; +} __attribute__ ((packed)) SmHeartbeatMsgAliveRev2T; + +typedef struct +{ + SmHeartbeatMsgHeaderT header; + + union + { + SmHeartbeatMsgAliveT alive; + SmHeartbeatMsgAliveRev2T if_state_msg; + char raw_msg[SM_HEARTBEAT_MSG_MAX_SIZE-sizeof(SmHeartbeatMsgHeaderT)]; + } u; +} __attribute__ ((packed)) SmHeartbeatMsgT; + +static char _tx_control_buffer[SM_HEARTBEAT_MSG_BUFFER_MAX_SIZE] __attribute__((aligned)); +static char _rx_control_buffer[SM_HEARTBEAT_MSG_BUFFER_MAX_SIZE] __attribute__((aligned)); +static SmListT* _callbacks = NULL; + +// **************************************************************************** +// Heartbeat Messaging - Register Callbacks +// ======================================== +SmErrorT sm_heartbeat_msg_register_callbacks( + SmHeartbeatMsgCallbacksT* callbacks ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callbacks ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Deregister Callbacks +// ========================================== +SmErrorT sm_heartbeat_msg_deregister_callbacks( + SmHeartbeatMsgCallbacksT* callbacks ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callbacks ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Send message from source +// ============================================== +static int sm_heartbeat_msg_sendmsg_src_ipv6(int socket, void* msg, size_t msg_len, + int flags, struct sockaddr_in6* dst_addr, struct in6_addr* src_Addr) +{ + struct msghdr msg_hdr = {}; + struct cmsghdr *cmsg; + struct in6_pktinfo *pktinfo; + struct iovec iov = {msg, msg_len}; + + + memset( &_tx_control_buffer, 0, sizeof(_tx_control_buffer) ); + msg_hdr.msg_iov = &iov; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_name = dst_addr; + msg_hdr.msg_namelen = sizeof(struct sockaddr_in6); + msg_hdr.msg_control = _tx_control_buffer; + msg_hdr.msg_controllen = CMSG_LEN(sizeof(struct in6_pktinfo)); + cmsg = CMSG_FIRSTHDR(&msg_hdr); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + pktinfo = (struct in6_pktinfo*) CMSG_DATA(cmsg); + pktinfo->ipi6_ifindex = 0; + pktinfo->ipi6_addr = *src_Addr; + + return sendmsg( socket, &msg_hdr, flags ); +} +// **************************************************************************** + +// **************************************************************************** +// initialize socket +// ============================================== +static SmErrorT sm_initialize_socket(int& sock) +{ + int result; + int flags; + + // Set socket to non-blocking. + flags = fcntl( sock, F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > fcntl( sock, F_SETFL, flags | O_NONBLOCK ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Close on exec. + flags = fcntl( sock, F_GETFD, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > fcntl( sock, F_SETFD, flags | FD_CLOEXEC ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Allow address reuse on socket. + flags = 1; + result = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, + (void*) &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set reuseaddr socket option, " + "errno=%s.", strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Send Alive +// ================================ +SmErrorT sm_heartbeat_msg_send_alive( SmNetworkTypeT network_type, char node_name[], + SmNetworkAddressT* network_address, SmNetworkAddressT* dst_addr, + int network_port, char interface_name[], SmAuthTypeT auth_type, char auth_key[], + int sender_socket ) +{ + struct sockaddr_in dst_addr4; + struct sockaddr_in6 dst_addr6; + SmHeartbeatMsgT heartbeat_msg; + SmIpv4AddressT* ipv4_address = &(dst_addr->u.ipv4); + SmIpv6AddressT* ipv6_address = &(dst_addr->u.ipv6); + int result; + + memset( &heartbeat_msg, 0, sizeof(SmHeartbeatMsgT) ); + + heartbeat_msg.header.version = htons(SM_VERSION); + heartbeat_msg.header.revision = htons(SM_REVISION); + heartbeat_msg.header.msg_len = htons(sizeof(SmHeartbeatMsgT)); + heartbeat_msg.header.msg_type = htons(SM_HEARTBEAT_MSG_TYPE_ALIVE); + snprintf( heartbeat_msg.header.node_name, + sizeof(heartbeat_msg.header.node_name), "%s", node_name ); + + heartbeat_msg.u.if_state_msg.msg_size = htons((uint16_t)sizeof(SmHeartbeatMsgAliveRev2T)); + SmHeartbeatMsgIfStateT if_state; + SmErrorT error = sm_failover_if_state_get(&if_state); + if(SM_OKAY != error) + { + return SM_FAILED; + } + heartbeat_msg.u.if_state_msg.if_state = htonl(if_state); + + if( SM_AUTH_TYPE_HMAC_SHA512 == auth_type ) + { + SmSha512HashT hash; + + heartbeat_msg.header.auth_type = htonl(auth_type); + sm_sha512_hmac( &heartbeat_msg, sizeof(heartbeat_msg), auth_key, + strlen(auth_key), &hash ); + memcpy( &(heartbeat_msg.header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + heartbeat_msg.header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if( SM_NETWORK_TYPE_IPV4_UDP == network_type ) + { + memset( &dst_addr4, 0, sizeof(dst_addr4) ); + + dst_addr4.sin_family = AF_INET; + dst_addr4.sin_port = htons(network_port); + dst_addr4.sin_addr.s_addr = ipv4_address->sin.s_addr; + + result = sendto( sender_socket, &heartbeat_msg, sizeof(SmHeartbeatMsgT), + 0, (struct sockaddr *) &dst_addr4, sizeof(dst_addr4) ); + if( 0 > result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + + } else if( SM_NETWORK_TYPE_IPV6_UDP == network_type ) { + memset( &dst_addr6, 0, sizeof(dst_addr6) ); + + dst_addr6.sin6_family = AF_INET6; + dst_addr6.sin6_port = htons(network_port); + dst_addr6.sin6_addr = ipv6_address->sin6; + + result = sm_heartbeat_msg_sendmsg_src_ipv6( sender_socket, (void*) &heartbeat_msg, + sizeof(SmHeartbeatMsgT),0, &dst_addr6, + &network_address->u.ipv6.sin6 ); + + if( 0 > result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } else { + DPRINTFE( "Unsupported network type (%s).", + sm_network_type_str( network_type ) ); + return( SM_FAILED ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Get Ancillary Data +// ======================================== +static void* sm_heartbeat_msg_get_ancillary_data( struct msghdr* msg_hdr, + int cmsg_level, int cmsg_type ) +{ + struct cmsghdr* cmsg; + + for( cmsg = CMSG_FIRSTHDR(msg_hdr); NULL != cmsg; + cmsg = CMSG_NXTHDR( msg_hdr, cmsg) ) + { + if(( cmsg_level == cmsg->cmsg_level )&& + ( cmsg_type == cmsg->cmsg_type )) + { + return( CMSG_DATA(cmsg) ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Dispatch Message +// ====================================== +static void sm_heartbeat_msg_dispatch_msg( SmHeartbeatMsgT* heartbeat_msg, + SmNetworkAddressT* network_address, + int network_port, char* interface_name ) +{ + SmHeartbeatMsgCallbacksT* callbacks; + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + + if( SM_VERSION != ntohs(heartbeat_msg->header.version) ) + { + DPRINTFD( "Received unsupported version (%i).", + ntohs(heartbeat_msg->header.version) ); + return; + } + + if( SM_AUTH_TYPE_HMAC_SHA512 == ntohl(heartbeat_msg->header.auth_type) ) + { + uint8_t auth_vector[SM_AUTHENTICATION_VECTOR_MAX_CHAR]; + + memcpy( auth_vector, &(heartbeat_msg->header.auth_vector[0]), + SM_AUTHENTICATION_VECTOR_MAX_CHAR ); + memset( &(heartbeat_msg->header.auth_vector[0]), 0, + SM_AUTHENTICATION_VECTOR_MAX_CHAR ); + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmHeartbeatMsgCallbacksT*) entry_data; + + if( NULL == callbacks->auth ) + continue; + + if( !(callbacks->auth( interface_name, network_address, + network_port, heartbeat_msg, + sizeof(SmHeartbeatMsgT), auth_vector )) ) + { + DPRINTFD( "Authentication check failed on message (%i) from " + "node (%s).", ntohs(heartbeat_msg->header.msg_type), + heartbeat_msg->header.node_name ); + return; + } else { + DPRINTFD( "Authentication check passed on message (%i) from " + "node (%s).", ntohs(heartbeat_msg->header.msg_type), + heartbeat_msg->header.node_name ); + } + } + } + + uint16_t msg_size; + SmHeartbeatMsgIfStateT if_state = 0; + bool perform_if_exg = false; + if(2 <= ntohs(heartbeat_msg->header.revision)) + { + msg_size = ntohs(heartbeat_msg->u.if_state_msg.msg_size); + if(sizeof(SmHeartbeatMsgAliveRev2T) == msg_size ) + { + if_state = ntohl(heartbeat_msg->u.if_state_msg.if_state); + perform_if_exg = true; + }else + { + DPRINTFE("Invalid interface state package. size (%d) vs expected (%d)", + msg_size, sizeof(SmHeartbeatMsgAliveRev2T)); + } + } + + switch( ntohs(heartbeat_msg->header.msg_type) ) + { + case SM_HEARTBEAT_MSG_TYPE_ALIVE: + DPRINTFD( "Alive message received." ); + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmHeartbeatMsgCallbacksT*) entry_data; + + if( NULL != callbacks->alive ) + { + callbacks->alive( heartbeat_msg->header.node_name, + network_address, network_port, + ntohs(heartbeat_msg->header.version), + ntohs(heartbeat_msg->header.revision), + interface_name ); + } + + if(perform_if_exg) + { + if(NULL != callbacks->if_state) + { + callbacks->if_state(heartbeat_msg->header.node_name, + if_state); + } + else + { + DPRINTFD("No handler for if state package"); + } + } + } + break; + + default: + DPRINTFI( "Unsupported message type (%i) received.", + ntohs(heartbeat_msg->header.msg_type) ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Dispatch Ipv4 Udp +// ======================================= +static void sm_heartbeat_msg_dispatch_ipv4_udp( int selobj, int64_t unused ) +{ + int network_port; + SmNetworkAddressT network_address; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmHeartbeatMsgT heartbeat_msg; + SmErrorT error; + struct msghdr msg_hdr; + struct sockaddr_in src_addr; + struct iovec iovec = {(void*)&heartbeat_msg, sizeof(heartbeat_msg)}; + int bytes_read; + + memset( _rx_control_buffer, 0, sizeof(_rx_control_buffer) ); + memset( &heartbeat_msg, 0, sizeof(SmHeartbeatMsgT) ); + memset( &msg_hdr, 0, sizeof(msg_hdr) ); + + msg_hdr.msg_name = &src_addr; + msg_hdr.msg_namelen= sizeof(src_addr); + msg_hdr.msg_iov = &iovec; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_control = _rx_control_buffer; + msg_hdr.msg_controllen = sizeof(_rx_control_buffer); + + int retry_i; + + for( retry_i = 5; retry_i != 0; --retry_i ) + { + bytes_read = recvmsg( selobj, &msg_hdr, MSG_NOSIGNAL | MSG_DONTWAIT ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_i, strerror( errno ) ); + } + + if( AF_INET == src_addr.sin_family ) + { + char network_address_str[SM_NETWORK_ADDRESS_MAX_CHAR]; + struct in_pktinfo* pkt_info; + + pkt_info = (struct in_pktinfo*) + sm_heartbeat_msg_get_ancillary_data( &msg_hdr, SOL_IP, IP_PKTINFO ); + if( NULL == pkt_info ) + { + DPRINTFD( "No packet information available." ); + return; + } + + error = sm_hw_get_if_name( pkt_info->ipi_ifindex, interface_name ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Failed to get interface name for interface index " + "(%i), error=%s.", pkt_info->ipi_ifindex, + sm_error_str(error) ); + } else { + DPRINTFE( "Failed to get interface name for interface index " + "(%i), error=%s.", pkt_info->ipi_ifindex, + sm_error_str(error) ); + } + return; + } + + network_address.type = SM_NETWORK_TYPE_IPV4_UDP; + network_address.u.ipv4.sin.s_addr = src_addr.sin_addr.s_addr; + network_port = ntohs(src_addr.sin_port); + + sm_network_address_str( &network_address, network_address_str ); + + DPRINTFD( "Received message from ip (%s), port (%i) on " + "interface (%s).", network_address_str, network_port, + interface_name ); + + } else { + DPRINTFE( "Received unsupported network address type (%i).", + src_addr.sin_family ); + return; + } + + // Once the message is received, pass it to protocol-independent handler + sm_heartbeat_msg_dispatch_msg( &heartbeat_msg, &network_address, + network_port, interface_name ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Dispatch IPv6 Udp +// ======================================= +static void sm_heartbeat_msg_dispatch_ipv6_udp( int selobj, int64_t unused ) +{ + int network_port; + SmNetworkAddressT network_address; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmHeartbeatMsgT heartbeat_msg; + SmErrorT error; + struct msghdr msg_hdr; + struct sockaddr_in6 src_addr; + struct iovec iovec = {(void*)&heartbeat_msg, sizeof(heartbeat_msg)}; + int bytes_read; + + memset( _rx_control_buffer, 0, sizeof(_rx_control_buffer) ); + memset( &heartbeat_msg, 0, sizeof(SmHeartbeatMsgT) ); + memset( &msg_hdr, 0, sizeof(msg_hdr) ); + + msg_hdr.msg_name = &src_addr; + msg_hdr.msg_namelen= sizeof(src_addr); + msg_hdr.msg_iov = &iovec; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_control = _rx_control_buffer; + msg_hdr.msg_controllen = sizeof(_rx_control_buffer); + + int retry_i; + for( retry_i = 5; retry_i != 0; --retry_i ) + { + bytes_read = recvmsg( selobj, &msg_hdr, MSG_NOSIGNAL | MSG_DONTWAIT ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_i, strerror( errno ) ); + } + + if( AF_INET6 == src_addr.sin6_family ) + { + char network_address_str[SM_NETWORK_ADDRESS_MAX_CHAR]; + struct in6_pktinfo* pkt_info; + + pkt_info = (struct in6_pktinfo*) + sm_heartbeat_msg_get_ancillary_data( &msg_hdr, SOL_IPV6, + IPV6_PKTINFO ); + if( NULL == pkt_info ) + { + DPRINTFD( "No packet information available." ); + return; + } + + error = sm_hw_get_if_name( pkt_info->ipi6_ifindex, interface_name ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Failed to get interface name for interface index " + "(%i), error=%s.", pkt_info->ipi6_ifindex, + sm_error_str(error) ); + } else { + DPRINTFE( "Failed to get interface name for interface index " + "(%i), error=%s.", pkt_info->ipi6_ifindex, + sm_error_str(error) ); + } + return; + } + + network_address.type = SM_NETWORK_TYPE_IPV6_UDP; + network_address.u.ipv6.sin6 = src_addr.sin6_addr; + network_port = ntohs(src_addr.sin6_port); + + sm_network_address_str( &network_address, network_address_str ); + + DPRINTFD( "Received message from ip (%s), port (%i) on " + "interface (%s).", network_address_str, network_port, + interface_name ); + + } else { + DPRINTFE( "Received unsupported network address type (%i).", + src_addr.sin6_family ); + return; + } + + // Once the message is received, pass it to protocol-independent handler + sm_heartbeat_msg_dispatch_msg( &heartbeat_msg, &network_address, + network_port, interface_name ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Open Ipv4 UDP Multicast Socket +// ==================================================== +static SmErrorT sm_heartbeat_msg_open_ipv4_udp_multicast_socket( + SmNetworkAddressT* network_address, SmNetworkAddressT* network_multicast, + int network_port, char interface_name[], int* multicast_socket ) +{ + int flags; + int sock; + int result; + struct ifreq ifr; + struct sockaddr_in addr; + SmIpv4AddressT* ipv4_unicast = &(network_address->u.ipv4); + SmIpv4AddressT* ipv4_multicast = &(network_multicast->u.ipv4); + + *multicast_socket = -1; + + // Create socket. + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to open socket for interface (%s), errno=%s.", + interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + SmErrorT error = sm_initialize_socket(sock); + if( SM_OKAY != error ) + { + DPRINTFI("Initialize socket on interface %s failed.", interface_name ); + return error; + } + + // Bind address to socket. + memset( &addr, 0, sizeof(addr) ); + + addr.sin_family = AF_INET; + addr.sin_port = htons(network_port); + addr.sin_addr.s_addr = ipv4_multicast->sin.s_addr; + + result = bind( sock, (struct sockaddr *) &addr, sizeof(addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind multicast address to socket for " + "interface (%s), error=%s.", interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast interface on socket. + result = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, + (struct in_addr*) &(ipv4_unicast->sin.s_addr), + sizeof(struct in_addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set unicast address on socket for " + "interface (%s), error=%s.", interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind socket to interface. + memset(&ifr, 0, sizeof(ifr)); + snprintf( ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface_name ); + + result = setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, + (void *)&ifr, sizeof(ifr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind socket to interface (%s), errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast TTL. + flags = 1; + result = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set multicast ttl for interface (%s), errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Disable looping of sent multicast packets on socket. + flags = 0; + result = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to stop looping of multicast messages for " + "interface (%s), errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket send priority on interface. + flags = IPTOS_CLASS_CS6; + result = setsockopt( sock, IPPROTO_IP, IP_TOS, &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + flags = 6; + result = setsockopt( sock, SOL_SOCKET, SO_PRIORITY, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket receive packet information. + flags = 1; + result = setsockopt( sock, SOL_IP, IP_PKTINFO, &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket receive packet information for " + "interface (%s) multicast messages, errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + *multicast_socket = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Open Ipv4 UDP unicast Socket +// ==================================================== +static SmErrorT sm_heartbeat_msg_open_ipv4_udp_unicast_socket( + SmNetworkAddressT* network_address, + int network_port, char interface_name[], int* unicast_socket ) +{ + int flags; + int sock; + int result; + struct ifreq ifr; + struct sockaddr_in addr; + SmIpv4AddressT* ipv4_unicast = &(network_address->u.ipv4); + + *unicast_socket = -1; + + // Create socket. + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to open socket for interface (%s), errno=%s.", + interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + SmErrorT error = sm_initialize_socket(sock); + if( SM_OKAY != error ) + { + DPRINTFI("Initialize socket on interface %s failed.", interface_name ); + return error; + } + + // Bind address to socket. + memset( &addr, 0, sizeof(addr) ); + + addr.sin_family = AF_INET; + addr.sin_port = htons(network_port); + addr.sin_addr.s_addr = ipv4_unicast->sin.s_addr; + + result = bind( sock, (struct sockaddr *) &addr, sizeof(addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind address to socket for " + "interface (%s), error=%s.", interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind socket to interface. + memset(&ifr, 0, sizeof(ifr)); + snprintf( ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface_name ); + + result = setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, + (void *)&ifr, sizeof(ifr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind socket to interface (%s), errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket send priority on interface. + flags = IPTOS_CLASS_CS6; + result = setsockopt( sock, IPPROTO_IP, IP_TOS, &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "messages, errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + flags = 6; + result = setsockopt( sock, SOL_SOCKET, SO_PRIORITY, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "messages, errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket receive packet information. + flags = 1; + result = setsockopt( sock, SOL_IP, IP_PKTINFO, &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket receive packet information for " + "interface (%s) messages, errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + *unicast_socket = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Open Ipv6 UDP Multicast Socket +// ==================================================== +static SmErrorT sm_heartbeat_msg_open_ipv6_udp_multicast_socket( + SmNetworkAddressT* network_address, SmNetworkAddressT* network_multicast, + int network_port, char interface_name[], int* multicast_socket ) +{ + int flags; + int sock; + int result; + int64_t ifindex; + struct ifreq ifr; + struct sockaddr_in6 addr; + SmIpv6AddressT* ipv6_multicast = &(network_multicast->u.ipv6); + *multicast_socket = -1; + + // Create socket. + sock = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to open socket for interface (%s), errno=%s.", + interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + SmErrorT error = sm_initialize_socket(sock); + if( SM_OKAY != error ) + { + DPRINTFI("Initialize socket on interface %s failed.", interface_name ); + return error; + } + + // Bind address to socket. + memset( &addr, 0, sizeof(addr) ); + + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(network_port); + addr.sin6_addr = ipv6_multicast->sin6; + + result = bind( sock, (struct sockaddr *) &addr, sizeof(addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind multicast address to socket for " + "interface (%s), error=%s.", interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast interface on socket. + ifindex = if_nametoindex( interface_name ); + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &ifindex, sizeof(ifindex) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set unicast address on socket for " + "interface (%s), error=%s.", interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind socket to interface. + memset( &ifr, 0, sizeof(ifr) ); + snprintf( ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface_name ); + + result = setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, + (void *)&ifr, sizeof(ifr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind socket to interface (%s), errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast TTL. + flags = 1; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set multicast ttl for interface (%s), errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Disable looping of sent multicast packets on socket. + flags = 0; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to stop looping of multicast messages for " + "interface (%s), errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket send priority on interface. + flags = IPTOS_CLASS_CS6; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_TCLASS, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + flags = 6; + result = setsockopt( sock, SOL_SOCKET, SO_PRIORITY, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket receive packet information. + flags = 1; + result = setsockopt( sock, SOL_IPV6, IPV6_RECVPKTINFO, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket receive packet information for " + "interface (%s) multicast messages, errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + *multicast_socket = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Open Ipv6 UDP Unicast Socket +// ==================================================== +static SmErrorT sm_heartbeat_msg_open_ipv6_udp_unicast_socket( + SmNetworkAddressT* network_address, + int network_port, char interface_name[], int* multicast_socket ) +{ + int flags; + int sock; + int result; + struct ifreq ifr; + struct sockaddr_in6 addr; + SmIpv6AddressT* ipv6_unicast = &(network_address->u.ipv6); + *multicast_socket = -1; + + // Create socket. + sock = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to open socket for interface (%s), errno=%s.", + interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + SmErrorT error = sm_initialize_socket(sock); + if( SM_OKAY != error ) + { + DPRINTFI("Initialize socket on interface %s failed.", interface_name ); + return error; + } + + // Bind address to socket. + memset( &addr, 0, sizeof(addr) ); + + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(network_port); + addr.sin6_addr = ipv6_unicast->sin6; + + result = bind( sock, (struct sockaddr *) &addr, sizeof(addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind multicast address to socket for " + "interface (%s), error=%s.", interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > result ) + { + DPRINTFE( "Failed to set unicast address on socket for " + "interface (%s), error=%s.", interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind socket to interface. + memset( &ifr, 0, sizeof(ifr) ); + snprintf( ifr.ifr_name, sizeof(ifr.ifr_name), "%s", interface_name ); + + result = setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, + (void *)&ifr, sizeof(ifr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind socket to interface (%s), errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast TTL. + flags = 1; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set multicast ttl for interface (%s), errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Disable looping of sent multicast packets on socket. + flags = 0; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to stop looping of multicast messages for " + "interface (%s), errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket send priority on interface. + flags = IPTOS_CLASS_CS6; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_TCLASS, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + flags = 6; + result = setsockopt( sock, SOL_SOCKET, SO_PRIORITY, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket receive packet information. + flags = 1; + result = setsockopt( sock, SOL_IPV6, IPV6_RECVPKTINFO, &flags, + sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket receive packet information for " + "interface (%s) multicast messages, errno=%s.", + interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + *multicast_socket = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Open Sockets +// ================================== +SmErrorT sm_heartbeat_msg_open_sockets( SmNetworkTypeT network_type, + SmNetworkAddressT* network_address, SmNetworkAddressT* network_multicast, + int network_port, char interface_name[], int* multicast_socket, int* unicast_socket ) +{ + SmErrorT error; + + if( -1 < *multicast_socket ) + { + DPRINTFD( "Multicast socket for interface (%s) already opened.", + interface_name ); + return( SM_OKAY ); + } + + *multicast_socket = -1; + + if( SM_NETWORK_TYPE_IPV4_UDP == network_type ) + { + int socket_fd; + + if ( network_multicast->type != SM_NETWORK_TYPE_NIL ) + { + error = sm_heartbeat_msg_open_ipv4_udp_multicast_socket( + network_address, network_multicast, network_port, + interface_name, &socket_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open multicast socket for interface (%s), " + "error=%s.", interface_name, sm_error_str(error) ); + return( error ); + } + + error = sm_selobj_register( socket_fd, + sm_heartbeat_msg_dispatch_ipv4_udp, + (int64_t) 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object for " + "interface (%s), error=%s.", interface_name, + sm_error_str(error) ); + close( socket_fd ); + return( SM_FAILED ); + } + + *multicast_socket = socket_fd; + } else + { + DPRINTFD("Multicast ip for %s is not configured.", interface_name); + *multicast_socket = -1; + } + + if( NULL != unicast_socket ) + { + error = sm_heartbeat_msg_open_ipv4_udp_unicast_socket( + network_address, network_port, + interface_name, &socket_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open multicast socket for interface (%s), " + "error=%s.", interface_name, sm_error_str(error) ); + return( error ); + } + + error = sm_selobj_register( socket_fd, + sm_heartbeat_msg_dispatch_ipv4_udp, (int64_t) 0); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object for " + "interface (%s), error=%s.", interface_name, + sm_error_str(error) ); + close( socket_fd ); + return( SM_FAILED ); + } + + *unicast_socket = socket_fd; + } + + + return( SM_OKAY ); + + } else if( SM_NETWORK_TYPE_IPV6_UDP == network_type ) + { + int socket_fd; + + if ( network_multicast->type != SM_NETWORK_TYPE_NIL ) + { + error = sm_heartbeat_msg_open_ipv6_udp_multicast_socket( + network_address, network_multicast, network_port, + interface_name, &socket_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open multicast socket for interface (%s), " + "error=%s.", interface_name, sm_error_str(error) ); + return( error ); + } + + error = sm_selobj_register( socket_fd, + sm_heartbeat_msg_dispatch_ipv6_udp, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object for " + "interface (%s), error=%s.", interface_name, + sm_error_str(error) ); + close( socket_fd ); + return( SM_FAILED ); + } + + *multicast_socket = socket_fd; + } else + { + DPRINTFD("Multicast ip for %s is not configured.", interface_name); + *multicast_socket = -1; + } + + if( NULL != unicast_socket ) + { + error = sm_heartbeat_msg_open_ipv6_udp_unicast_socket( + network_address, network_port, + interface_name, &socket_fd ); + + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open unicast socket for interface (%s), " + "error=%s.", interface_name, sm_error_str(error) ); + return( error ); + } + + error = sm_selobj_register( socket_fd, + sm_heartbeat_msg_dispatch_ipv6_udp, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object for " + "interface (%s), error=%s.", interface_name, + sm_error_str(error) ); + close( socket_fd ); + return( SM_FAILED ); + } + + *unicast_socket = socket_fd; + } + return( SM_OKAY ); + + } else { + DPRINTFE( "Unsupported network type (%s).", + sm_network_type_str( network_type ) ); + return( SM_FAILED ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Close Sockets +// =================================== +SmErrorT sm_heartbeat_msg_close_sockets( int* multicast_socket ) +{ + SmErrorT error; + + if( -1 < *multicast_socket ) + { + error = sm_selobj_deregister( *multicast_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str(error) ); + } + + close( *multicast_socket ); + *multicast_socket = -1; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Message - Initialize +// ============================== +SmErrorT sm_heartbeat_msg_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeart Message - Finalize +// ============================= +SmErrorT sm_heartbeat_msg_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.h b/service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.h new file mode 100644 index 00000000..1125d923 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_heartbeat_msg.h @@ -0,0 +1,90 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_HEARTBEAT_MSG_H__ +#define __SM_HEARTBEAT_MSG_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef bool (*SmHeartbeatMsgAuthCallbackT) (char interface_name[], + SmNetworkAddressT* network_address, int network_port, + void* msg, int msg_size, uint8_t auth_vector[]); + +typedef void (*SmHeartbeatMsgAliveCallbackT) (char node_name[], + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char interface_name[]); + +typedef void (*SmHeartbeatMsgIfStateCallbackT) (const char node_name[], + SmHeartbeatMsgIfStateT if_state); + +typedef struct +{ + SmHeartbeatMsgAuthCallbackT auth; + SmHeartbeatMsgAliveCallbackT alive; + SmHeartbeatMsgIfStateCallbackT if_state; +} SmHeartbeatMsgCallbacksT; + +// **************************************************************************** +// Heartbeat Messaging - Register Callbacks +// ======================================== +extern SmErrorT sm_heartbeat_msg_register_callbacks( + SmHeartbeatMsgCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Deregister Callbacks +// ========================================== +extern SmErrorT sm_heartbeat_msg_deregister_callbacks( + SmHeartbeatMsgCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Send Alive +// ================================ +extern SmErrorT sm_heartbeat_msg_send_alive( SmNetworkTypeT network_type, + char node_name[], SmNetworkAddressT* network_address, + SmNetworkAddressT* network_multicast, int network_port, + char interface_name[], SmAuthTypeT auth_type, char auth_key[], + int multicast_socket ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Open Sockets +// ================================== +extern SmErrorT sm_heartbeat_msg_open_sockets( SmNetworkTypeT network_type, + SmNetworkAddressT* network_address, SmNetworkAddressT* network_multicast, + int network_port, char interface_name[], int* multicast_socket, int* unicast_socket ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Messaging - Close Sockets +// =================================== +extern SmErrorT sm_heartbeat_msg_close_sockets( int* multicast_socket ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Message - Initialize +// ============================== +extern SmErrorT sm_heartbeat_msg_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeart Message - Finalize +// ============================= +extern SmErrorT sm_heartbeat_msg_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_HEARTBEAT_MSG_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_heartbeat_thread.c b/service-mgmt/sm-1.0.0/src/sm_heartbeat_thread.c new file mode 100644 index 00000000..75d54b3b --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_heartbeat_thread.c @@ -0,0 +1,1363 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_heartbeat_thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_list.h" +#include "sm_debug.h" +#include "sm_trap.h" +#include "sm_time.h" +#include "sm_selobj.h" +#include "sm_timer.h" +#include "sm_hw.h" +#include "sm_sha512.h" +#include "sm_thread_health.h" +#include "sm_heartbeat_msg.h" +#include "sm_node_utils.h" +#include "sm_alarm.h" +#include "sm_log.h" +#include "sm_failover.h" + +#define SM_HEARTBEAT_THREAD_NAME "sm_heartbeat" +#define SM_HEARTBEAT_THREAD_TICK_INTERVAL_IN_MS 100 +#define SM_HEARTBEAT_THREAD_ALIVE_TIMER_IN_MS 100 +#define SM_HEARTBEAT_ALARM_DEBOUNCE_IN_MS 30000 +#define SM_HEARTBEAT_ALARM_THROTTLE_IN_MS 5000 + +typedef enum +{ + SEND_UNICAST = 1, + SEND_MULTICAST = 2 +}SmHeartbeatThreadMethod; + +typedef struct +{ + int64_t id; + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char service_domain_interface[SM_SERVICE_DOMAIN_INTERFACE_NAME_MAX_CHAR]; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmInterfaceStateT interface_state; + SmNetworkTypeT network_type; + SmNetworkAddressT network_multicast; + SmNetworkAddressT network_address; + SmNetworkAddressT network_peer_address; + int network_peer_port; + int network_port; + SmAuthTypeT auth_type; + char auth_key[SM_AUTHENTICATION_KEY_MAX_CHAR]; + int unicast_socket; + int multicast_socket; + bool socket_reconfigure; + int method; + SmInterfaceTypeT interface_type; +} SmHeartbeatThreadInterfaceT; + +typedef struct +{ + int64_t id; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmNetworkAddressT network_address; + int network_port; + int dead_interval; + SmTimeT last_alive_msg; + SmTimeT alarm_raised_time; + SmTimeT last_alarm_clear; + SmTimeT last_alarm_raise; + SmTimerIdT alarm_timer; + char log_text[SM_LOG_REASON_TEXT_MAX_CHAR]; +} SmHeartbeatThreadPeerInterfaceT; + +typedef struct +{ + char node_name[SM_NODE_NAME_MAX_CHAR]; + int version; + int revision; + SmTimeT last_alive_msg; +} SmHeartbeatThreadPeerNodeT; + +static sig_atomic_t _stay_on; +static bool _thread_created = false; +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_t _heartbeat_thread; +static sig_atomic_t _messaging_enabled = 0; +static sig_atomic_t _heartbeat_required = 1; +static SmListT* _heartbeat_interfaces = NULL; +static SmListT* _heartbeat_peer_interfaces = NULL; +static SmListT* _heartbeat_peer_nodes = NULL; +static SmTimerIdT _alive_timer_id = SM_TIMER_ID_INVALID; +static char _node_name[SM_NODE_NAME_MAX_CHAR]; +static SmHeartbeatMsgCallbacksT _callbacks; + +// **************************************************************************** +// Heartbeat Thread - SmNetworkAddressT == +// ========================= +static bool operator == ( const SmNetworkAddressT& src, const SmNetworkAddressT& dest ) +{ + return ( 0 == memcmp( &src, &dest, sizeof(SmNetworkAddressT) ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - SmNetworkAddressT != +// ========================= +static bool operator != ( const SmNetworkAddressT& src, const SmNetworkAddressT& dest ) +{ + return !( src == dest ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Disable heartbeat +// ========================= +void sm_heartbeat_thread_disable_heartbeat( void ) +{ + _heartbeat_required = 0; + + DPRINTFI( "Heartbeat is not required." ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Enable +// ========================= +void sm_heartbeat_thread_enable( void ) +{ + _messaging_enabled = 1; + + DPRINTFI( "Heartbeat messaging is now enabled." ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Disable +// ========================== +void sm_heartbeat_thread_disable( void ) +{ + _messaging_enabled = 0; + + DPRINTFI( "Heartbeat messaging is now disabled." ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Find Interface +// ================================= +static SmHeartbeatThreadInterfaceT* sm_heartbeat_thread_find_interface( + int64_t id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmHeartbeatThreadInterfaceT* interface; + + SM_LIST_FOREACH( _heartbeat_interfaces, entry, entry_data ) + { + interface = (SmHeartbeatThreadInterfaceT*) entry_data; + + if( id == interface->id ) + { + return( interface ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Add Interface +// ================================ +SmErrorT sm_heartbeat_thread_add_interface( const SmServiceDomainInterfaceT& domain_interface ) +{ + if (0 == _heartbeat_required) + { + DPRINTFE( "Heartbeat is not required, skip adding interface." ); + return( SM_OKAY ); + } + bool configure = false; + SmHeartbeatThreadInterfaceT* interface; + SmErrorT error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + interface = sm_heartbeat_thread_find_interface( domain_interface.id ); + if( NULL == interface ) + { + interface = (SmHeartbeatThreadInterfaceT*) + malloc( sizeof(SmHeartbeatThreadInterfaceT) ); + if( NULL == interface ) + { + DPRINTFE( "Failed to allocate heartbeat interface (%s).", + domain_interface.interface_name ); + goto ERROR; + } + + SM_LIST_PREPEND( _heartbeat_interfaces, + (SmListEntryDataPtrT) interface ); + + memset( interface, 0, sizeof(SmHeartbeatThreadInterfaceT) ); + interface->multicast_socket = -1; + + interface->interface_type = sm_get_interface_type(domain_interface.service_domain_interface); + if ( SM_INTERFACE_OAM == interface->interface_type ) + { + interface->method = SEND_UNICAST; + } else + { + interface->method = SEND_MULTICAST; + } + configure = true; + + } else { + if(( 0 != strcmp( interface->service_domain, domain_interface.service_domain ) )|| + ( 0 != strcmp( interface->service_domain_interface, + domain_interface.service_domain_interface ) )|| + ( 0 != strcmp( interface->interface_name, domain_interface.interface_name ) )|| + ( interface->network_type != domain_interface.network_type ) || + ( interface->network_multicast != domain_interface.network_multicast ) || + ( interface->network_address != domain_interface.network_address ) || + ( interface->network_port != domain_interface.network_heartbeat_port ) || + ( interface->network_peer_address != domain_interface.network_peer_address ) || + ( interface->network_peer_port != domain_interface.network_peer_heartbeat_port )) + { + // Same id, but not the same instance data. + error = sm_heartbeat_msg_close_sockets( + &(interface->multicast_socket) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close multicast socket for interface " + "(%s).", interface->interface_name ); + goto ERROR; + } + error = sm_heartbeat_msg_close_sockets( + &(interface->unicast_socket) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close unicast socket for interface " + "(%s).", interface->interface_name ); + goto ERROR; + } + + configure = true; + + } else { + // Update data. + interface->interface_state = domain_interface.interface_state; + interface->auth_type = domain_interface.auth_type; + snprintf( interface->auth_key, sizeof(interface->auth_key), + "%s", domain_interface.auth_key ); + } + } + + if( configure ) + { + interface->id = domain_interface.id; + snprintf( interface->service_domain, sizeof(interface->service_domain), + "%s", domain_interface.service_domain ); + snprintf( interface->service_domain_interface, + sizeof(interface->service_domain_interface), + "%s", domain_interface.service_domain_interface ); + snprintf( interface->interface_name, sizeof(interface->interface_name), + "%s", domain_interface.interface_name ); + interface->interface_state = domain_interface.interface_state; + interface->network_type = domain_interface.network_type; + memcpy( &(interface->network_multicast), &domain_interface.network_multicast, + sizeof(SmNetworkAddressT) ); + memcpy( &(interface->network_address), &domain_interface.network_address, + sizeof(SmNetworkAddressT) ); + interface->network_port = domain_interface.network_heartbeat_port; + memcpy( &(interface->network_peer_address), &domain_interface.network_peer_address, + sizeof(SmNetworkAddressT) ); + interface->network_peer_port = domain_interface.network_peer_heartbeat_port; + interface->auth_type = domain_interface.auth_type; + snprintf( interface->auth_key, sizeof(interface->auth_key), "%s", + domain_interface.auth_key ); + interface->multicast_socket = -1; + interface->unicast_socket = -1; + interface->socket_reconfigure = false; + + DPRINTFI( "Heartbeat interface (%s) configured.", + interface->interface_name ); + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); + +ERROR: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Delete Interface +// =================================== +SmErrorT sm_heartbeat_thread_delete_interface( int64_t id ) +{ + SmHeartbeatThreadInterfaceT* interface; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + interface = sm_heartbeat_thread_find_interface( id ); + if( NULL != interface ) + { + SM_LIST_REMOVE( _heartbeat_interfaces, + (SmListEntryDataPtrT) interface ); + free( interface ); + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Find Peer Interface +// ====================================== +static SmHeartbeatThreadPeerInterfaceT* sm_heartbeat_thread_find_peer_interface( + char interface_name[], SmNetworkAddressT* network_address, int network_port ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmHeartbeatThreadPeerInterfaceT* peer_interface; + + SM_LIST_FOREACH( _heartbeat_peer_interfaces, entry, entry_data ) + { + peer_interface = (SmHeartbeatThreadPeerInterfaceT*) entry_data; + + if( 0 != strcmp( interface_name, peer_interface->interface_name ) ) + continue; + + if( network_address->type != peer_interface->network_address.type ) + { + continue; + } + + if( SM_NETWORK_TYPE_IPV4 == network_address->type ) + { + if( network_address->u.ipv4.sin.s_addr + == peer_interface->network_address.u.ipv4.sin.s_addr ) + { + return( peer_interface ); + } + } else if( SM_NETWORK_TYPE_IPV4_UDP == network_address->type ) { + if(( network_address->u.ipv4.sin.s_addr + == peer_interface->network_address.u.ipv4.sin.s_addr )&& + ( network_port == peer_interface->network_port )) + { + return( peer_interface ); + } + } else if( SM_NETWORK_TYPE_IPV6 == network_address->type ) { + if( !memcmp( &(network_address->u.ipv6.sin6), + &(peer_interface->network_address.u.ipv6.sin6), + sizeof(in6_addr) )) + { + return( peer_interface ); + } + } else if( SM_NETWORK_TYPE_IPV6_UDP == network_address->type ) { + if( !memcmp( &(network_address->u.ipv6.sin6), + &(peer_interface->network_address.u.ipv6.sin6), + sizeof(in6_addr) )&& + ( network_port == peer_interface->network_port )) + { + return( peer_interface ); + } + } + } + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Peer Alarm on Interface Timer +// ================================================ +static bool sm_heartbeat_peer_alarm_on_interface( SmTimerIdT timer_id, + int64_t user_data ) +{ + bool rearm = true; + bool raise_alarm = false; + long ms_expired; + char hostname[SM_NODE_NAME_MAX_CHAR]; + char network_type[16]; + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmAlarmSpecificProblemTextT problem_text; + SmAlarmProposedRepairActionT proposed_repair_action; + SmHeartbeatThreadInterfaceT* interface = NULL; + SmHeartbeatThreadPeerInterfaceT* peer_interface = NULL; + char log_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( true ); + } + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( true ); + } + + SM_LIST_FOREACH( _heartbeat_peer_interfaces, entry, entry_data ) + { + SmHeartbeatThreadPeerInterfaceT* tmp; + + tmp = (SmHeartbeatThreadPeerInterfaceT*) entry_data; + + if( timer_id == tmp->alarm_timer ) + { + peer_interface = tmp; + break; + } + } + + if( NULL == peer_interface ) + { + DPRINTFE( "Stale peer interface alarm timer detected, peer " + "interface not found." ); + rearm = false; + goto ERROR; + } + + interface = sm_heartbeat_thread_find_interface( peer_interface->id ); + if( NULL == interface ) + { + DPRINTFE( "Interface (%s) not found.", + peer_interface->interface_name ); + goto ERROR; + } + + if( 0 == strcmp( SM_SERVICE_DOMAIN_MGMT_INTERFACE, + interface->service_domain_interface ) ) + { + snprintf( network_type, sizeof(network_type), SM_MGMT_INTERFACE_NAME ); + + } else if( 0 == strcmp( SM_SERVICE_DOMAIN_OAM_INTERFACE, + interface->service_domain_interface ) ) + { + snprintf( network_type, sizeof(network_type), SM_OAM_INTERFACE_NAME ); + + } else if( 0 == strcmp( SM_SERVICE_DOMAIN_INFRA_INTERFACE, + interface->service_domain_interface ) ) + { + snprintf( network_type, sizeof(network_type), SM_INFRA_INTERFACE_NAME ); + + } else { + snprintf( network_type, sizeof(network_type), "unknown" ); + } + + ms_expired = sm_time_get_elapsed_ms( &(peer_interface->last_alive_msg) ); + SmFailoverInterfaceT failover_interface; + failover_interface.service_domain = interface->service_domain; + failover_interface.service_domain_interface = interface->service_domain_interface; + failover_interface.interface_name = interface->interface_name; + failover_interface.interface_state = interface->interface_state; + if( ms_expired >= peer_interface->dead_interval ) + { + sm_failover_lost_heartbeat(&failover_interface); + raise_alarm = true; + sm_time_get( &(peer_interface->alarm_raised_time) ); + snprintf( problem_text, sizeof(problem_text), + "communication failure detected with peer over " + "port %s on host %s", interface->interface_name, hostname ); + snprintf( log_text, sizeof(log_text), "%s", problem_text ); + + } else { + sm_failover_heartbeat_restore(&failover_interface); + if( SM_HEARTBEAT_ALARM_DEBOUNCE_IN_MS > + sm_time_get_elapsed_ms( &(peer_interface->alarm_raised_time) ) ) + { + raise_alarm = true; + snprintf( problem_text, sizeof(problem_text), + "communication failure detected with peer over " + "port %s on host %s within the last %i seconds", + interface->interface_name, hostname, + SM_HEARTBEAT_ALARM_DEBOUNCE_IN_MS/1000 ); + snprintf( log_text, sizeof(log_text), "%s", problem_text ); + + } else { + raise_alarm = false; + snprintf( log_text, sizeof(log_text), "communication established " + "with peer over port %s on host %s", + interface->interface_name, hostname ); + } + } + + if( raise_alarm ) + { + memset( &(peer_interface->last_alarm_clear), 0, sizeof(SmTimeT) ); + + if( SM_HEARTBEAT_ALARM_THROTTLE_IN_MS <= + sm_time_get_elapsed_ms( &(peer_interface->last_alarm_raise) ) ) + { + sm_time_get( &(peer_interface->last_alarm_raise) ); + + snprintf( proposed_repair_action, sizeof(proposed_repair_action), + "check cabling and far-end port configuration " + "and status on adjacent equipment" ); + + sm_alarm_raise_communication_alarm( + SM_ALARM_COMMUNICATION_FAILURE, hostname, + network_type, SM_ALARM_SEVERITY_MAJOR, + SM_ALARM_PROBABLE_CAUSE_UNDERLYING_RESOURCE_UNAVAILABLE, + problem_text, "", proposed_repair_action, true ); + } + + } else { + memset( &(peer_interface->last_alarm_raise), 0, sizeof(SmTimeT) ); + + if( SM_HEARTBEAT_ALARM_THROTTLE_IN_MS <= + sm_time_get_elapsed_ms( &(peer_interface->last_alarm_clear) ) ) + { + sm_time_get( &(peer_interface->last_alarm_clear) ); + + sm_alarm_clear( SM_ALARM_COMMUNICATION_FAILURE, hostname, "", + network_type ); + } + } + + if( 0 != strcmp( peer_interface->log_text, log_text ) ) + { + snprintf( peer_interface->log_text, + sizeof(peer_interface->log_text), "%s", log_text ); + + sm_log_communication_state_change( network_type, peer_interface->log_text ); + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( true ); + +ERROR: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( rearm ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Add Peer Interface +// ===================================== +SmErrorT sm_heartbeat_thread_add_peer_interface( int64_t id, + char interface_name[], SmNetworkAddressT* network_address, + int network_port, int dead_interval ) +{ + SmHeartbeatThreadPeerInterfaceT* peer_interface; + SmErrorT error; + + + if (0 == _heartbeat_required) + { + DPRINTFE( "Heartbeat is not required, skip adding peer interface." ); + return( SM_OKAY ); + } + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + peer_interface = sm_heartbeat_thread_find_peer_interface( interface_name, + network_address, network_port ); + if( NULL == peer_interface ) + { + char timer_name[80]; + + peer_interface = (SmHeartbeatThreadPeerInterfaceT*) + malloc( sizeof(SmHeartbeatThreadPeerInterfaceT) ); + if( NULL == peer_interface ) + { + DPRINTFE( "Failed to allocate peer heartbeat interface (%s).", + interface_name ); + goto ERROR; + } + + memset( peer_interface, 0, sizeof(SmHeartbeatThreadPeerInterfaceT) ); + + peer_interface->id = id; + snprintf( peer_interface->interface_name, + sizeof(peer_interface->interface_name), "%s", + interface_name ); + memcpy( &(peer_interface->network_address), network_address, + sizeof(SmNetworkAddressT) ); + peer_interface->network_port = network_port; + peer_interface->dead_interval = dead_interval; + sm_time_get( &(peer_interface->last_alive_msg) ); + peer_interface->alarm_timer = SM_TIMER_ID_INVALID; + + snprintf( timer_name, sizeof(timer_name), "peer alarm on interface %s", + interface_name ); + + error = sm_timer_register( timer_name, + peer_interface->dead_interval, + sm_heartbeat_peer_alarm_on_interface, 0, + &(peer_interface->alarm_timer) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create peer alarm timer, error=%s.", + sm_error_str( error ) ); + } + + SM_LIST_PREPEND( _heartbeat_peer_interfaces, + (SmListEntryDataPtrT) peer_interface ); + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); + +ERROR: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Delete Peer Interface +// ======================================== +SmErrorT sm_heartbeat_thread_delete_peer_interface( char interface_name[], + SmNetworkAddressT* network_address, int network_port ) +{ + SmHeartbeatThreadPeerInterfaceT* peer_interface; + SmErrorT error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + peer_interface = sm_heartbeat_thread_find_peer_interface( interface_name, + network_address, network_port ); + if( NULL != peer_interface ) + { + if( SM_TIMER_ID_INVALID != peer_interface->alarm_timer ) + { + error = sm_timer_deregister( peer_interface->alarm_timer ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel peer alarm timer, error=%s.", + sm_error_str( error ) ); + } + + peer_interface->alarm_timer = SM_TIMER_ID_INVALID; + } + + SM_LIST_REMOVE( _heartbeat_peer_interfaces, + (SmListEntryDataPtrT) peer_interface ); + + memset( peer_interface, 0, sizeof(SmHeartbeatThreadPeerInterfaceT) ); + + free( peer_interface ); + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Find Peer Node +// ================================= +static SmHeartbeatThreadPeerNodeT* sm_heartbeat_thread_find_peer_node( + char node_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmHeartbeatThreadPeerNodeT* peer_node; + + SM_LIST_FOREACH( _heartbeat_peer_nodes, entry, entry_data ) + { + peer_node = (SmHeartbeatThreadPeerNodeT*) entry_data; + + if( 0 == strcmp( node_name, peer_node->node_name ) ) + { + return( peer_node ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Peer Alive In Period +// ======================================= +bool sm_heartbeat_thread_peer_alive_in_period( char node_name[], + unsigned int period_in_ms ) +{ + bool peer_alive = false; + SmHeartbeatThreadPeerNodeT* peer_node; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( true ); + } + + peer_node = sm_heartbeat_thread_find_peer_node( node_name ); + if( NULL != peer_node ) + { + long ms_expired; + + ms_expired = sm_time_get_elapsed_ms( &(peer_node->last_alive_msg) ); + + peer_alive = ( period_in_ms >= ms_expired ); + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( peer_alive ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Alive Timer +// ============================== +static bool sm_heartbeat_alive_timer( SmTimerIdT timer_id, int64_t user_data ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmHeartbeatThreadInterfaceT* interface; + SmErrorT error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( true ); + } + + if( '\0' == _node_name[0] ) + { + DPRINTFI( "Node name not set yet." ); + goto DONE; + } + + if( 0 == _messaging_enabled ) + { + DPRINTFD( "Messaging is disabled." ); + goto DONE; + } + + SM_LIST_FOREACH( _heartbeat_interfaces, entry, entry_data ) + { + interface = (SmHeartbeatThreadInterfaceT*) entry_data; + + if( SM_INTERFACE_STATE_ENABLED != interface->interface_state || + interface->socket_reconfigure ) + { + error = sm_heartbeat_msg_close_sockets( + &(interface->multicast_socket) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close multicast socket for interface " + "(%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + continue; + } + + if ( SM_INTERFACE_OAM == interface->interface_type ) + { + error = sm_heartbeat_msg_close_sockets( + &(interface->unicast_socket) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close unicast socket for interface " + "(%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + continue; + } + } + + if( SM_INTERFACE_STATE_ENABLED != interface->interface_state ) + { + continue; + } + + if( SM_INTERFACE_OAM == interface->interface_type ) + { + error = sm_heartbeat_msg_open_sockets( interface->network_type, + &(interface->network_address), + &(interface->network_multicast), + interface->network_port, interface->interface_name, + &(interface->multicast_socket), &(interface->unicast_socket) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open sockets for interface (%s), " + "error=%s.", interface->interface_name, + sm_error_str(error) ); + continue; + } + + }else + { + error = sm_heartbeat_msg_open_sockets( interface->network_type, + &(interface->network_address), + &(interface->network_multicast), + interface->network_port, interface->interface_name, + &(interface->multicast_socket), NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open sockets for interface (%s), " + "error=%s.", interface->interface_name, + sm_error_str(error) ); + continue; + } + } + interface->socket_reconfigure = false; + } + + if ( interface->network_multicast.type != SM_NETWORK_TYPE_NIL ) + { + if( SM_INTERFACE_OAM != interface->interface_type ) + { + error = sm_heartbeat_msg_send_alive( interface->network_type, _node_name, + &(interface->network_address), &(interface->network_multicast), + interface->network_port, interface->interface_name, + interface->auth_type, interface->auth_key, + interface->multicast_socket ); + if( SM_OKAY != error ) + { + char multicast_addr_str[200]; + sm_network_address_str(&interface->network_multicast, multicast_addr_str); + + DPRINTFE( "Failed to send alive on to %s interface (%s), " + "error=%s.", multicast_addr_str, interface->interface_name, + sm_error_str(error) ); + interface->socket_reconfigure = true; + continue; + } + } + } else + { + DPRINTFD( "Multicast not configured for interface %s", interface->interface_name ); + } + + if ( SM_INTERFACE_OAM == interface->interface_type ) + { + error = sm_heartbeat_msg_send_alive( interface->network_type, _node_name, + &(interface->network_address), &(interface->network_peer_address), + interface->network_port, interface->interface_name, + interface->auth_type, interface->auth_key, + interface->unicast_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send alive on interface (%s), " + "error=%s.", interface->interface_name, + sm_error_str(error) ); + interface->socket_reconfigure = true; + continue; + } + } + + DPRINTFD( "Sent alive message for node (%s).", _node_name ); + } + +DONE: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( true ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Authenticate Message +// ======================================= +static bool sm_heartbeat_thread_auth_message( char interface_name[], + SmNetworkAddressT* network_address, int network_port, + void* msg, int msg_size, uint8_t auth_vector[] ) +{ + bool auth = false; + SmHeartbeatThreadPeerInterfaceT* peer_interface; + SmHeartbeatThreadInterfaceT* interface; + SmSha512HashT hash; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( true ); + } + + peer_interface = sm_heartbeat_thread_find_peer_interface( interface_name, + network_address, network_port ); + if( NULL != peer_interface ) + { + interface = sm_heartbeat_thread_find_interface( peer_interface->id ); + if( NULL == interface ) + { + DPRINTFE( "Interface (%s) not found.", + peer_interface->interface_name ); + goto DONE; + } + + sm_sha512_hmac( msg, msg_size, interface->auth_key, + strlen(interface->auth_key), &hash ); + + if( 0 == memcmp( &(hash.bytes[0]), auth_vector, SM_SHA512_HASH_SIZE ) ) + { + auth = true; + } + else + { + DPRINTFD("auth key not matched, auth key %s", interface->auth_key); + } + } + + +DONE: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( true ); + } + + return( auth ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Receive Alive Message +// ======================================== +static void sm_heartbeat_thread_receive_alive_message( char node_name[], + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char interface_name[] ) +{ + SmHeartbeatThreadPeerInterfaceT* peer_interface; + + DPRINTFD( "Received alive message from node (%s).", node_name ); + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return; + } + + if( '\0' == node_name[0] ) + { + DPRINTFE( "Node name invalid." ); + goto DONE; + } + + if( 0 == _messaging_enabled ) + { + DPRINTFD( "Messaging is disabled." ); + goto DONE; + } + + peer_interface = sm_heartbeat_thread_find_peer_interface( interface_name, + network_address, network_port ); + if( NULL != peer_interface ) + { + SmHeartbeatThreadPeerNodeT* peer_node; + + sm_time_get( &(peer_interface->last_alive_msg) ); + + peer_node = sm_heartbeat_thread_find_peer_node( node_name ); + if( NULL == peer_node ) + { + peer_node = (SmHeartbeatThreadPeerNodeT*) + malloc( sizeof(SmHeartbeatThreadPeerNodeT) ); + if( NULL == peer_node ) + { + DPRINTFE( "Failed to allocate peer node (%s).", node_name ); + goto DONE; + } + + SM_LIST_PREPEND( _heartbeat_peer_nodes, + (SmListEntryDataPtrT) peer_node ); + + memset( peer_node, 0, sizeof(SmHeartbeatThreadPeerNodeT) ); + + snprintf( peer_node->node_name, sizeof(peer_node->node_name), + "%s", node_name ); + + DPRINTFI( "Peer node (%s) added.", peer_node->node_name ); + } + + peer_node->version = version; + peer_node->revision = revision; + peer_node->last_alive_msg = peer_interface->last_alive_msg; + } + +DONE: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Receive if_state Message +// ======================================== +static void sm_heartbeat_thread_receive_if_state_message( const char node_name[], + SmHeartbeatMsgIfStateT if_state) +{ + sm_failover_if_state_update(node_name, if_state); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Initialize Thread +// ==================================== +static SmErrorT sm_heartbeat_thread_initialize_thread( void ) +{ + SmErrorT error; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_initialize( SM_HEARTBEAT_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_heartbeat_msg_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize heartbeat message module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + _callbacks.auth = sm_heartbeat_thread_auth_message; + _callbacks.alive = sm_heartbeat_thread_receive_alive_message; + _callbacks.if_state = sm_heartbeat_thread_receive_if_state_message; + + error = sm_heartbeat_msg_register_callbacks( &_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register heartbeat message callbacks, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_timer_register( "heartbeat alive", + SM_HEARTBEAT_THREAD_ALIVE_TIMER_IN_MS, + sm_heartbeat_alive_timer, 0, &_alive_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create heartbeat alive timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_hw_initialize( NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize hardware module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_node_utils_get_hostname( _node_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get node name, error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Finalize Thread +// ================================== +static SmErrorT sm_heartbeat_thread_finalize_thread( void ) +{ + SmErrorT error; + + error = sm_hw_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize hardware module, error=%s.", + sm_error_str( error ) ); + } + + if( SM_TIMER_ID_INVALID != _alive_timer_id ) + { + error = sm_timer_deregister( _alive_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel heartbeat alive timer, error=%s.", + sm_error_str( error ) ); + } + + _alive_timer_id = SM_TIMER_ID_INVALID; + } + + error = sm_heartbeat_msg_deregister_callbacks( &_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister heartbeat message callbacks, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_heartbeat_msg_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize heartbeat message module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize timer module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Main +// ======================= +static void* sm_heartbeat_thread_main( void* arguments ) +{ + SmErrorT error; + struct sched_param param; + int result; + + pthread_setname_np( pthread_self(), SM_HEARTBEAT_THREAD_NAME ); + sm_debug_set_thread_info(); + sm_trap_set_thread_info(); + + memset( ¶m, 0, sizeof(struct sched_param) ); + param.sched_priority = sched_get_priority_min( SCHED_RR ); + + result = pthread_setschedparam( pthread_self(), SCHED_RR, ¶m ); + if( 0 != result ) + { + DPRINTFE( "Failed to set heartbeat thread to realtime (priority=%d), " + "error=%s (%i).", param.sched_priority, strerror( result ), + result ); + pthread_exit( NULL ); + } + + DPRINTFI( "Starting" ); + + // Warn after 400 milliseconds, fail after 3 seconds. + error = sm_thread_health_register( SM_HEARTBEAT_THREAD_NAME, 400, 3000 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register heartbeat thread, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + error = sm_heartbeat_thread_initialize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize heartbeat thread, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + DPRINTFI( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_HEARTBEAT_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + + error = sm_thread_health_update( SM_HEARTBEAT_THREAD_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update heartbeat thread health, error=%s.", + sm_error_str(error) ); + } + } + + DPRINTFI( "Shutting down." ); + + error = sm_heartbeat_thread_finalize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize heartbeat thread, error=%s.", + sm_error_str( error ) ); + } + + error = sm_thread_health_deregister( SM_HEARTBEAT_THREAD_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister heartbeat thread, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Start +// ======================== +SmErrorT sm_heartbeat_thread_start( void ) +{ + int result; + + _stay_on = 1; + _messaging_enabled = 0; + _thread_created = false; + + result = pthread_create( &_heartbeat_thread, NULL, sm_heartbeat_thread_main, + NULL ); + if( 0 != result ) + { + DPRINTFE( "Failed to start heartbeat thread, error=%s.", + strerror(result) ); + return( SM_FAILED ); + } + + _thread_created = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Stop +// ======================= +SmErrorT sm_heartbeat_thread_stop( void ) +{ + _stay_on = 0; + _messaging_enabled = 0; + + if( _thread_created ) + { + long ms_expired; + SmTimeT time_prev; + int result; + + sm_time_get( &time_prev ); + + while( true ) + { + result = pthread_tryjoin_np( _heartbeat_thread, NULL ); + if(( 0 != result )&&( EBUSY != result )) + { + if(( ESRCH != result )&&( EINVAL != result )) + { + DPRINTFE( "Failed to wait for heartbeat thread exit, " + "sending kill signal, error=%s.", + strerror(result) ); + pthread_kill( _heartbeat_thread, SIGKILL ); + } + break; + } + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( 5000 <= ms_expired ) + { + DPRINTFE( "Failed to stop heartbeat thread, sending " + "kill signal." ); + pthread_kill( _heartbeat_thread, SIGKILL ); + break; + } + + usleep( 250000 ); // 250 milliseconds. + } + } + + _thread_created = false; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_heartbeat_thread.h b/service-mgmt/sm-1.0.0/src/sm_heartbeat_thread.h new file mode 100644 index 00000000..6f5f1446 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_heartbeat_thread.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_HEARTBEAT_THREAD_H__ +#define __SM_HEARTBEAT_THREAD_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_service_domain_interface_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Heartbeat Thread - Disable heartbeat +// ========================= +extern void sm_heartbeat_thread_disable_heartbeat( void ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Enable +// ========================= +extern void sm_heartbeat_thread_enable( void ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Disable +// ========================== +extern void sm_heartbeat_thread_disable( void ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Add Interface +// ================================ +extern SmErrorT sm_heartbeat_thread_add_interface( + const SmServiceDomainInterfaceT& domain_interface ); +// **************************************************************************** + + + +// **************************************************************************** +// Heartbeat Thread - Delete Interface +// =================================== +extern SmErrorT sm_heartbeat_thread_delete_interface( int64_t id ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Add Peer Interface +// ===================================== +extern SmErrorT sm_heartbeat_thread_add_peer_interface( int64_t id, + char interface_name[], SmNetworkAddressT* network_address, + int network_port, int dead_interval ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Delete Peer Interface +// ======================================== +extern SmErrorT sm_heartbeat_thread_delete_peer_interface( + char interface_name[], SmNetworkAddressT* network_address, + int network_port ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Peer Alive In Period +// ======================================= +extern bool sm_heartbeat_thread_peer_alive_in_period( char node_name[], + unsigned int period_in_ms ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeat Thread - Start +// ======================== +extern SmErrorT sm_heartbeat_thread_start( void ); +// **************************************************************************** + +// **************************************************************************** +// Heartbeart Thread - Stop +// ======================== +extern SmErrorT sm_heartbeat_thread_stop( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_HEARTBEAT_THREAD_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_log.c b/service-mgmt/sm-1.0.0/src/sm_log.c new file mode 100644 index 00000000..11de977a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_log.c @@ -0,0 +1,517 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_log.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_log_thread.h" +#include "sm_node_utils.h" +#include "sm_service_domain_member_table.h" +#include "sm_service_group_member_table.h" + +static int _server_fd = -1; +static int _client_fd = -1; + +// **************************************************************************** +// Log - Node Reboot +// ================= +void sm_log_node_reboot( char entity_name[], const char reason_text[], + bool forced ) +{ + SmLogThreadMsgT msg; + SmLogThreadMsgRebootLogT* reboot = &(msg.u.reboot); + + memset( &msg, 0, sizeof(msg) ); + + if( forced ) + { + msg.type = SM_LOG_THREAD_MSG_NODE_REBOOT_FORCE_LOG; + } else { + msg.type = SM_LOG_THREAD_MSG_NODE_REBOOT_LOG; + } + + clock_gettime( CLOCK_REALTIME, &(reboot->ts_real) ); + + snprintf( reboot->node_name, sizeof(reboot->node_name), + "%s", entity_name ); + snprintf( reboot->entity_name, sizeof(reboot->entity_name), + "%s", entity_name ); + snprintf( reboot->reason_text, sizeof(reboot->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Node State Change +// ======================= +void sm_log_node_state_change( char entity_name[], const char prev_state[], + const char state[], const char reason_text[] ) +{ + SmLogThreadMsgT msg; + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_LOG_THREAD_MSG_NODE_STATE_CHANGE_LOG; + + clock_gettime( CLOCK_REALTIME, &(state_change->ts_real) ); + + snprintf( state_change->node_name, sizeof(state_change->node_name), + "%s", entity_name ); + snprintf( state_change->entity_name, sizeof(state_change->entity_name), + "%s", entity_name ); + snprintf( state_change->prev_state, sizeof(state_change->prev_state), + "%s", prev_state ); + state_change->prev_status[0] = '\0'; + snprintf( state_change->state, sizeof(state_change->state), + "%s", state ); + state_change->status[0] = '\0'; + snprintf( state_change->reason_text, sizeof(state_change->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Interface State Change +// ============================ +void sm_log_interface_state_change( char entity_name[], + const char prev_state[], const char state[], const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + SmLogThreadMsgT msg; + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + SmErrorT error; + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_LOG_THREAD_MSG_INTERFACE_STATE_CHANGE_LOG; + + clock_gettime( CLOCK_REALTIME, &(state_change->ts_real) ); + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY == error ) + { + snprintf( state_change->node_name, sizeof(state_change->node_name), + "%s", hostname ); + } + + snprintf( state_change->entity_name, sizeof(state_change->entity_name), + "%s", entity_name ); + snprintf( state_change->prev_state, sizeof(state_change->prev_state), + "%s", prev_state ); + state_change->prev_status[0] = '\0'; + snprintf( state_change->state, sizeof(state_change->state), + "%s", state ); + state_change->status[0] = '\0'; + snprintf( state_change->reason_text, sizeof(state_change->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Comunication State Change +// ================================ +void sm_log_communication_state_change( char entity_name[], + const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + SmLogThreadMsgT msg; + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + SmErrorT error; + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_LOG_THREAD_MSG_COMMUNICATION_STATE_CHANGE_LOG; + + clock_gettime( CLOCK_REALTIME, &(state_change->ts_real) ); + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY == error ) + { + snprintf( state_change->node_name, sizeof(state_change->node_name), + "%s", hostname ); + } + + snprintf( state_change->entity_name, sizeof(state_change->entity_name), + "%s", entity_name ); + snprintf( state_change->reason_text, sizeof(state_change->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Neighbor State Change +// =========================== +void sm_log_neighbor_state_change( char entity_name[], const char prev_state[], + const char state[], const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + SmLogThreadMsgT msg; + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + SmErrorT error; + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_LOG_THREAD_MSG_NEIGHBOR_STATE_CHANGE_LOG; + + clock_gettime( CLOCK_REALTIME, &(state_change->ts_real) ); + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY == error ) + { + snprintf( state_change->node_name, sizeof(state_change->node_name), + "%s", hostname ); + } + + snprintf( state_change->entity_name, sizeof(state_change->entity_name), + "%s", entity_name ); + snprintf( state_change->prev_state, sizeof(state_change->prev_state), + "%s", prev_state ); + state_change->prev_status[0] = '\0'; + snprintf( state_change->state, sizeof(state_change->state), + "%s", state ); + state_change->status[0] = '\0'; + snprintf( state_change->reason_text, sizeof(state_change->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Service Domain State Change +// ================================= +void sm_log_service_domain_state_change( char entity_name[], + const char prev_state[], const char state[], const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + SmLogThreadMsgT msg; + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + SmErrorT error; + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_LOG_THREAD_MSG_SERVICE_DOMAIN_STATE_CHANGE_LOG; + + clock_gettime( CLOCK_REALTIME, &(state_change->ts_real) ); + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY == error ) + { + snprintf( state_change->node_name, sizeof(state_change->node_name), + "%s", hostname ); + } + + snprintf( state_change->domain_name, sizeof(state_change->domain_name), + "%s", entity_name ); + + snprintf( state_change->entity_name, sizeof(state_change->entity_name), + "%s", entity_name ); + snprintf( state_change->prev_state, sizeof(state_change->prev_state), + "%s", prev_state ); + state_change->prev_status[0] = '\0'; + snprintf( state_change->state, sizeof(state_change->state), + "%s", state ); + state_change->status[0] = '\0'; + snprintf( state_change->reason_text, sizeof(state_change->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Service Group Redundancy Change +// ===================================== +void sm_log_service_group_redundancy_change( char entity_name[], + const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + SmServiceDomainMemberT* domain_member; + SmLogThreadMsgT msg; + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + SmErrorT error; + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_LOG_THREAD_MSG_SERVICE_GROUP_REDUNDANCY_CHANGE_LOG; + + clock_gettime( CLOCK_REALTIME, &(state_change->ts_real) ); + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY == error ) + { + snprintf( state_change->node_name, sizeof(state_change->node_name), + "%s", hostname ); + } + + domain_member + = sm_service_domain_member_table_read_service_group( entity_name ); + if( NULL != domain_member ) + { + snprintf( state_change->domain_name, sizeof(state_change->domain_name), + "%s", domain_member->name ); + } + + snprintf( state_change->service_group_name, + sizeof(state_change->service_group_name), + "%s", entity_name ); + + snprintf( state_change->entity_name, sizeof(state_change->entity_name), + "%s", entity_name ); + snprintf( state_change->reason_text, sizeof(state_change->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Service Group State Change +// ================================ +void sm_log_service_group_state_change( char entity_name[], + const char prev_state[], const char prev_status[], const char state[], + const char status[], const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + SmServiceDomainMemberT* domain_member; + SmLogThreadMsgT msg; + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + SmErrorT error; + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_LOG_THREAD_MSG_SERVICE_GROUP_STATE_CHANGE_LOG; + + clock_gettime( CLOCK_REALTIME, &(state_change->ts_real) ); + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY == error ) + { + snprintf( state_change->node_name, sizeof(state_change->node_name), + "%s", hostname ); + } + + domain_member + = sm_service_domain_member_table_read_service_group( entity_name ); + if( NULL != domain_member ) + { + snprintf( state_change->domain_name, sizeof(state_change->domain_name), + "%s", domain_member->name ); + } + + snprintf( state_change->service_group_name, + sizeof(state_change->service_group_name), + "%s", entity_name ); + + snprintf( state_change->entity_name, sizeof(state_change->entity_name), + "%s", entity_name ); + snprintf( state_change->prev_state, sizeof(state_change->prev_state), + "%s", prev_state ); + snprintf( state_change->prev_status, sizeof(state_change->prev_status), + "%s", prev_status ); + snprintf( state_change->state, sizeof(state_change->state), + "%s", state ); + snprintf( state_change->status, sizeof(state_change->status), + "%s", status ); + snprintf( state_change->reason_text, sizeof(state_change->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Service State Change +// ========================== +void sm_log_service_state_change( char entity_name[], + const char prev_state[], const char prev_status[], const char state[], + const char status[], const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + SmServiceDomainMemberT* domain_member; + SmServiceGroupMemberT* service_group_member; + SmLogThreadMsgT msg; + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + SmErrorT error; + + memset( &msg, 0, sizeof(msg) ); + + msg.type = SM_LOG_THREAD_MSG_SERVICE_STATE_CHANGE_LOG; + + clock_gettime( CLOCK_REALTIME, &(state_change->ts_real) ); + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY == error ) + { + snprintf( state_change->node_name, sizeof(state_change->node_name), + "%s", hostname ); + } + + service_group_member + = sm_service_group_member_table_read_by_service( entity_name ); + if( NULL != service_group_member ) + { + snprintf( state_change->service_group_name, + sizeof(state_change->service_group_name), + "%s", service_group_member->name ); + + domain_member + = sm_service_domain_member_table_read_service_group( + service_group_member->name ); + if( NULL != domain_member ) + { + snprintf( state_change->domain_name, + sizeof(state_change->domain_name), "%s", + domain_member->name ); + } + } + + snprintf( state_change->entity_name, sizeof(state_change->entity_name), + "%s", entity_name ); + snprintf( state_change->prev_state, sizeof(state_change->prev_state), + "%s", prev_state ); + snprintf( state_change->prev_status, sizeof(state_change->prev_status), + "%s", prev_status ); + snprintf( state_change->state, sizeof(state_change->state), + "%s", state ); + snprintf( state_change->status, sizeof(state_change->status), + "%s", status ); + snprintf( state_change->reason_text, sizeof(state_change->reason_text), + "%s", reason_text ); + + send( _client_fd, &msg, sizeof(msg), 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Initialize +// ================ +SmErrorT sm_log_initialize( void ) +{ + int flags; + int sockets[2]; + int buffer_len = 1048576; + int result; + SmErrorT error; + + result = socketpair( AF_UNIX, SOCK_DGRAM, 0, sockets ); + if( 0 > result ) + { + DPRINTFE( "Failed to create log communication sockets, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + int socket_i; + for( socket_i=0; socket_i < 2; ++socket_i ) + { + flags = fcntl( sockets[socket_i] , F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get log communication socket (%i) flags, " + "error=%s.", socket_i, strerror( errno ) ); + return( SM_FAILED ); + } + + result = fcntl( sockets[socket_i], F_SETFL, flags | O_NONBLOCK ); + if( 0 > result ) + { + DPRINTFE( "Failed to set log communication socket (%i) to " + "non-blocking, error=%s.", socket_i, + strerror( errno ) ); + return( SM_FAILED ); + } + + result = setsockopt( sockets[socket_i], SOL_SOCKET, SO_SNDBUF, + &buffer_len, sizeof(buffer_len) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set log communication socket (%i) " + "send buffer length (%i), error=%s.", socket_i, + buffer_len, strerror( errno ) ); + return( SM_FAILED ); + } + + result = setsockopt( sockets[socket_i], SOL_SOCKET, SO_RCVBUF, + &buffer_len, sizeof(buffer_len) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set log communication socket (%i) " + "receive buffer length (%i), error=%s.", socket_i, + buffer_len, strerror( errno ) ); + return( SM_FAILED ); + } + } + + _server_fd = sockets[0]; + _client_fd = sockets[1]; + + error = sm_log_thread_start( _server_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start log thread, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Log - Finalize +// ============== +SmErrorT sm_log_finalize( void ) +{ + SmErrorT error; + + error = sm_log_thread_stop(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop log thread, error=%s.", + sm_error_str( error ) ); + } + + if( -1 < _server_fd ) + { + close( _server_fd ); + _server_fd = -1; + } + + if( -1 < _client_fd ) + { + close( _client_fd ); + _client_fd = -1; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_log.h b/service-mgmt/sm-1.0.0/src/sm_log.h new file mode 100644 index 00000000..2d1f4052 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_log.h @@ -0,0 +1,96 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_LOG_H__ +#define __SM_LOG_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Log - Node Reboot +// ================= +extern void sm_log_node_reboot( char entity_name[], const char reason_text[], + bool forced ); +// **************************************************************************** + +// **************************************************************************** +// Log - Node State Change +// ======================= +extern void sm_log_node_state_change( char entity_name[], + const char prev_state[], const char state[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Log - Interface State Change +// ============================ +extern void sm_log_interface_state_change( char entity_name[], + const char prev_state[], const char state[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Log - Comunication State Change +// =============================== +extern void sm_log_communication_state_change( char entity_name[], + const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Log - Neighbor State Change +// =========================== +extern void sm_log_neighbor_state_change( char entity_name[], + const char prev_state[], const char state[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Log - Service Domain State Change +// ================================= +extern void sm_log_service_domain_state_change( char entity_name[], + const char prev_state[], const char state[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Log - Service Group Redundancy Change +// ===================================== +extern void sm_log_service_group_redundancy_change( char entity_name[], + const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Log - Service Group State Change +// ================================ +extern void sm_log_service_group_state_change( char entity_name[], + const char prev_state[], const char prev_status[], const char state[], + const char status[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Log - Service State Change +// ========================== +extern void sm_log_service_state_change( char entity_name[], + const char prev_state[], const char prev_status[], const char state[], + const char status[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Log - Initialize +// ================ +extern SmErrorT sm_log_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Log - Finalize +// ============== +extern SmErrorT sm_log_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_LOG_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_log_defs.h b/service-mgmt/sm-1.0.0/src/sm_log_defs.h new file mode 100644 index 00000000..52b0f0d5 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_log_defs.h @@ -0,0 +1,65 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_LOG_DEFINITIONS_H__ +#define __SM_LOG_DEFINITIONS_H__ + +#include + +#include "sm_limits.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef char SmLogNodeNameT[SM_NODE_NAME_MAX_CHAR]; + +typedef char SmLogDomainNameT[SM_LOG_DOMAIN_NAME_MAX_CHAR]; + +typedef char SmLogServiceGroupNameT[SM_LOG_SERVICE_GROUP_NAME_MAX_CHAR]; + +typedef char SmLogEntityNameT[SM_LOG_ENTITY_NAME_MAX_CHAR]; + +typedef enum +{ + SM_LOG_EVENT_TYPE_UNKNOWN, + SM_LOG_EVENT_TYPE_COMMUNICATIONS_ALARM, + SM_LOG_EVENT_TYPE_PROCESSING_ERROR_ALARM, + SM_LOG_EVENT_TYPE_ENVIRONMENTAL_ALARM, + SM_LOG_EVENT_TYPE_QUALITY_OF_SERVICE_ALARM, + SM_LOG_EVENT_TYPE_EQUIPMENT_ALARM, + SM_LOG_EVENT_TYPE_INTEGRITY_VIOLATION, + SM_LOG_EVENT_TYPE_OPERATIONAL_VIOLATION, + SM_LOG_EVENT_TYPE_PHYSICAL_VIOLATION, + SM_LOG_EVENT_TYPE_SECURITY_SERVICE_VIOLATION, + SM_LOG_EVENT_TYPE_MECHANISM_VIOLATION, + SM_LOG_EVENT_TYPE_TIME_DOMAIN_VIOLATION, + SM_LOG_EVENT_TYPE_MAX +} SmLogEventTypeT; + +typedef enum +{ + SM_LOG_UNKNOWN, + SM_LOG_SERVICE_GROUP_STATE, + SM_LOG_SERVICE_GROUP_REDUNDANCY, + SM_LOG_SOFTWARE_MODIFICATION, + SM_LOG_COMMUNICATION_FAILURE, + SM_LOG_SERVICE_STATE, + SM_LOG_NODE_STATE, + SM_LOG_MAX +} SmLogT; + +#define SM_LOG_SERVICE_GROUP_STATE_LOG_ID "401.001" +#define SM_LOG_SERVICE_GROUP_REDUNDANCY_LOG_ID "401.002" +#define SM_LOG_SOFTWARE_MODIFICATION_LOG_ID "401.004" +#define SM_LOG_COMMUNICATION_FAILURE_LOG_ID "401.005" +#define SM_LOG_SERVICE_STATE_LOG_ID "401.006" +#define SM_LOG_NODE_STATE_LOG_ID "401.007" + +#ifdef __cplusplus +} +#endif + +#endif // __SM_LOG_DEFINITIONS_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_log_thread.c b/service-mgmt/sm-1.0.0/src/sm_log_thread.c new file mode 100644 index 00000000..8632caed --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_log_thread.c @@ -0,0 +1,933 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_log_thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fm_api_wrapper.h" + +#include "sm_types.h" +#include "sm_list.h" +#include "sm_time.h" +#include "sm_selobj.h" +#include "sm_timer.h" +#include "sm_debug.h" +#include "sm_trap.h" +#include "sm_thread_health.h" + +#define SM_LOG_WRITE_BRIEF_LOGS + +#define SM_LOG_THREAD_NAME "sm_log" +#define SM_LOG_THREAD_LOG_REPORT_TIMER_IN_MS 5000 +#define SM_LOG_THREAD_TICK_INTERVAL_IN_MS 5000 +#define SM_LOG_CUSTOMER_LOG_FILE "/var/log/sm-customer.log" + +#define SM_LOG_ENTRY_INUSE 0xFDFDFDFD + +typedef struct +{ + uint32_t inuse; + SFmAlarmDataT fm_log_data; +} SmLogEntryT; + +static sig_atomic_t _stay_on; +static bool _thread_created = false; +static pthread_t _log_thread; +static SmTimerIdT _log_report_timer_id = SM_TIMER_ID_INVALID; +static int _server_fd = -1; +static bool _server_fd_registered = false; +static SmListT* _logs = NULL; +static SmLogEntryT _log_storage[SM_LOGS_MAX]; +static uint64_t _customer_log_id = 0; +static FILE * _customer_log = NULL; + +// **************************************************************************** +// Log Thread - Log String +// ======================= +static const char * sm_log_thread_log_str( SmLogT log ) +{ + switch( log ) + { + case SM_LOG_UNKNOWN: + return( "unknown" ); + break; + + case SM_LOG_SERVICE_GROUP_STATE: + return( "service-group-state" ); + break; + + case SM_LOG_SERVICE_GROUP_REDUNDANCY: + return( "service-group-redundancy" ); + break; + + case SM_LOG_SOFTWARE_MODIFICATION: + return( "software-modification" ); + break; + + case SM_LOG_COMMUNICATION_FAILURE: + return( "communication-failure" ); + break; + + default: + return ( "???" ); + break; + } + + return( "???" ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Get Fault Management Log Identifier +// ================================================ +static SmErrorT sm_log_thread_get_fm_log_id( SmLogT log, + const SmLogNodeNameT node_name, const SmLogDomainNameT domain_name, + const SmLogServiceGroupNameT service_group_name, + const SmLogEntityNameT entity_name, char fm_log_id[], + char fm_entity_type_id[], char fm_entity_instance_id[] ) +{ + switch( log ) + { + case SM_LOG_SERVICE_GROUP_STATE: + snprintf( fm_log_id, FM_MAX_BUFFER_LENGTH, + SM_LOG_SERVICE_GROUP_STATE_LOG_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, + "service_domain.service_group.host" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "service_domain=%s.service_group=%s.host=%s", + domain_name, entity_name, node_name ); + break; + + case SM_LOG_SERVICE_GROUP_REDUNDANCY: + snprintf( fm_log_id, FM_MAX_BUFFER_LENGTH, + SM_LOG_SERVICE_GROUP_REDUNDANCY_LOG_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, + "service_domain.service_group" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "service_domain=%s.service_group=%s", + domain_name, entity_name ); + break; + + case SM_LOG_NODE_STATE: + snprintf( fm_log_id, FM_MAX_BUFFER_LENGTH, + SM_LOG_NODE_STATE_LOG_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, "host" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "host=%s", node_name ); + break; + + case SM_LOG_SOFTWARE_MODIFICATION: + snprintf( fm_log_id, FM_MAX_BUFFER_LENGTH, + SM_LOG_SOFTWARE_MODIFICATION_LOG_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, "host" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "host=%s", node_name ); + break; + + case SM_LOG_COMMUNICATION_FAILURE: + snprintf( fm_log_id, FM_MAX_BUFFER_LENGTH, + SM_LOG_COMMUNICATION_FAILURE_LOG_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, + "host.network" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "host=%s.network=%s", node_name, + entity_name ); + break; + + case SM_LOG_SERVICE_STATE: + snprintf( fm_log_id, FM_MAX_BUFFER_LENGTH, + SM_LOG_SERVICE_STATE_LOG_ID ); + snprintf( fm_entity_type_id, FM_MAX_BUFFER_LENGTH, + "service_domain.service_group.service.host" ); + snprintf( fm_entity_instance_id, FM_MAX_BUFFER_LENGTH, + "service_domain=%s.service_group=%s.service=%s.host=%s", + domain_name, service_group_name, entity_name, node_name ); + break; + + default: + DPRINTFE( "Unknown log (%i).", log ); + return( SM_FAILED ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Get Fault Management Log Type +// ========================================== +static EFmAlarmTypeT sm_log_thread_get_fm_log_type( SmLogEventTypeT event_type ) +{ + switch( event_type ) + { + case SM_LOG_EVENT_TYPE_UNKNOWN: + return( FM_ALARM_TYPE_UNKNOWN ); + break; + + case SM_LOG_EVENT_TYPE_COMMUNICATIONS_ALARM: + return( FM_ALARM_COMM ); + break; + + case SM_LOG_EVENT_TYPE_PROCESSING_ERROR_ALARM: + return( FM_ALARM_PROCESSING_ERROR ); + break; + + case SM_LOG_EVENT_TYPE_ENVIRONMENTAL_ALARM: + return( FM_ALARM_ENVIRONMENTAL ); + break; + + case SM_LOG_EVENT_TYPE_QUALITY_OF_SERVICE_ALARM: + return( FM_ALARM_QOS ); + break; + + case SM_LOG_EVENT_TYPE_EQUIPMENT_ALARM: + return( FM_ALARM_EQUIPMENT ); + break; + + case SM_LOG_EVENT_TYPE_INTEGRITY_VIOLATION: + return( FM_ALARM_INTERGRITY ); + break; + + case SM_LOG_EVENT_TYPE_OPERATIONAL_VIOLATION: + return( FM_ALARM_OPERATIONAL ); + break; + + case SM_LOG_EVENT_TYPE_PHYSICAL_VIOLATION: + return( FM_ALARM_PHYSICAL ); + break; + + case SM_LOG_EVENT_TYPE_SECURITY_SERVICE_VIOLATION: + return( FM_ALARM_SECURITY ); + break; + + case SM_LOG_EVENT_TYPE_MECHANISM_VIOLATION: + return( FM_ALARM_SECURITY ); + break; + + case SM_LOG_EVENT_TYPE_TIME_DOMAIN_VIOLATION: + return( FM_ALARM_TIME ); + break; + + default: + DPRINTFI( "Unknown event type (%i).", event_type ); + return( FM_ALARM_TYPE_UNKNOWN ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Log Brief Header +// ============================= +static void sm_log_thread_log_brief_header( void ) +{ + // Output the brief log header every so many logs. + if( 0 == ( _customer_log_id % 512 ) ) + { + fprintf( _customer_log, "+-------------------------+------------+----------------------+----------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------\n" ); + fprintf( _customer_log, "| timestamp | log-id | log-type | entity-name | from-state | to-state | reason \n" ); + fprintf( _customer_log, "+-------------------------+------------+----------------------+----------------------------------+----------------------------------+----------------------------------+---------------------------------------------------------------------------\n" ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Log Brief +// ====================== +static void sm_log_thread_log_brief( const char time[], const char type[], + const char entity_name[], const char prev_state_change[], + const char state_change[], + char reason_text[] ) +{ + fprintf( _customer_log, "| %s | %10"PRIu64" | %-20s | %-32s | " + "%-32s | %-32s | %-s \n", time, ++_customer_log_id, type, + entity_name, prev_state_change, state_change, reason_text ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Log Reboot +// ======================= +static void sm_log_thread_log_reboot( const char reboot_type[], + SmLogThreadMsgRebootLogT* reboot ) +{ + char time_str[80]; + char date_str[32]; + struct tm t_real; + + if( NULL == localtime_r( &(reboot->ts_real.tv_sec), &t_real ) ) + { + snprintf( time_str, sizeof(time_str), "YYYY:MM:DD HH:MM:SS.xxx" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + snprintf( time_str, sizeof(time_str), "%s.%03ld", date_str, + reboot->ts_real.tv_nsec/1000000 ); + } + +#ifdef SM_LOG_WRITE_BRIEF_LOGS + sm_log_thread_log_brief_header(); + + sm_log_thread_log_brief( time_str, reboot_type, reboot->entity_name, + "", "", reboot->reason_text ); +#else + fprintf( _customer_log, "log-id: %"PRIu64"\n", ++_customer_log_id ); + fprintf( _customer_log, "log-type: reboot\n" ); + fprintf( _customer_log, "timestamp: %s\n", time_str ); + fprintf( _customer_log, "entity-name: %s\n", reboot->entity_name ); + fprintf( _customer_log, "reason-text: %s\n\n", reboot->reason_text ); +#endif // SM_LOG_WRITE_BRIEF_LOGS + + fflush( _customer_log ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Log State Change +// ============================= +static void sm_log_thread_log_state_change( const char state_change_type[], + SmLogThreadMsgStateChangeLogT* state_change ) +{ + char time_str[80]; + char prev_state_change_str[80]; + char state_change_str[80]; + char date_str[32]; + struct tm t_real; + + if( NULL == localtime_r( &(state_change->ts_real.tv_sec), &t_real ) ) + { + snprintf( time_str, sizeof(time_str), "YYYY:MM:DD HH:MM:SS.xxx" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + snprintf( time_str, sizeof(time_str), "%s.%03ld", date_str, + state_change->ts_real.tv_nsec/1000000 ); + } + + snprintf( prev_state_change_str, sizeof(prev_state_change_str), "%s%s%s", + state_change->prev_state, + ('\0' == state_change->prev_status[0]) ? "" : "-", + ('\0' == state_change->prev_status[0]) ? "" : state_change->prev_status ); + + snprintf( state_change_str, sizeof(state_change_str), "%s%s%s", + state_change->state, + ('\0' == state_change->status[0]) ? "" : "-", + ('\0' == state_change->status[0]) ? "" : state_change->status ); + +#ifdef SM_LOG_WRITE_BRIEF_LOGS + sm_log_thread_log_brief_header(); + + sm_log_thread_log_brief( time_str, state_change_type, + state_change->entity_name, + prev_state_change_str, state_change_str, + state_change->reason_text ); +#else + fprintf( _customer_log, "log-id: %"PRIu64"\n", ++_customer_log_id ); + fprintf( _customer_log, "log-type: state-change\n" ); + fprintf( _customer_log, "timestamp: %s\n", time_str ); + fprintf( _customer_log, "entity-name: %s\n", state_change->entity_name ); + fprintf( _customer_log, "previous-state: %s\n", state_change->prev_state ); + fprintf( _customer_log, "previous-status: %s\n", + ('\0' == state_change->prev_status[0]) ? "" : state_change->prev_status ); + fprintf( _customer_log, "current-state: %s\n", state_change->state ); + fprintf( _customer_log, "current-status: %s\n", + ('\0' == state_change->status[0]) ? "" : state_change->status ); + fprintf( _customer_log, "reason-text: %s\n\n", state_change->reason_text ); +#endif // SM_LOG_WRITE_BRIEF_LOGS + + fflush( _customer_log ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Log Generate +// ========================= +static void sm_log_thread_log_generate( SmLogT log, SmLogNodeNameT node_name, + SmLogDomainNameT domain_name, SmLogServiceGroupNameT service_group_name, + SmLogEntityNameT entity_name, SmLogEventTypeT event_type, + const char log_text[] ) +{ + struct timeval tv; + SmLogEntryT* log_entry; + SFmAlarmDataT* fm_log_data; + SmErrorT error; + + memset(&tv,0,sizeof(tv)); + + unsigned int log_entry_i; + for( log_entry_i=0; SM_LOGS_MAX > log_entry_i; ++log_entry_i ) + { + log_entry = &(_log_storage[log_entry_i]); + + if( SM_LOG_ENTRY_INUSE != log_entry->inuse ) + break; + } + + if( SM_LOGS_MAX <= log_entry_i ) + { + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + + SM_LIST_FIRST( _logs, entry, entry_data ); + + DPRINTFI( "Max logs (%i) buffered has been reached, deleting oldest", + SM_LOGS_MAX ); + + SM_LIST_REMOVE( _logs, (SmListEntryDataPtrT) entry_data ); + log_entry = (SmLogEntryT*) entry_data; + } + + memset( log_entry, 0, sizeof(SmLogEntryT) ); + fm_log_data = &(log_entry->fm_log_data); + + error = sm_log_thread_get_fm_log_id( log, node_name, domain_name, + service_group_name, entity_name, fm_log_data->alarm_id, + fm_log_data->entity_type_id, fm_log_data->entity_instance_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get log (%s) data for node (%s) domain (%s) " + "service-group (%s) entity (%s), error=%s.", + sm_log_thread_log_str( log ), node_name, domain_name, + service_group_name, entity_name, sm_error_str( error ) ); + return; + } + + fm_log_data->alarm_state = FM_ALARM_STATE_MSG; + fm_log_data->severity = FM_ALARM_SEVERITY_CRITICAL; + + snprintf( fm_log_data->reason_text, sizeof(fm_log_data->reason_text), + "%s", log_text ); + + if( isalpha( fm_log_data->reason_text[0] ) ) + { + fm_log_data->reason_text[0] = toupper( fm_log_data->reason_text[0] ); + } + + if( 0 == gettimeofday( &tv, NULL ) ) + { + fm_log_data->timestamp = ((((FMTimeT)tv.tv_sec) * 1000000) + + ((FMTimeT)tv.tv_usec)); + } else { + DPRINTFE( "Failed to get time of day, errno=%s.", strerror( errno ) ); + } + + fm_log_data->alarm_type = sm_log_thread_get_fm_log_type( event_type ); + fm_log_data->probable_cause = FM_ALARM_UNSPECIFIED_REASON; + fm_log_data->proposed_repair_action[0] = '\0'; + fm_log_data->service_affecting = FM_TRUE; + fm_log_data->suppression = FM_TRUE; + fm_log_data->inhibit_alarms = FM_FALSE; + + log_entry->inuse = SM_LOG_ENTRY_INUSE; + SM_LIST_APPEND( _logs, (SmListEntryDataPtrT) log_entry ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Report +// =================== +static void sm_log_thread_report( void ) +{ + SmListT* entry = NULL; + SmListT* next = NULL; + SmListEntryDataPtrT entry_data; + SmLogEntryT* log_entry; + fm_uuid_t fm_uuid; + EFmErrorT fm_error; + + SM_LIST_FOREACH_SAFE( _logs, entry, next, entry_data ) + { + log_entry = (SmLogEntryT*) entry_data; + + fm_error = fm_set_fault_wrapper( &(log_entry->fm_log_data), &fm_uuid ); + if( FM_ERR_OK == fm_error ) + { + DPRINTFD( "Set log (%s) for entity (%s), reason_text=%s.", + log_entry->fm_log_data.alarm_id, + log_entry->fm_log_data.entity_instance_id, + log_entry->fm_log_data.reason_text ); + } else { + DPRINTFE( "Failed to set log (%s) for entity (%s), error=%i", + log_entry->fm_log_data.alarm_id, + log_entry->fm_log_data.entity_instance_id, fm_error ); + return; + } + + memset( log_entry, 0, sizeof(SmLogEntryT) ); + SM_LIST_REMOVE( _logs,(SmListEntryDataPtrT) log_entry ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Dispatch +// ===================== +static void sm_log_thread_dispatch( int selobj, int64_t user_data ) +{ + bool report = false; + char prev_state_change_str[80]; + char state_change_str[80]; + char log_text[1024] = ""; + int bytes_read; + SmLogThreadMsgT msg; + SmLogThreadMsgRebootLogT* reboot = &(msg.u.reboot); + SmLogThreadMsgStateChangeLogT* state_change = &(msg.u.state_change); + + memset( &msg, 0, sizeof(msg) ); + + int retry_count; + for( retry_count = 5; retry_count != 0; --retry_count ) + { + bytes_read = recv( selobj, &msg, sizeof(msg), 0 ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_count, strerror( errno ) ); + } + + switch( msg.type ) + { + case SM_LOG_THREAD_MSG_NODE_REBOOT_LOG: + sm_log_thread_log_reboot( "node-reboot", reboot ); + break; + + case SM_LOG_THREAD_MSG_NODE_REBOOT_FORCE_LOG: + sm_log_thread_log_reboot( "node-reboot-force", reboot ); + break; + + case SM_LOG_THREAD_MSG_NODE_STATE_CHANGE_LOG: + sm_log_thread_log_state_change( "node-scn", state_change ); + + if( 0 == strcmp( "swact", state_change->state ) ) + { + snprintf( log_text, sizeof(log_text), "Swact %s", + state_change->reason_text ); + + sm_log_thread_log_generate( SM_LOG_NODE_STATE, + state_change->node_name, state_change->domain_name, + state_change->service_group_name, state_change->entity_name, + SM_LOG_EVENT_TYPE_PROCESSING_ERROR_ALARM, log_text ); + + report = true; + + } else if( 0 == strcmp( "swact-force", state_change->state ) ) { + snprintf( log_text, sizeof(log_text), "Swact-Force %s", + state_change->reason_text ); + + sm_log_thread_log_generate( SM_LOG_NODE_STATE, + state_change->node_name, state_change->domain_name, + state_change->service_group_name, state_change->entity_name, + SM_LOG_EVENT_TYPE_PROCESSING_ERROR_ALARM, log_text ); + + report = true; + } + break; + + case SM_LOG_THREAD_MSG_INTERFACE_STATE_CHANGE_LOG: + sm_log_thread_log_state_change( "interface-scn", state_change ); + break; + + case SM_LOG_THREAD_MSG_COMMUNICATION_STATE_CHANGE_LOG: + sm_log_thread_log_generate( SM_LOG_COMMUNICATION_FAILURE, + state_change->node_name, state_change->domain_name, + state_change->service_group_name, state_change->entity_name, + SM_LOG_EVENT_TYPE_PROCESSING_ERROR_ALARM, + state_change->reason_text ); + + report = true; + break; + + case SM_LOG_THREAD_MSG_NEIGHBOR_STATE_CHANGE_LOG: + sm_log_thread_log_state_change( "neighbor-scn", state_change ); + break; + + case SM_LOG_THREAD_MSG_SERVICE_DOMAIN_STATE_CHANGE_LOG: + sm_log_thread_log_state_change( "service-domain-scn", state_change ); + break; + + case SM_LOG_THREAD_MSG_SERVICE_GROUP_REDUNDANCY_CHANGE_LOG: + sm_log_thread_log_generate( SM_LOG_SERVICE_GROUP_REDUNDANCY, + state_change->node_name, state_change->domain_name, + state_change->service_group_name, state_change->entity_name, + SM_LOG_EVENT_TYPE_PROCESSING_ERROR_ALARM, + state_change->reason_text ); + + report = true; + break; + + case SM_LOG_THREAD_MSG_SERVICE_GROUP_STATE_CHANGE_LOG: + sm_log_thread_log_state_change( "service-group-scn", state_change ); + + snprintf( prev_state_change_str, sizeof(prev_state_change_str), + "%s%s%s", state_change->prev_state, + ('\0' == state_change->prev_status[0]) ? "" : "-", + ('\0' == state_change->prev_status[0]) ? "" : + state_change->prev_status ); + + snprintf( state_change_str, sizeof(state_change_str), "%s%s%s", + state_change->state, + ('\0' == state_change->status[0]) ? "" : "-", + ('\0' == state_change->status[0]) ? "" : + state_change->status ); + + if(( 0 == strcmp( sm_service_group_status_str( + SM_SERVICE_GROUP_STATUS_WARN ), + state_change->status ) ) || + ( 0 == strcmp( sm_service_group_status_str( + SM_SERVICE_GROUP_STATUS_DEGRADED ), + state_change->status ) ) || + ( 0 == strcmp( sm_service_group_status_str( + SM_SERVICE_GROUP_STATUS_FAILED ), + state_change->status ) )) + { + snprintf( log_text, sizeof(log_text), + "Service group %s state change from %s to %s on " + "host %s; %s", state_change->entity_name, + prev_state_change_str, state_change_str, + state_change->node_name, state_change->reason_text ); + } else { + snprintf( log_text, sizeof(log_text), + "Service group %s state change from %s to %s on " + "host %s", + state_change->entity_name, prev_state_change_str, + state_change_str, state_change->node_name ); + } + + sm_log_thread_log_generate( SM_LOG_SERVICE_GROUP_STATE, + state_change->node_name, state_change->domain_name, + state_change->service_group_name, state_change->entity_name, + SM_LOG_EVENT_TYPE_PROCESSING_ERROR_ALARM, log_text ); + + report = true; + break; + + case SM_LOG_THREAD_MSG_SERVICE_STATE_CHANGE_LOG: + sm_log_thread_log_state_change( "service-scn", state_change ); + break; + + default: + DPRINTFE( "Unknown message (%i) received.", msg.type ); + return; + break; + } + + if( report ) + sm_log_thread_report(); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Report Timer +// ========================= +static bool sm_log_thread_report_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + sm_log_thread_report(); + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Initialize Thread +// ============================== +static SmErrorT sm_log_thread_initialize_thread( void ) +{ + SmErrorT error; + + _server_fd_registered = false; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + if( -1 < _server_fd ) + { + error = sm_selobj_register( _server_fd, sm_log_thread_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + _server_fd_registered = true; + } + + error = sm_timer_initialize( SM_LOG_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_register( "log report", + SM_LOG_THREAD_LOG_REPORT_TIMER_IN_MS, + sm_log_thread_report_timer, 0, + &_log_report_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create log report timer, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + if( NULL != _customer_log ) + { + fflush( _customer_log ); + fclose( _customer_log ); + _customer_log = NULL; + } + + _customer_log = fopen( SM_LOG_CUSTOMER_LOG_FILE, "a" ); + if( NULL == _customer_log ) + { + DPRINTFE( "Failed to open customer log file (%s).", + SM_LOG_CUSTOMER_LOG_FILE ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Finalize Thread +// ============================ +static SmErrorT sm_log_thread_finalize_thread( void ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != _log_report_timer_id ) + { + error = sm_timer_deregister( _log_report_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel log report timer, error=%s.", + sm_error_str( error ) ); + } + + _log_report_timer_id = SM_TIMER_ID_INVALID; + } + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize timer module, error=%s.", + sm_error_str( error ) ); + } + + if( _server_fd_registered ) + { + error = sm_selobj_deregister( _server_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + _server_fd_registered = false; + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + if( NULL != _customer_log ) + { + fflush( _customer_log ); + fclose( _customer_log ); + _customer_log = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Main +// ================= +static void* sm_log_thread_main( void* arguments ) +{ + SmErrorT error; + + pthread_setname_np( pthread_self(), SM_LOG_THREAD_NAME ); + sm_debug_set_thread_info(); + sm_trap_set_thread_info(); + + DPRINTFI( "Starting" ); + + // Warn after 60 seconds, fail after 16 minutes. + error = sm_thread_health_register( SM_LOG_THREAD_NAME, 60000, 1000000 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register log thread, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + error = sm_log_thread_initialize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize log thread, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + DPRINTFI( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_LOG_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + + error = sm_thread_health_update( SM_LOG_THREAD_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update log thread health, error=%s.", + sm_error_str(error) ); + } + } + + DPRINTFI( "Shutting down." ); + + error = sm_log_thread_finalize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize log thread, error=%s.", + sm_error_str( error ) ); + } + + error = sm_thread_health_deregister( SM_LOG_THREAD_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister log thread, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Start +// ================== +SmErrorT sm_log_thread_start( int server_fd ) +{ + int result; + + _logs = NULL; + memset( _log_storage, 0, sizeof(_log_storage) ); + + _stay_on = 1; + _thread_created = false; + _server_fd = server_fd; + + result = pthread_create( &_log_thread, NULL, sm_log_thread_main, NULL ); + if( 0 != result ) + { + DPRINTFE( "Failed to start log thread, error=%s.", + strerror(result) ); + return( SM_FAILED ); + } + + _thread_created = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Stop +// ================= +SmErrorT sm_log_thread_stop( void ) +{ + _stay_on = 0; + + if( _thread_created ) + { + long ms_expired; + SmTimeT time_prev; + int result; + + sm_time_get( &time_prev ); + + while( true ) + { + result = pthread_tryjoin_np( _log_thread, NULL ); + if(( 0 != result )&&( EBUSY != result )) + { + if(( ESRCH != result )&&( EINVAL != result )) + { + DPRINTFE( "Failed to wait for log thread exit, " + "sending kill signal, error=%s.", + strerror(result) ); + pthread_kill( _log_thread, SIGKILL ); + } + break; + } + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( 5000 <= ms_expired ) + { + DPRINTFE( "Failed to stop log thread, sending " + "kill signal." ); + pthread_kill( _log_thread, SIGKILL ); + break; + } + + usleep( 250000 ); // 250 milliseconds. + } + } + + _server_fd = -1; + _thread_created = false; + + memset( _log_storage, 0, sizeof(_log_storage) ); + SM_LIST_CLEANUP_ALL( _logs ); + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_log_thread.h b/service-mgmt/sm-1.0.0/src/sm_log_thread.h new file mode 100644 index 00000000..795b5f34 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_log_thread.h @@ -0,0 +1,85 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_LOG_THREAD_H__ +#define __SM_LOG_THREAD_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_log_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + SM_LOG_THREAD_MSG_NODE_REBOOT_LOG, + SM_LOG_THREAD_MSG_NODE_REBOOT_FORCE_LOG, + SM_LOG_THREAD_MSG_NODE_STATE_CHANGE_LOG, + SM_LOG_THREAD_MSG_LICENSE_CHANGE_LOG, + SM_LOG_THREAD_MSG_COMMUNICATION_STATE_CHANGE_LOG, + SM_LOG_THREAD_MSG_INTERFACE_STATE_CHANGE_LOG, + SM_LOG_THREAD_MSG_NEIGHBOR_STATE_CHANGE_LOG, + SM_LOG_THREAD_MSG_SERVICE_DOMAIN_STATE_CHANGE_LOG, + SM_LOG_THREAD_MSG_SERVICE_GROUP_REDUNDANCY_CHANGE_LOG, + SM_LOG_THREAD_MSG_SERVICE_GROUP_STATE_CHANGE_LOG, + SM_LOG_THREAD_MSG_SERVICE_STATE_CHANGE_LOG, +} SmLogThreadMsgTypeT; + +typedef struct +{ + struct timespec ts_real; + SmLogNodeNameT node_name; + SmLogEntityNameT entity_name; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR]; +} SmLogThreadMsgRebootLogT; + +typedef struct +{ + struct timespec ts_real; + SmLogNodeNameT node_name; + SmLogDomainNameT domain_name; + SmLogServiceGroupNameT service_group_name; + SmLogEntityNameT entity_name; + char prev_state[SM_LOG_ENTITY_STATE_MAX_CHAR]; + char prev_status[SM_LOG_ENTITY_STATUS_MAX_CHAR]; + char prev_condition[SM_LOG_ENTITY_CONDITION_MAX_CHAR]; + char state[SM_LOG_ENTITY_STATE_MAX_CHAR]; + char status[SM_LOG_ENTITY_STATUS_MAX_CHAR]; + char condition[SM_LOG_ENTITY_CONDITION_MAX_CHAR]; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR]; +} SmLogThreadMsgStateChangeLogT; + +typedef struct +{ + SmLogThreadMsgTypeT type; + + union + { + SmLogThreadMsgRebootLogT reboot; + SmLogThreadMsgStateChangeLogT state_change; + } u; +} SmLogThreadMsgT; + +// **************************************************************************** +// Log Thread - Start +// ================== +extern SmErrorT sm_log_thread_start( int server_fd ); +// **************************************************************************** + +// **************************************************************************** +// Log Thread - Stop +// ================= +extern SmErrorT sm_log_thread_stop( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_LOG_THREAD_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_main_event_handler.c b/service-mgmt/sm-1.0.0/src/sm_main_event_handler.c new file mode 100644 index 00000000..501945e3 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_main_event_handler.c @@ -0,0 +1,480 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_main_event_handler.h" + +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_utils.h" +#include "sm_api.h" +#include "sm_notify_api.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_groups.h" +#include "sm_service_group_table.h" +#include "sm_node_api.h" +#include "sm_service_domain_interface_api.h" +#include "sm_service_group_api.h" +#include "sm_service_api.h" +#include "sm_failover.h" +#include "sm_node_swact_monitor.h" + +#define SM_NODE_AUDIT_TIMER_IN_MS 1000 +#define SM_INTERFACE_AUDIT_TIMER_IN_MS 1000 + +static SmDbHandleT* _sm_db_handle = NULL; +static SmApiCallbacksT _api_callbacks = {0}; +static SmNotifyApiCallbacksT _notify_api_callbacks = {0}; +static SmTimerIdT _node_audit_timer_id = SM_TIMER_ID_INVALID; +static SmTimerIdT _interface_audit_timer_id = SM_TIMER_ID_INVALID; + +// **************************************************************************** +// Main Event Handler - Audit Node +// =============================== +static bool sm_main_event_handler_audit_node( SmTimerIdT timer_id, + int64_t user_data ) +{ + bool complete; + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", sm_error_str( error ) ); + return( true ); + } + + error = sm_node_api_config_complete( hostname, &complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if configuration is complete, " + "error=%s.", sm_error_str( error ) ); + return( true ); + } + + if( complete ) + { + error = sm_node_api_add_node( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to add node to database, error=%s.", + sm_error_str( error ) ); + return( true ); + } + + error = sm_node_api_audit(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit nodes, error=%s.", + sm_error_str( error ) ); + return( true ); + } + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Audit Interfaces +// ===================================== +static bool sm_main_event_handler_audit_interfaces( SmTimerIdT timer_id, + int64_t user_data ) +{ + SmErrorT error; + + error = sm_service_domain_interface_api_audit(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit interfaces, error=%s.", + sm_error_str( error ) ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Release Service Group +// ========================================== +static SmErrorT sm_main_event_handler_release_service_group( + void* user_data[], void* record ) +{ + SmDbServiceGroupT* service_group = (SmDbServiceGroupT*) record; + SmErrorT error; + + error = sm_service_group_api_go_active( service_group->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform go-active action on member (%s), " + "error=%s.", service_group->name, sm_error_str(error) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Release Service Groups +// =========================================== +static SmErrorT sm_main_event_handler_release_service_groups( void ) +{ + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbServiceGroupT service_group; + SmErrorT error; + + snprintf( db_query, sizeof(db_query), "%s = 'yes'", + SM_SERVICE_GROUPS_TABLE_COLUMN_AUTO_RECOVER ); + + error = sm_db_foreach( SM_DATABASE_NAME, SM_SERVICE_GROUPS_TABLE_NAME, + db_query, &service_group, + &sm_db_service_groups_convert, + sm_main_event_handler_release_service_group, + NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service groups, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - API Node Set Callback +// ========================================== +static void sm_main_event_handler_api_node_set_callback( char node_name[], + SmNodeSetActionT action, SmNodeAdminStateT admin_state, + SmNodeOperationalStateT oper_state, SmNodeAvailStatusT avail_status, + int seqno ) +{ + SmErrorT error; + + DPRINTFI( "Set node (%s) requested, action=%i, admin_state=%s, " + "oper_state=%s, avail_status=%s, seqno=%i.", node_name, action, + sm_node_admin_state_str(admin_state), + sm_node_oper_state_str(oper_state), + sm_node_avail_status_str(avail_status), seqno ); + + error = sm_node_api_update_node( node_name, admin_state, oper_state, + avail_status ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update node (%s), seqno=%i, error=%s.", + node_name, seqno, sm_error_str(error) ); + return; + } + + if( SM_NODE_SET_ACTION_SWACT == action ) + { + SmNodeSwactMonitor::SwactStart(SM_NODE_STATE_STANDBY); + error = sm_node_api_swact( node_name, false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to swact node (%s), seqno=%i, error=%s.", + node_name, seqno, sm_error_str(error) ); + return; + } + } else if( SM_NODE_SET_ACTION_SWACT_FORCE == action ) { + SmNodeSwactMonitor::SwactStart(SM_NODE_STATE_STANDBY); + error = sm_node_api_swact( node_name, true ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to swact force node (%s), seqno=%i, error=%s.", + node_name, seqno, sm_error_str(error) ); + return; + } + } + + error = sm_api_send_node_set_ack( node_name, action, admin_state, + oper_state, avail_status, seqno ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send node (%s) set ack, seqno=%i, error=%s.", + node_name, seqno, sm_error_str(error) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - API Service Restart Callback +// ================================================= +static void sm_main_event_handler_api_service_restart_callback( + char service_name[], int seqno, int flag ) +{ + DPRINTFI( "Service (%s) restart requested, seqno=%i, flag=%i.", + service_name, seqno, flag ); + + sm_service_api_restart( service_name, flag ); +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Notify API Service Event Callback +// ====================================================== +static void sm_main_event_handler_notify_api_service_event_callback( + char service_name[], SmNotifyServiceEventT event ) +{ + DPRINTFI( "Received notification event %i for service %s.", event, + service_name ); + + sm_service_api_audit( service_name ); +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Reload Data +// ================================ +void sm_main_event_handler_reload_data( void ) +{ +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Service Group Degraded Count +// ================================================= +static void sm_main_event_handler_service_group_degraded_count( + void* user_data[], SmServiceGroupT* service_group ) +{ + int* degrade_count = (int*) user_data[0]; + + if( SM_SERVICE_GROUP_STATUS_DEGRADED == service_group->status ) + { + *degrade_count = *degrade_count + 1; + } +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Service Group State Callback +// ================================================= +static void sm_main_event_handler_service_group_state_callback( + char service_group_name[], SmServiceGroupStateT state, + SmServiceGroupStatusT status, SmServiceGroupConditionT condition, + int64_t health, const char reason_text[] ) +{ + int degrade_count = 0; + void* user_data[] = { °rade_count }; + + sm_service_group_table_foreach( user_data, + sm_main_event_handler_service_group_degraded_count ); + + if( 0 < degrade_count ) + { + sm_failover_degrade(SM_FAILOVER_DEGRADE_SOURCE_SERVICE_GROUP); + } else { + sm_failover_degrade_clear(SM_FAILOVER_DEGRADE_SOURCE_SERVICE_GROUP); + } +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Initialize +// =============================== +SmErrorT sm_main_event_handler_initialize( void ) +{ + SmErrorT error; + + memset( &_api_callbacks, 0, sizeof(_api_callbacks) ); + memset( &_notify_api_callbacks, 0, sizeof(_notify_api_callbacks) ); + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_timer_register( "node audit", + SM_NODE_AUDIT_TIMER_IN_MS, + sm_main_event_handler_audit_node, + 0, &_node_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create node audit timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_timer_register( "interface audit", + SM_INTERFACE_AUDIT_TIMER_IN_MS, + sm_main_event_handler_audit_interfaces, + 0, &_interface_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create interface audit timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_api_abort_actions(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup service actions, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_node_api_audit(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit nodes, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_main_event_handler_release_service_groups(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to release service groups, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_api_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize api, error=%s.", + sm_error_str(error) ); + return( error ); + } + + _api_callbacks.node_set + = sm_main_event_handler_api_node_set_callback; + _api_callbacks.service_restart + = sm_main_event_handler_api_service_restart_callback; + + error = sm_api_register_callbacks( &_api_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register api callbacks, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_notify_api_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize notify api, error=%s.", + sm_error_str(error) ); + return( error ); + } + + _notify_api_callbacks.service_event + = sm_main_event_handler_notify_api_service_event_callback; + + error = sm_notify_api_register_callbacks( &_notify_api_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register notify api callbacks, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_api_register_callback( + sm_main_event_handler_service_group_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for service group state callbacks, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Finalize +// ============================= +SmErrorT sm_main_event_handler_finalize( void ) +{ + SmErrorT error; + + error = sm_service_group_api_deregister_callback( + sm_main_event_handler_service_group_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for service group state callbacks, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_notify_api_deregister_callbacks( &_notify_api_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister notify api callbacks, error=%s.", + sm_error_str( error ) ); + } + + error = sm_notify_api_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize notify api, error=%s.", + sm_error_str( error ) ); + } + + error = sm_api_deregister_callbacks( &_api_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister api callbacks, error=%s.", + sm_error_str( error ) ); + } + + error = sm_api_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize api, error=%s.", sm_error_str( error ) ); + } + + if( SM_TIMER_ID_INVALID != _node_audit_timer_id ) + { + error = sm_timer_deregister( _node_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel node audit timer, error=%s.", + sm_error_str( error ) ); + } + + _node_audit_timer_id = SM_TIMER_ID_INVALID; + } + + if( SM_TIMER_ID_INVALID != _interface_audit_timer_id ) + { + error = sm_timer_deregister( _interface_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel interface audit timer, error=%s.", + sm_error_str( error ) ); + } + + _interface_audit_timer_id = SM_TIMER_ID_INVALID; + } + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_main_event_handler.h b/service-mgmt/sm-1.0.0/src/sm_main_event_handler.h new file mode 100644 index 00000000..fec81ee8 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_main_event_handler.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_MAIN_EVENT_HANDLER_H__ +#define __SM_MAIN_EVENT_HANDLER_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Main Event Handler - Reload Data +// ================================ +extern void sm_main_event_handler_reload_data( void ); +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Initialize +// =============================== +extern SmErrorT sm_main_event_handler_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Main Event Handler - Finalize +// ============================= +extern SmErrorT sm_main_event_handler_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_MAIN_EVENT_HANDLER_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_msg.c b/service-mgmt/sm-1.0.0/src/sm_msg.c new file mode 100644 index 00000000..29ad5194 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_msg.c @@ -0,0 +1,3387 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_msg.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_selobj.h" +#include "sm_uuid.h" +#include "sm_sha512.h" +#include "sm_hw.h" +#include "sm_node_utils.h" +#include "sm_db.h" +#include "sm_db_service_domain_interfaces.h" + +#define SM_MSG_VERSION 1 +#define SM_MSG_REVISION 1 +#define SM_MSG_FLAG_ACK 0x1 +#define SM_MSG_MAX_SIZE 1024 +#define SM_MSG_BUFFER_MAX_SIZE 4096 +#define SM_MSG_MAX_SEQ_DELTA 1000 + +#if __BYTE_ORDER == __BIG_ENDIAN +#define ntohll(x) (x) +#define htonll(x) (x) +#else +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define ntohll(x) sm_msg_little_endian_ntohll(x) +# define htonll(x) sm_msg_little_endian_htonll(x) +# endif +#endif + +#define _MSG_NOT_SENT_TO_TARGET -128 +typedef enum +{ + SM_MSG_TYPE_UNKNOWN = 0x0, + SM_MSG_TYPE_NODE_HELLO = 0x1, + SM_MSG_TYPE_NODE_UPDATE = 0x2, + SM_MSG_TYPE_NODE_SWACT = 0x3, + SM_MSG_TYPE_NODE_SWACT_ACK = 0x4, + SM_MSG_TYPE_SERVICE_DOMAIN_HELLO = 0x5, + SM_MSG_TYPE_SERVICE_DOMAIN_PAUSE = 0x6, + SM_MSG_TYPE_SERVICE_DOMAIN_EXCHANGE_START = 0x7, + SM_MSG_TYPE_SERVICE_DOMAIN_EXCHANGE = 0x8, + SM_MSG_TYPE_SERVICE_DOMAIN_MEMBER_REQUEST = 0x9, + SM_MSG_TYPE_SERVICE_DOMAIN_MEMBER_UPDATE = 0xa, + SM_MSG_MAX, +} SmMsgTypeT; + +typedef struct +{ + uint16_t version; + uint16_t revision; + uint16_t max_supported_version; + uint16_t max_supported_revision; + uint16_t msg_len; + uint16_t msg_type; + uint64_t msg_flags; + SmUuidT msg_instance; + uint64_t msg_seq_num; + char node_name[SM_NODE_NAME_MAX_CHAR]; + uint32_t auth_type; + uint8_t auth_vector[SM_AUTHENTICATION_VECTOR_MAX_CHAR]; +} __attribute__ ((packed)) SmMsgHeaderT; + +typedef struct +{ + char node_name[SM_NODE_NAME_MAX_CHAR]; + char admin_state[SM_NODE_ADMIN_STATE_MAX_CHAR]; + char oper_state[SM_NODE_OPERATIONAL_STATE_MAX_CHAR]; + char avail_status[SM_NODE_AVAIL_STATUS_MAX_CHAR]; + char ready_state[SM_NODE_READY_STATE_MAX_CHAR]; + SmUuidT state_uuid; + uint32_t uptime; +} __attribute__ ((packed)) SmMsgNodeHelloT; + +typedef struct +{ + char node_name[SM_NODE_NAME_MAX_CHAR]; + char admin_state[SM_NODE_ADMIN_STATE_MAX_CHAR]; + char oper_state[SM_NODE_OPERATIONAL_STATE_MAX_CHAR]; + char avail_status[SM_NODE_AVAIL_STATUS_MAX_CHAR]; + char ready_state[SM_NODE_READY_STATE_MAX_CHAR]; + SmUuidT old_state_uuid; + SmUuidT state_uuid; + uint32_t uptime; + uint32_t force; +} __attribute__ ((packed)) SmMsgNodeUpdateT; + +typedef struct +{ + SmUuidT request_uuid; + char node_name[SM_NODE_NAME_MAX_CHAR]; + uint32_t force; +} __attribute__ ((packed)) SmMsgNodeSwactT; + +typedef struct +{ + SmUuidT request_uuid; + char node_name[SM_NODE_NAME_MAX_CHAR]; + uint32_t force; +} __attribute__ ((packed)) SmMsgNodeSwactAckT; + +typedef struct +{ + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char node_name[SM_NODE_NAME_MAX_CHAR]; + char orchestration[SM_ORCHESTRATION_MAX_CHAR]; + char designation[SM_DESIGNATION_MAX_CHAR]; + uint32_t generation; + uint32_t priority; + uint32_t hello_interval; + uint32_t dead_interval; + uint32_t wait_interval; + uint32_t exchange_interval; + char leader[SM_NODE_NAME_MAX_CHAR]; +} __attribute__ ((packed)) SmMsgServiceDomainHelloT; + +typedef struct +{ + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char node_name[SM_NODE_NAME_MAX_CHAR]; + uint32_t pause_interval; +} __attribute__ ((packed)) SmMsgServiceDomainPauseT; + +typedef struct +{ + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char node_name[SM_NODE_NAME_MAX_CHAR]; + char exchange_node_name[SM_NODE_NAME_MAX_CHAR]; + uint32_t exchange_seq; +} __attribute__ ((packed)) SmMsgServiceDomainExchangeStartT; + +typedef struct +{ + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char node_name[SM_NODE_NAME_MAX_CHAR]; + char exchange_node_name[SM_NODE_NAME_MAX_CHAR]; + uint32_t exchange_seq; + int64_t member_id; + char member_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + char member_desired_state[SM_SERVICE_GROUP_STATE_MAX_CHAR]; + char member_state[SM_SERVICE_GROUP_STATE_MAX_CHAR]; + char member_status[SM_SERVICE_GROUP_STATUS_MAX_CHAR]; + char member_condition[SM_SERVICE_GROUP_CONDITION_MAX_CHAR]; + int64_t member_health; + char reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR]; + uint32_t more_members; + int64_t last_received_member_id; +} __attribute__ ((packed)) SmMsgServiceDomainExchangeT; + +typedef struct +{ + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char node_name[SM_NODE_NAME_MAX_CHAR]; + char member_node_name[SM_NODE_NAME_MAX_CHAR]; + int64_t member_id; + char member_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + char member_action[SM_SERVICE_GROUP_ACTION_MAX_CHAR]; + uint64_t member_action_flags; +} __attribute__ ((packed)) SmMsgServiceDomainMemberRequestT; + +typedef struct +{ + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char node_name[SM_NODE_NAME_MAX_CHAR]; + char member_node_name[SM_NODE_NAME_MAX_CHAR]; + int64_t member_id; + char member_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + char member_desired_state[SM_SERVICE_GROUP_STATE_MAX_CHAR]; + char member_state[SM_SERVICE_GROUP_STATE_MAX_CHAR]; + char member_status[SM_SERVICE_GROUP_STATUS_MAX_CHAR]; + char member_condition[SM_SERVICE_GROUP_CONDITION_MAX_CHAR]; + int64_t member_health; + char reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR]; +} __attribute__ ((packed)) SmMsgServiceDomainMemberUpdateT; + +typedef struct +{ + SmMsgHeaderT header; + + union + { // Node Messages. + SmMsgNodeHelloT node_hello; + SmMsgNodeUpdateT node_update; + SmMsgNodeSwactT node_swact; + SmMsgNodeSwactAckT node_swact_ack; + + // Service Domain Messages. + SmMsgServiceDomainHelloT hello; + SmMsgServiceDomainPauseT pause; + SmMsgServiceDomainExchangeStartT exchange_start; + SmMsgServiceDomainExchangeT exchange; + SmMsgServiceDomainMemberRequestT request; + SmMsgServiceDomainMemberUpdateT update; + char raw_msg[SM_MSG_MAX_SIZE-sizeof(SmMsgHeaderT)]; + } u; +} __attribute__ ((packed)) SmMsgT; + +typedef struct +{ + bool inuse; + char node_name[SM_NODE_NAME_MAX_CHAR]; + SmUuidT msg_instance; + uint64_t msg_last_seq_num; +} SmMsgPeerNodeInfoT; + +typedef struct +{ + bool inuse; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmNetworkAddressT network_address; + int network_port; + SmAuthTypeT auth_type; + char auth_key[SM_AUTHENTICATION_KEY_MAX_CHAR]; +} SmMsgPeerInterfaceInfoT; + +static bool _messaging_enabled = false; +static char _hostname[SM_NODE_NAME_MAX_CHAR]; +static SmUuidT _msg_instance = {0}; +static uint64_t _msg_seq_num = 0; +static char _tx_control_buffer[SM_MSG_BUFFER_MAX_SIZE] __attribute__((aligned)); +static char _tx_buffer[SM_MSG_BUFFER_MAX_SIZE] __attribute__((aligned)); +static char _rx_control_buffer[SM_MSG_BUFFER_MAX_SIZE] __attribute__((aligned)); +static char _rx_buffer[SM_MSG_BUFFER_MAX_SIZE] __attribute__((aligned)); +static SmListT* _callbacks = NULL; +static unsigned int _next_free_peer_entry = 0; +static SmMsgPeerNodeInfoT _peers[SM_NODE_MAX]; +static SmMsgPeerInterfaceInfoT _peer_interfaces[SM_INTERFACE_PEER_MAX]; + +// Transmit and Receive Statistics +static uint64_t _rcvd_total_msgs = 0; +static uint64_t _rcvd_msgs_while_disabled = 0; +static uint64_t _rcvd_bad_msg_auth = 0; +static uint64_t _rcvd_bad_msg_version = 0; +static uint64_t _send_node_hello_cnt = 0; +static uint64_t _rcvd_node_hello_cnt = 0; +static uint64_t _send_node_update_cnt = 0; +static uint64_t _rcvd_node_update_cnt = 0; +static uint64_t _send_node_swact_cnt = 0; +static uint64_t _rcvd_node_swact_cnt = 0; +static uint64_t _send_node_swact_ack_cnt = 0; +static uint64_t _rcvd_node_swact_ack_cnt = 0; +static uint64_t _send_service_domain_hello_cnt = 0; +static uint64_t _rcvd_service_domain_hello_cnt = 0; +static uint64_t _send_service_domain_pause_cnt = 0; +static uint64_t _rcvd_service_domain_pause_cnt = 0; +static uint64_t _send_service_domain_exchange_start_cnt = 0; +static uint64_t _rcvd_service_domain_exchange_start_cnt = 0; +static uint64_t _send_service_domain_exchange_cnt = 0; +static uint64_t _rcvd_service_domain_exchange_cnt = 0; +static uint64_t _send_service_domain_member_request_cnt = 0; +static uint64_t _rcvd_service_domain_member_request_cnt = 0; +static uint64_t _send_service_domain_member_update_cnt = 0; +static uint64_t _rcvd_service_domain_member_update_cnt = 0; + +// **************************************************************************** +// Messaging - Find Peer Node Info +// =============================== +static SmMsgPeerNodeInfoT* sm_msg_find_peer_node_info( char node_name[] ) +{ + SmMsgPeerNodeInfoT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_NODE_MAX > entry_i; ++entry_i ) + { + entry = &(_peers[entry_i]); + + if( entry->inuse ) + { + if( 0 == strcmp( node_name, entry->node_name ) ) + { + return( entry ); + } + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - In Sequence +// ======================= +static bool sm_msg_in_sequence( char node_name[], + SmUuidT msg_instance, uint64_t msg_seq_num ) +{ + bool in_sequence = false; + SmMsgPeerNodeInfoT* entry; + + entry = sm_msg_find_peer_node_info( node_name ); + if( NULL == entry ) + { + // Cheap way of aging out entries when the maximum node limit is + // reached. + entry = &(_peers[_next_free_peer_entry++]); + if( _next_free_peer_entry >= SM_NODE_MAX ) + { + _next_free_peer_entry = 0; + } + + entry->inuse = true; + snprintf( entry->node_name, sizeof(entry->node_name), "%s", + node_name ); + snprintf( entry->msg_instance, sizeof(entry->msg_instance), + "%s", msg_instance ); + entry->msg_last_seq_num = msg_seq_num; + in_sequence = true; + + DPRINTFI( "Message instance (%s) for node (%s) set.", msg_instance, + node_name ); + } else { + if( 0 == strcmp( msg_instance, entry->msg_instance ) ) + { + uint64_t delta; + + if( msg_seq_num > entry->msg_last_seq_num ) + { + delta = msg_seq_num- entry->msg_last_seq_num; + if( SM_MSG_MAX_SEQ_DELTA < delta ) + { + DPRINTFI( "Message sequence delta (%"PRIu64") too large " + "for message instance (%s) from node (%s), " + "rcvd_seq=%"PRIu64", last_recvd_seq=%"PRIu64".", + delta, entry->msg_instance, node_name, + msg_seq_num, entry->msg_last_seq_num ); + } + + entry->msg_last_seq_num = msg_seq_num; + in_sequence = true; + + } else { + delta = entry->msg_last_seq_num - msg_seq_num; + + if( SM_MSG_MAX_SEQ_DELTA < delta ) + { + DPRINTFI( "Message sequence delta (%"PRIu64") too large " + "for message instance (%s) from node (%s), " + "rcvd_seq=%"PRIu64", last_recvd_seq=%"PRIu64".", + delta, entry->msg_instance, node_name, + msg_seq_num, entry->msg_last_seq_num ); + + entry->msg_last_seq_num = msg_seq_num; + in_sequence = true; + } + } + } else { + DPRINTFI( "Message instance (%s) changed for node (%s), now=%s.", + entry->msg_instance, node_name, msg_instance ); + + snprintf( entry->msg_instance, sizeof(entry->msg_instance), + "%s", msg_instance ); + entry->msg_last_seq_num = msg_seq_num; + in_sequence = true; + } + } + + return( in_sequence ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Add Peer Interface +// ============================== +SmErrorT sm_msg_add_peer_interface( char interface_name[], + SmNetworkAddressT* network_address, int network_port, + SmAuthTypeT auth_type, char auth_key[] ) +{ + bool found = false; + SmMsgPeerInterfaceInfoT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_INTERFACE_PEER_MAX > entry_i; ++entry_i ) + { + entry = &(_peer_interfaces[entry_i]); + + if( !(entry->inuse) ) + continue; + + if( 0 != strcmp( interface_name, entry->interface_name ) ) + continue; + + if( network_address->type != entry->network_address.type ) + continue; + + if( SM_NETWORK_TYPE_IPV4 == network_address->type ) + { + if( network_address->u.ipv4.sin.s_addr + == entry->network_address.u.ipv4.sin.s_addr ) + { + found = true; + break; + } + } else if( SM_NETWORK_TYPE_IPV4_UDP == network_address->type ) { + if(( network_address->u.ipv4.sin.s_addr + == entry->network_address.u.ipv4.sin.s_addr )&& + ( network_port == entry->network_port )) + { + found = true; + break; + } + } else if( SM_NETWORK_TYPE_IPV6 == network_address->type ) { + if( 0 != memcmp( &( network_address->u.ipv6.sin6 ), + &( entry->network_address.u.ipv6.sin6 ), + sizeof(struct in6_addr) )) + { + found = true; + break; + } + } else if( SM_NETWORK_TYPE_IPV6_UDP == network_address->type ) { + if(( 0 != memcmp( &( network_address->u.ipv6.sin6 ), + &( entry->network_address.u.ipv6.sin6 ), + sizeof(struct in6_addr) ))&& + ( network_port == entry->network_port )) + { + found = true; + break; + } + } + } + + if( !found ) + { + for( entry_i=0; SM_INTERFACE_PEER_MAX > entry_i; ++entry_i ) + { + entry = &(_peer_interfaces[entry_i]); + + if( !(entry->inuse) ) + { + entry->inuse = true; + snprintf( entry->interface_name, sizeof(entry->interface_name), + "%s", interface_name ); + memcpy( &(entry->network_address), network_address, + sizeof(SmNetworkAddressT) ); + entry->network_port = network_port; + entry->auth_type = auth_type; + memcpy( entry->auth_key, auth_key, + SM_AUTHENTICATION_KEY_MAX_CHAR ); + break; + } + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Delete Peer Interface +// ================================= +SmErrorT sm_msg_delete_peer_interface( char interface_name[], + SmNetworkAddressT* network_address, int network_port ) +{ + SmMsgPeerInterfaceInfoT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_INTERFACE_PEER_MAX > entry_i; ++entry_i ) + { + entry = &(_peer_interfaces[entry_i]); + + if( !(entry->inuse) ) + continue; + + if( 0 != strcmp( interface_name, entry->interface_name ) ) + continue; + + if( network_address->type != entry->network_address.type ) + continue; + + if( SM_NETWORK_TYPE_IPV4 == network_address->type ) + { + if( network_address->u.ipv4.sin.s_addr + == entry->network_address.u.ipv4.sin.s_addr ) + { + memset( entry, 0, sizeof(SmMsgPeerInterfaceInfoT) ); + break; + } + } else if( SM_NETWORK_TYPE_IPV4_UDP == network_address->type ) { + if(( network_address->u.ipv4.sin.s_addr + == entry->network_address.u.ipv4.sin.s_addr )&& + ( network_port == entry->network_port )) + { + memset( entry, 0, sizeof(SmMsgPeerInterfaceInfoT) ); + break; + } + } else if( SM_NETWORK_TYPE_IPV6 == network_address->type ) { + if( 0 != memcmp( &(network_address->u.ipv6.sin6), + &(entry->network_address.u.ipv6.sin6), + sizeof(in6_addr) )) + { + memset( entry, 0, sizeof(SmMsgPeerInterfaceInfoT) ); + break; + } + } else if( SM_NETWORK_TYPE_IPV6_UDP == network_address->type ) { + if(( 0 != memcmp( &(network_address->u.ipv6.sin6), + &(entry->network_address.u.ipv6.sin6), + sizeof(in6_addr) ))&& + ( network_port == entry->network_port )) + { + memset( entry, 0, sizeof(SmMsgPeerInterfaceInfoT) ); + break; + } + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Get Peer Interface +// ============================== +static SmMsgPeerInterfaceInfoT* sm_msg_get_peer_interface( + char interface_name[], SmNetworkAddressT* network_address, + int network_port ) +{ + SmMsgPeerInterfaceInfoT* entry; + in6_addr empty_ipv6_address; + + unsigned int entry_i; + for( entry_i=0; SM_INTERFACE_PEER_MAX > entry_i; ++entry_i ) + { + entry = &(_peer_interfaces[entry_i]); + + if( !(entry->inuse) ) + continue; + + if( 0 != strcmp( interface_name, entry->interface_name ) ) + continue; + + if( SM_NETWORK_TYPE_IPV4 == entry->network_address.type ) + { + if( 0 == entry->network_address.u.ipv4.sin.s_addr ) + { + return( entry ); + + } else if( network_address->u.ipv4.sin.s_addr + == entry->network_address.u.ipv4.sin.s_addr ) + { + return( entry ); + } + } else if( SM_NETWORK_TYPE_IPV4_UDP == entry->network_address.type ) { + if( 0 == entry->network_address.u.ipv4.sin.s_addr ) + { + return( entry ); + + } else if( -1 == entry->network_port ) + { + return( entry ); + + } else if(( network_address->u.ipv4.sin.s_addr + == entry->network_address.u.ipv4.sin.s_addr )&& + ( network_port == entry->network_port )) + { + return( entry ); + } + } else if( SM_NETWORK_TYPE_IPV6 == entry->network_address.type ) { + memset( &empty_ipv6_address, 0, sizeof(in6_addr) ); + if( 0 == memcmp( &(entry->network_address.u.ipv6.sin6), + &(empty_ipv6_address), + sizeof(in6_addr) )) + { + return( entry ); + + } else if( 0 == memcmp( &(network_address->u.ipv6.sin6), + &(entry->network_address.u.ipv6.sin6), + sizeof(in6_addr) )) + { + return( entry ); + } + } else if( SM_NETWORK_TYPE_IPV6_UDP == entry->network_address.type ) { + memset( &empty_ipv6_address, 0, sizeof(in6_addr) ); + if( 0 == memcmp( &(entry->network_address.u.ipv6.sin6), + &(empty_ipv6_address), + sizeof(in6_addr) )) + { + return( entry ); + + } else if( -1 == entry->network_port ) + { + return( entry ); + + } else if(( 0 == memcmp( &(network_address->u.ipv6.sin6), + &(entry->network_address.u.ipv6.sin6), + sizeof(in6_addr) ))&& + ( network_port == entry->network_port )) + { + return( entry ); + } + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Little Endian Network To Host Byte Order For Uint64 +// =============================================================== +uint64_t sm_msg_little_endian_ntohll( uint64_t i ) +{ + uint32_t tmp; + + union + { + uint64_t uint64; + struct + { + uint32_t word0; + uint32_t word1; + } uint32; + } u; + + u.uint64 = i; + + u.uint32.word0 = ntohl( u.uint32.word0 ); + u.uint32.word1 = ntohl( u.uint32.word1 ); + + tmp = u.uint32.word0; + u.uint32.word0 = u.uint32.word1; + u.uint32.word1 = tmp; + + return( u.uint64 ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Little Endian Host To Network Byte Order For Uint64 +// =============================================================== +uint64_t sm_msg_little_endian_htonll( uint64_t i ) +{ + uint32_t tmp; + + union + { + uint64_t uint64; + struct + { + uint32_t word0; + uint32_t word1; + } uint32; + } u; + + u.uint64 = i; + + u.uint32.word0 = htonl( u.uint32.word0 ); + u.uint32.word1 = htonl( u.uint32.word1 ); + + tmp = u.uint32.word0; + u.uint32.word0 = u.uint32.word1; + u.uint32.word1 = tmp; + + return( u.uint64 ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Enable +// ================== +void sm_msg_enable( void ) +{ + _messaging_enabled = true; + + DPRINTFI( "Messaging is now enabled." ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Disable +// =================== +void sm_msg_disable( void ) +{ + _messaging_enabled = false; + + DPRINTFI( "Messaging is now disabled." ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Register Callbacks +// ============================== +SmErrorT sm_msg_register_callbacks( SmMsgCallbacksT* callbacks ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callbacks ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Deregister Callbacks +// ================================ +SmErrorT sm_msg_deregister_callbacks( SmMsgCallbacksT* callbacks ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callbacks ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Increment Sequence Number +// ===================================== +void sm_msg_increment_seq_num( void ) +{ + ++_msg_seq_num; +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send message from IPv6 source +// ========================================== +static int sm_msg_sendmsg_src_ipv6( int socket, void* msg, size_t msg_len, + int flags, struct sockaddr_in6* dst_addr, struct in6_addr* src_Addr ) +{ + struct msghdr msg_hdr = {}; + struct cmsghdr *cmsg; + struct in6_pktinfo *pktinfo; + struct iovec iov = {msg, msg_len}; + + memset( &_tx_control_buffer, 0, sizeof(_tx_control_buffer) ); + msg_hdr.msg_iov = &iov; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_name = dst_addr; + msg_hdr.msg_namelen = sizeof(struct sockaddr_in6); + msg_hdr.msg_control = _tx_control_buffer; + msg_hdr.msg_controllen = CMSG_LEN( sizeof(struct in6_pktinfo) ); + cmsg = CMSG_FIRSTHDR( &msg_hdr ); + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN( sizeof(struct in6_pktinfo) ); + pktinfo = (struct in6_pktinfo*) CMSG_DATA( cmsg ); + pktinfo->ipi6_ifindex = 0; + pktinfo->ipi6_addr = *src_Addr; + + return sendmsg( socket, &msg_hdr, flags ); +} +// **************************************************************************** + +static int sm_send_msg(SmServiceDomainInterfaceT* interface, SmMsgT* msg ) +{ + struct sockaddr_in dst_addr4; + int result = -1; + SmIpv4AddressT* ipv4_dst; + + memset( &dst_addr4, 0, sizeof(dst_addr4) ); + dst_addr4.sin_family = AF_INET; + dst_addr4.sin_port = htons(interface->network_port); + + if ( SM_INTERFACE_OAM != interface->interface_type ) + { + ipv4_dst = &(interface->network_multicast.u.ipv4); + } + else + { + ipv4_dst = &(interface->network_peer_address.u.ipv4); + } + + if( 0 == ipv4_dst->sin.s_addr ) + { + //don't send to 0.0.0.0 + return _MSG_NOT_SENT_TO_TARGET; + } + dst_addr4.sin_addr.s_addr = ipv4_dst->sin.s_addr; + + result = sendto( interface->unicast_socket, msg, sizeof(SmMsgT), + 0, (struct sockaddr *) &dst_addr4, sizeof(dst_addr4) ); + + return result; +} + +static int sm_send_ipv6_msg(SmServiceDomainInterfaceT* interface, SmMsgT* msg ) +{ + struct sockaddr_in6 dst_addr6; + int result = -1; + SmIpv6AddressT* ipv6_dst; + + memset( &dst_addr6, 0, sizeof(dst_addr6) ); + dst_addr6.sin6_family = AF_INET6; + dst_addr6.sin6_port = htons(interface->network_port); + + if ( SM_INTERFACE_OAM != interface->interface_type ) + { + ipv6_dst = &(interface->network_multicast.u.ipv6); + }else + { + ipv6_dst = &(interface->network_peer_address.u.ipv6); + } + dst_addr6.sin6_addr = ipv6_dst->sin6; + result = sm_msg_sendmsg_src_ipv6( interface->unicast_socket, msg, sizeof(SmMsgT), + 0, &dst_addr6, &interface->network_address.u.ipv6.sin6 ); + + return result; +} +// **************************************************************************** +// Messaging - Send Node Hello +// =========================== +SmErrorT sm_msg_send_node_hello( char node_name[], + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status, SmNodeReadyStateT ready_state, + SmUuidT state_uuid, long uptime, SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgNodeHelloT* hello_msg = &(msg->u.node_hello); + int result = -1; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_NODE_HELLO); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( hello_msg->node_name, sizeof(hello_msg->node_name), + "%s", node_name ); + snprintf( hello_msg->admin_state, sizeof(hello_msg->admin_state), + "%s", sm_node_admin_state_str(admin_state) ); + snprintf( hello_msg->oper_state, sizeof(hello_msg->oper_state), + "%s", sm_node_oper_state_str(oper_state) ); + snprintf( hello_msg->avail_status, sizeof(hello_msg->avail_status), + "%s", sm_node_avail_status_str(avail_status) ); + snprintf( hello_msg->ready_state, sizeof(hello_msg->ready_state), + "%s", sm_node_ready_state_str(ready_state) ); + snprintf( hello_msg->state_uuid, sizeof(hello_msg->state_uuid), + "%s", state_uuid ); + hello_msg->uptime = htonl(uptime); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_node_hello_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Node Update +// ============================ +SmErrorT sm_msg_send_node_update( char node_name[], + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status, SmNodeReadyStateT ready_state, + SmUuidT old_state_uuid, SmUuidT state_uuid, long uptime, bool force, + SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgNodeUpdateT* update_msg = &(msg->u.node_update); + int result = -1; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_NODE_UPDATE); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( update_msg->node_name, sizeof(update_msg->node_name), + "%s", node_name ); + snprintf( update_msg->admin_state, sizeof(update_msg->admin_state), + "%s", sm_node_admin_state_str(admin_state) ); + snprintf( update_msg->oper_state, sizeof(update_msg->oper_state), + "%s", sm_node_oper_state_str(oper_state) ); + snprintf( update_msg->avail_status, sizeof(update_msg->avail_status), + "%s", sm_node_avail_status_str(avail_status) ); + snprintf( update_msg->ready_state, sizeof(update_msg->ready_state), + "%s", sm_node_ready_state_str(ready_state) ); + snprintf( update_msg->old_state_uuid, + sizeof(update_msg->old_state_uuid), "%s", old_state_uuid ); + snprintf( update_msg->state_uuid, sizeof(update_msg->state_uuid), + "%s", state_uuid ); + update_msg->uptime = htonl(uptime); + update_msg->force = htonl(force); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_node_update_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Node Swact +// =========================== +SmErrorT sm_msg_send_node_swact( char node_name[], bool force, + SmUuidT request_uuid, SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgNodeSwactT* swact_msg = &(msg->u.node_swact); + int result = -1; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_NODE_SWACT); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( swact_msg->node_name, sizeof(swact_msg->node_name), + "%s", node_name ); + snprintf( swact_msg->request_uuid, sizeof(swact_msg->request_uuid), + "%s", request_uuid ); + swact_msg->force = htonl(force); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_node_swact_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Node Swact Ack +// =============================== +SmErrorT sm_msg_send_node_swact_ack( char node_name[], bool force, + SmUuidT request_uuid, SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgNodeSwactAckT* swact_ack_msg = NULL; + int result = -1; + + swact_ack_msg = &(msg->u.node_swact_ack); + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_NODE_SWACT_ACK); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( swact_ack_msg->node_name, + sizeof(swact_ack_msg->node_name), "%s", node_name ); + snprintf( swact_ack_msg->request_uuid, + sizeof(swact_ack_msg->request_uuid), "%s", request_uuid ); + swact_ack_msg->force = htonl(force); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_node_swact_ack_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Hello +// ===================================== +SmErrorT sm_msg_send_service_domain_hello( char node_name[], + SmOrchestrationTypeT orchestration, SmDesignationTypeT designation, + int generation, int priority, int hello_interval, int dead_interval, + int wait_interval, int exchange_interval, char leader[], + SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgServiceDomainHelloT* hello_msg = &(msg->u.hello); + int result = -1; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_SERVICE_DOMAIN_HELLO); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( hello_msg->service_domain, sizeof(hello_msg->service_domain), + "%s", interface->service_domain ); + snprintf( hello_msg->node_name, sizeof(hello_msg->node_name), + "%s", node_name ); + snprintf( hello_msg->orchestration, sizeof(hello_msg->orchestration), + "%s", sm_orchestration_type_str(orchestration) ); + snprintf( hello_msg->designation, sizeof(hello_msg->designation), + "%s", sm_designation_type_str(designation) ); + hello_msg->generation = htonl(generation); + hello_msg->priority = htonl(priority); + hello_msg->hello_interval = htonl(hello_interval); + hello_msg->dead_interval = htonl(dead_interval); + hello_msg->wait_interval = htonl(wait_interval); + hello_msg->exchange_interval = htonl(exchange_interval); + snprintf( hello_msg->leader, sizeof(hello_msg->leader), "%s", leader ); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_service_domain_hello_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Pause +// ===================================== +SmErrorT sm_msg_send_service_domain_pause( char node_name[], + int pause_interval, SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgServiceDomainPauseT* pause_msg = &(msg->u.pause); + int result = -1; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_SERVICE_DOMAIN_PAUSE); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( pause_msg->service_domain, sizeof(pause_msg->service_domain), + "%s", interface->service_domain ); + snprintf( pause_msg->node_name, sizeof(pause_msg->node_name), + "%s", node_name ); + pause_msg->pause_interval = htonl(pause_interval); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_service_domain_pause_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Exchange Start +// ============================================== +SmErrorT sm_msg_send_service_domain_exchange_start( char node_name[], + char exchange_node_name[], int exchange_seq, + SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgServiceDomainExchangeStartT* exchange_start_msg; + int result = -1; + + exchange_start_msg = &(msg->u.exchange_start); + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_SERVICE_DOMAIN_EXCHANGE_START); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( exchange_start_msg->service_domain, + sizeof(exchange_start_msg->service_domain), + "%s", interface->service_domain ); + snprintf( exchange_start_msg->node_name, + sizeof(exchange_start_msg->node_name), + "%s", node_name ); + snprintf( exchange_start_msg->exchange_node_name, + sizeof(exchange_start_msg->exchange_node_name), + "%s", exchange_node_name ); + exchange_start_msg->exchange_seq = htonl(exchange_seq); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_service_domain_exchange_start_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Exchange +// ======================================== +SmErrorT sm_msg_send_service_domain_exchange( char node_name[], + char exchange_node_name[], int exchange_seq, int64_t member_id, + char member_name[], SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t member_health, + char reason_text[], bool more_members, int64_t last_received_member_id, + SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgServiceDomainExchangeT* exchange_msg = &(msg->u.exchange); + int result = -1; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_SERVICE_DOMAIN_EXCHANGE); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( exchange_msg->service_domain, sizeof(exchange_msg->service_domain), + "%s", interface->service_domain ); + snprintf( exchange_msg->node_name, sizeof(exchange_msg->node_name), + "%s", node_name ); + snprintf( exchange_msg->exchange_node_name, + sizeof(exchange_msg->exchange_node_name), + "%s", exchange_node_name ); + exchange_msg->exchange_seq = htonl(exchange_seq); + exchange_msg->member_id = htonll(member_id); + snprintf( exchange_msg->member_name, sizeof(exchange_msg->member_name), + "%s", member_name ); + snprintf( exchange_msg->member_desired_state, + sizeof(exchange_msg->member_desired_state), + "%s", sm_service_group_state_str(member_desired_state) ); + snprintf( exchange_msg->member_state, sizeof(exchange_msg->member_state), + "%s", sm_service_group_state_str(member_state) ); + snprintf( exchange_msg->member_status, sizeof(exchange_msg->member_status), + "%s", sm_service_group_status_str(member_status) ); + snprintf( exchange_msg->member_condition, + sizeof( exchange_msg->member_condition), + "%s", sm_service_group_condition_str(member_condition) ); + exchange_msg->member_health = htonll(member_health); + snprintf( exchange_msg->reason_text, sizeof(exchange_msg->reason_text), + "%s", reason_text ); + exchange_msg->more_members = htonl(more_members ? 1 : 0); + exchange_msg->last_received_member_id = htonll(last_received_member_id); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_service_domain_exchange_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Member Request +// ============================================== +SmErrorT sm_msg_send_service_domain_member_request( char node_name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupActionT member_action, + SmServiceGroupActionFlagsT member_action_flags, + SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgServiceDomainMemberRequestT* request_msg = &(msg->u.request); + int result = -1; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_SERVICE_DOMAIN_MEMBER_REQUEST); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( request_msg->service_domain, sizeof(request_msg->service_domain), + "%s", interface->service_domain ); + snprintf( request_msg->node_name, sizeof(request_msg->node_name), + "%s", node_name ); + snprintf( request_msg->member_node_name, sizeof(request_msg->member_node_name), + "%s", member_node_name ); + request_msg->member_id = htonll(member_id); + snprintf( request_msg->member_name, sizeof(request_msg->member_name), + "%s", member_name ); + snprintf( request_msg->member_action, sizeof(request_msg->member_action), + "%s", sm_service_group_action_str(member_action) ); + request_msg->member_action_flags = htonll(member_action_flags); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_service_domain_member_request_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Member Update +// ============================================= +SmErrorT sm_msg_send_service_domain_member_update( char node_name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t member_health, + const char reason_text[], SmServiceDomainInterfaceT* interface ) +{ + SmMsgT* msg = (SmMsgT*) _tx_buffer; + SmMsgServiceDomainMemberUpdateT* update_msg = &(msg->u.update); + int result = -1; + + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + + msg->header.version = htons(SM_VERSION); + msg->header.revision = htons(SM_REVISION); + msg->header.max_supported_version = htons(SM_VERSION); + msg->header.max_supported_revision = htons(SM_REVISION); + msg->header.msg_len = htons(sizeof(SmMsgT)); + msg->header.msg_type = htons(SM_MSG_TYPE_SERVICE_DOMAIN_MEMBER_UPDATE); + msg->header.msg_flags = htonll(0); + snprintf( msg->header.msg_instance, sizeof(msg->header.msg_instance), + "%s", _msg_instance ); + msg->header.msg_seq_num = htonll(_msg_seq_num); + snprintf( msg->header.node_name, sizeof(msg->header.node_name), + "%s", _hostname ); + + snprintf( update_msg->service_domain, sizeof(update_msg->service_domain), + "%s", interface->service_domain ); + snprintf( update_msg->node_name, sizeof(update_msg->node_name), + "%s", node_name ); + snprintf( update_msg->member_node_name, sizeof(update_msg->member_node_name), + "%s", member_node_name ); + update_msg->member_id = htonll(member_id); + snprintf( update_msg->member_name, sizeof(update_msg->member_name), + "%s", member_name ); + snprintf( update_msg->member_desired_state, + sizeof(update_msg->member_desired_state), + "%s", sm_service_group_state_str(member_desired_state) ); + snprintf( update_msg->member_state, sizeof(update_msg->member_state), + "%s", sm_service_group_state_str(member_state) ); + snprintf( update_msg->member_status, sizeof(update_msg->member_status), + "%s", sm_service_group_status_str(member_status) ); + snprintf( update_msg->member_condition, sizeof(update_msg->member_condition), + "%s", sm_service_group_condition_str(member_condition) ); + update_msg->member_health = htonll(member_health); + snprintf( update_msg->reason_text, sizeof(update_msg->reason_text), + "%s", reason_text ); + + if( SM_AUTH_TYPE_HMAC_SHA512 == interface->auth_type ) + { + SmSha512HashT hash; + + msg->header.auth_type = htonl(interface->auth_type); + sm_sha512_hmac( msg, sizeof(SmMsgT), interface->auth_key, + strlen(interface->auth_key), &hash ); + memcpy( &(msg->header.auth_vector[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ); + } else { + msg->header.auth_type = htonl(SM_AUTH_TYPE_NONE); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + result = sm_send_msg(interface, msg); + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + result = sm_send_ipv6_msg(interface, msg); + } + + if( 0 > result ) + { + if ( _MSG_NOT_SENT_TO_TARGET != result ) + { + DPRINTFE( "Failed to send message on socket for interface (%s), " + "error=%s.", interface->interface_name, strerror( errno ) ); + return( SM_FAILED ); + } + return( SM_OKAY ); + } + + ++_send_service_domain_member_update_cnt; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Get Ancillary Data +// ============================== +static void* sm_msg_get_ancillary_data( struct msghdr* msg_hdr, int cmsg_level, + int cmsg_type ) +{ + struct cmsghdr* cmsg; + + for( cmsg = CMSG_FIRSTHDR(msg_hdr); NULL != cmsg; + cmsg = CMSG_NXTHDR( msg_hdr, cmsg) ) + { + if(( cmsg_level == cmsg->cmsg_level )&& + ( cmsg_type == cmsg->cmsg_type )) + { + return( CMSG_DATA(cmsg) ); + } + } + + return( NULL ); +} +// **************************************************************************** + + +// **************************************************************************** +// Messaging - Dispatch Message +// ============================ +static void sm_msg_dispatch_msg( bool is_multicast_msg, SmMsgT* msg, + SmNetworkAddressT* network_address, int network_port, + SmMsgPeerInterfaceInfoT* peer_interface ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmMsgCallbacksT* callbacks; + SmMsgNodeHelloT* node_hello_msg = &(msg->u.node_hello); + SmMsgNodeUpdateT* node_update_msg = &(msg->u.node_update); + SmMsgNodeSwactT* node_swact_msg; + SmMsgNodeSwactAckT* node_swact_ack_msg; + SmNodeAdminStateT node_admin_state; + SmNodeOperationalStateT node_oper_state; + SmNodeAvailStatusT node_avail_status; + SmNodeReadyStateT node_ready_state; + SmMsgServiceDomainHelloT* hello_msg = &(msg->u.hello); + SmMsgServiceDomainPauseT* pause_msg = &(msg->u.pause); + SmMsgServiceDomainExchangeStartT* exchange_start_msg; + SmMsgServiceDomainExchangeT* exchange_msg = &(msg->u.exchange); + SmMsgServiceDomainMemberRequestT* request_msg = &(msg->u.request); + SmMsgServiceDomainMemberUpdateT* update_msg = &(msg->u.update); + SmServiceGroupStateT member_desired_state; + SmServiceGroupStateT member_state; + SmServiceGroupStatusT member_status; + SmServiceGroupConditionT member_condition; + SmServiceGroupActionT member_action; + + + node_swact_msg = &(msg->u.node_swact); + node_swact_ack_msg = &(msg->u.node_swact_ack); + exchange_start_msg = &(msg->u.exchange_start); + + if( SM_VERSION != ntohs(msg->header.version) ) + { + ++_rcvd_bad_msg_version; + DPRINTFD( "Received unsupported version (%i).", + ntohs(msg->header.version) ); + return; + } + + if( 0 == strcmp( _hostname, msg->header.node_name ) ) + { + DPRINTFD( "Received own message (%i),", + ntohs(msg->header.msg_type) ); + return; + } + + if( !(sm_msg_in_sequence( msg->header.node_name, msg->header.msg_instance, + ntohll(msg->header.msg_seq_num) )) ) + { + DPRINTFD( "Duplicate message received from node (%s), " + "msg_seq=%"PRIi64".", msg->header.node_name, + ntohll(msg->header.msg_seq_num) ); + return; + } else { + DPRINTFD( "Message received from node (%s), " + "msg_seq=%"PRIi64".", msg->header.node_name, + ntohll(msg->header.msg_seq_num) ); + } + + if( SM_AUTH_TYPE_HMAC_SHA512 == ntohl(msg->header.auth_type) ) + { + uint8_t auth_vector[SM_AUTHENTICATION_VECTOR_MAX_CHAR]; + SmSha512HashT hash; + + memcpy( auth_vector, &(msg->header.auth_vector[0]), + SM_AUTHENTICATION_VECTOR_MAX_CHAR ); + memset( &(msg->header.auth_vector[0]), 0, + SM_AUTHENTICATION_VECTOR_MAX_CHAR ); + + sm_sha512_hmac( msg, sizeof(SmMsgT), peer_interface->auth_key, + strlen(peer_interface->auth_key), &hash ); + + if( 0 != memcmp( &(hash.bytes[0]), auth_vector, SM_SHA512_HASH_SIZE ) ) + { + ++_rcvd_bad_msg_auth; + DPRINTFD( "Authentication check failed on message (%i) from " + "node (%s).", ntohs(msg->header.msg_type), + msg->header.node_name ); + return; + } else { + DPRINTFD( "Authentication check passed on message (%i) from " + "node (%s).", ntohs(msg->header.msg_type), + msg->header.node_name ); + } + } + + uint16_t msg_type = ntohs(msg->header.msg_type) ; + + switch( msg_type ) + { + case SM_MSG_TYPE_NODE_HELLO: + ++_rcvd_node_hello_cnt; + + node_admin_state + = sm_node_admin_state_value(node_hello_msg->admin_state); + node_oper_state + = sm_node_oper_state_value(node_hello_msg->oper_state); + node_avail_status + = sm_node_avail_status_value(node_hello_msg->avail_status); + node_ready_state + = sm_node_ready_state_value(node_hello_msg->ready_state); + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->node_hello ) + continue; + + callbacks->node_hello( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + node_hello_msg->node_name, + node_admin_state, node_oper_state, + node_avail_status, node_ready_state, + node_hello_msg->state_uuid, + ntohl(node_hello_msg->uptime) ); + } + break; + + case SM_MSG_TYPE_NODE_UPDATE: + ++_rcvd_node_update_cnt; + + node_admin_state + = sm_node_admin_state_value(node_update_msg->admin_state); + node_oper_state + = sm_node_oper_state_value(node_update_msg->oper_state); + node_avail_status + = sm_node_avail_status_value(node_update_msg->avail_status); + node_ready_state + = sm_node_ready_state_value(node_update_msg->ready_state); + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->node_update ) + continue; + + callbacks->node_update( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + node_update_msg->node_name, + node_admin_state, node_oper_state, + node_avail_status, node_ready_state, + node_update_msg->old_state_uuid, + node_update_msg->state_uuid, + ntohl(node_update_msg->uptime), + ntohl(node_update_msg->force) ); + } + break; + + case SM_MSG_TYPE_NODE_SWACT: + ++_rcvd_node_swact_cnt; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->node_swact ) + continue; + + callbacks->node_swact( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + node_swact_msg->node_name, + ntohl(node_swact_msg->force), + node_swact_msg->request_uuid ); + } + break; + + case SM_MSG_TYPE_NODE_SWACT_ACK: + ++_rcvd_node_swact_ack_cnt; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->node_swact_ack ) + continue; + + callbacks->node_swact_ack( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + node_swact_ack_msg->node_name, + ntohl(node_swact_ack_msg->force), + node_swact_ack_msg->request_uuid ); + } + break; + + + case SM_MSG_TYPE_SERVICE_DOMAIN_HELLO: + ++_rcvd_service_domain_hello_cnt; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->hello ) + continue; + + callbacks->hello( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + hello_msg->service_domain, + hello_msg->node_name, + hello_msg->orchestration, + hello_msg->designation, + ntohl(hello_msg->generation), + ntohl(hello_msg->priority), + ntohl(hello_msg->hello_interval), + ntohl(hello_msg->dead_interval), + ntohl(hello_msg->wait_interval), + ntohl(hello_msg->exchange_interval), + hello_msg->leader ); + } + break; + + case SM_MSG_TYPE_SERVICE_DOMAIN_PAUSE: + ++_send_service_domain_pause_cnt; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->pause ) + continue; + + callbacks->pause( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + pause_msg->service_domain, + pause_msg->node_name, + ntohl(pause_msg->pause_interval) ); + } + break; + + case SM_MSG_TYPE_SERVICE_DOMAIN_EXCHANGE_START: + if( 0 != strcmp( exchange_start_msg->exchange_node_name, + _hostname ) ) + { + DPRINTFD( "Exchange start message not for us." ); + return; + } + + ++_rcvd_service_domain_exchange_start_cnt; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->exchange_start ) + continue; + + callbacks->exchange_start( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + exchange_start_msg->service_domain, + exchange_start_msg->node_name, + ntohl(exchange_start_msg->exchange_seq) ); + } + break; + + case SM_MSG_TYPE_SERVICE_DOMAIN_EXCHANGE: + if( 0 != strcmp( exchange_msg->exchange_node_name, _hostname ) ) + { + DPRINTFD( "Exchange message not for us." ); + return; + } + + ++_rcvd_service_domain_exchange_cnt; + + member_desired_state = sm_service_group_state_value( + exchange_msg->member_desired_state ); + member_state = sm_service_group_state_value( + exchange_msg->member_state ); + member_status = sm_service_group_status_value( + exchange_msg->member_status ); + + member_condition = sm_service_group_condition_value( + exchange_msg->member_condition ); + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->exchange ) + continue; + + callbacks->exchange( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + exchange_msg->service_domain, + exchange_msg->node_name, + ntohl(exchange_msg->exchange_seq), + ntohll(exchange_msg->member_id), + exchange_msg->member_name, + member_desired_state, + member_state, member_status, + member_condition, + ntohll(exchange_msg->member_health), + exchange_msg->reason_text, + ntohl(exchange_msg->more_members) ? true : false, + ntohll(exchange_msg->last_received_member_id) ); + } + break; + + case SM_MSG_TYPE_SERVICE_DOMAIN_MEMBER_REQUEST: + if( 0 != strcmp( request_msg->member_node_name, _hostname ) ) + { + DPRINTFD( "Member request message not for us." ); + return; + } + + ++_rcvd_service_domain_member_request_cnt; + + member_action = sm_service_group_action_value( + request_msg->member_action ); + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->member_request ) + continue; + + callbacks->member_request( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + request_msg->service_domain, + request_msg->node_name, + request_msg->member_node_name, + ntohll(request_msg->member_id), + request_msg->member_name, + member_action, + ntohll(request_msg->member_action_flags) ); + } + break; + + case SM_MSG_TYPE_SERVICE_DOMAIN_MEMBER_UPDATE: + ++_rcvd_service_domain_member_update_cnt; + + member_desired_state = sm_service_group_state_value( + update_msg->member_desired_state ); + member_state = sm_service_group_state_value( + update_msg->member_state ); + member_status = sm_service_group_status_value( + update_msg->member_status ); + member_condition = sm_service_group_condition_value( + update_msg->member_condition ); + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmMsgCallbacksT*) entry_data; + + if( NULL == callbacks->member_update ) + continue; + + callbacks->member_update( network_address, network_port, + ntohs(msg->header.version), + ntohs(msg->header.revision), + update_msg->service_domain, + update_msg->node_name, + update_msg->member_node_name, + ntohll(update_msg->member_id), + update_msg->member_name, + member_desired_state, + member_state, member_status, + member_condition, + ntohll(update_msg->member_health), + update_msg->reason_text ); + } + break; + + default: + DPRINTFI( "Unsupported message type (%i) received.", + ntohs(msg->header.msg_type) ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Dispatch Ipv4 Udp +// ============================= +static void sm_msg_dispatch_ipv4_udp( int selobj, int64_t msg_method ) +{ + SmMsgT* msg = (SmMsgT*) _rx_buffer; + SmNetworkAddressT network_address; + SmMsgPeerInterfaceInfoT* peer_interface = NULL; + SmErrorT error; + int network_port; + struct sockaddr_in src_addr; + struct iovec iovec = {(void*)_rx_buffer, sizeof(_rx_buffer)}; + struct msghdr msg_hdr; + int bytes_read; + + memset( &network_address, 0, sizeof(network_address) ); + memset( _rx_control_buffer, 0, sizeof(_rx_control_buffer) ); + memset( _rx_buffer, 0, sizeof(_rx_buffer) ); + memset( &msg_hdr, 0, sizeof(msg_hdr) ); + + msg_hdr.msg_name = &src_addr; + msg_hdr.msg_namelen= sizeof(src_addr); + msg_hdr.msg_iov = &iovec; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_control = _rx_control_buffer; + msg_hdr.msg_controllen = sizeof(_rx_control_buffer); + + int retry_i; + for( retry_i = 5; retry_i != 0; --retry_i ) + { + bytes_read = recvmsg( selobj, &msg_hdr, MSG_NOSIGNAL | MSG_DONTWAIT ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_i, strerror( errno ) ); + } + + ++_rcvd_total_msgs; + + if( !_messaging_enabled ) + { + ++_rcvd_msgs_while_disabled; + DPRINTFD( "Messaging is disabled." ); + return; + } + + if( AF_INET == src_addr.sin_family ) + { + char if_name[SM_INTERFACE_NAME_MAX_CHAR] = {0}; + struct in_pktinfo* pkt_info; + char network_address_str[SM_NETWORK_ADDRESS_MAX_CHAR]; + + pkt_info = (struct in_pktinfo*) sm_msg_get_ancillary_data( &msg_hdr, + SOL_IP, IP_PKTINFO ); + if( NULL == pkt_info ) + { + DPRINTFD( "No packet information available." ); + return; + } + + error = sm_hw_get_if_name( pkt_info->ipi_ifindex, if_name ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Failed to get interface name for interface index " + "(%i), error=%s.", pkt_info->ipi_ifindex, + sm_error_str(error) ); + } else { + DPRINTFE( "Failed to get interface name for interface index " + "(%i), error=%s.", pkt_info->ipi_ifindex, + sm_error_str(error) ); + } + return; + } + + network_address.type = SM_NETWORK_TYPE_IPV4_UDP; + network_address.u.ipv4.sin.s_addr = src_addr.sin_addr.s_addr; + network_port = ntohs(src_addr.sin_port); + + sm_network_address_str( &network_address, network_address_str ); + + DPRINTFD( "Received message from ip (%s), port (%i) on " + "interface (%s).", network_address_str, network_port, + if_name ); + + peer_interface = sm_msg_get_peer_interface( if_name, &network_address, + network_port ); + if( NULL == peer_interface ) + { + DPRINTFD( "Message received not for us, if=%s, ip=%s, port=%i.", + if_name, network_address_str, network_port ); + return; + } + } else { + DPRINTFE( "Received unsupported network address type (%i).", + src_addr.sin_family ); + return; + } + + // Once the message is received, pass it to protocol-independent handler + sm_msg_dispatch_msg( msg_method, msg, &network_address, network_port, + peer_interface ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Dispatch Ipv6 Udp +// ============================= +static void sm_msg_dispatch_ipv6_udp( int selobj, int64_t msg_method ) +{ + SmMsgT* msg = (SmMsgT*) _rx_buffer; + SmNetworkAddressT network_address; + SmMsgPeerInterfaceInfoT* peer_interface = NULL; + SmErrorT error; + int network_port; + struct sockaddr_in6 src_addr; + struct iovec iovec = {(void*)_rx_buffer, sizeof(_rx_buffer)}; + struct msghdr msg_hdr; + int bytes_read; + + memset( &network_address, 0, sizeof(network_address) ); + memset( _rx_control_buffer, 0, sizeof(_rx_control_buffer) ); + memset( _rx_buffer, 0, sizeof(_rx_buffer) ); + memset( &msg_hdr, 0, sizeof(msg_hdr) ); + + msg_hdr.msg_name = &src_addr; + msg_hdr.msg_namelen= sizeof(src_addr); + msg_hdr.msg_iov = &iovec; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_control = _rx_control_buffer; + msg_hdr.msg_controllen = sizeof(_rx_control_buffer); + + int retry_i; + for( retry_i = 5; retry_i != 0; --retry_i ) + { + bytes_read = recvmsg( selobj, &msg_hdr, MSG_NOSIGNAL | MSG_DONTWAIT ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_i, strerror( errno ) ); + } + + ++_rcvd_total_msgs; + + if( !_messaging_enabled ) + { + ++_rcvd_msgs_while_disabled; + DPRINTFD( "Messaging is disabled." ); + return; + } + + if( AF_INET6 == src_addr.sin6_family ) + { + char if_name[SM_INTERFACE_NAME_MAX_CHAR] = {0}; + struct in6_pktinfo* pkt_info; + char network_address_str[SM_NETWORK_ADDRESS_MAX_CHAR]; + + pkt_info = (struct in6_pktinfo*) sm_msg_get_ancillary_data( &msg_hdr, + SOL_IPV6, IPV6_PKTINFO ); + if( NULL == pkt_info ) + { + DPRINTFD( "No packet information available." ); + return; + } + + error = sm_hw_get_if_name( pkt_info->ipi6_ifindex, if_name ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Failed to get interface name for interface index " + "(%i), error=%s.", pkt_info->ipi6_ifindex, + sm_error_str(error) ); + } else { + DPRINTFE( "Failed to get interface name for interface index " + "(%i), error=%s.", pkt_info->ipi6_ifindex, + sm_error_str(error) ); + } + return; + } + + network_address.type = SM_NETWORK_TYPE_IPV6_UDP; + network_address.u.ipv6.sin6 = src_addr.sin6_addr; + network_port = ntohs(src_addr.sin6_port); + + sm_network_address_str( &network_address, network_address_str ); + + DPRINTFD( "Received message from ip (%s), port (%i) on " + "interface (%s).", network_address_str, network_port, + if_name ); + + peer_interface = sm_msg_get_peer_interface( if_name, &network_address, + network_port ); + if( NULL == peer_interface ) + { + DPRINTFD( "Message received not for us, if=%s, ip=%s, port=%i.", + if_name, network_address_str, network_port ); + return; + } + } else { + DPRINTFE( "Received unsupported network address type (%i).", + src_addr.sin6_family ); + return; + } + + // Once the message is received, pass it to protocol-independent handler + sm_msg_dispatch_msg( msg_method, msg, &network_address, network_port, + peer_interface ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Register Ipv4 Multicast Address +// =========================================== +static SmErrorT sm_msg_register_ipv4_multicast( + SmServiceDomainInterfaceT* interface ) +{ + int if_index; + struct ip_mreqn mreq; + int result = 0; + SmIpv4AddressT* ipv4_multicast = &(interface->network_multicast.u.ipv4); + SmErrorT error; + + error = sm_hw_get_if_index( interface->interface_name, &if_index ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to convert interface name (%s) to interface index, " + "error=%s.", interface->interface_name, + sm_error_str( error ) ); + return( error ); + } + + memset( &mreq, 0, sizeof(mreq) ); + + mreq.imr_multiaddr.s_addr = ipv4_multicast->sin.s_addr; + mreq.imr_ifindex = if_index; + + result = setsockopt( interface->multicast_socket, IPPROTO_IP, + IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq) ); + if( 0 > result ) + { + DPRINTFE( "Failed to add multicast membership to interface (%s), " + "errno=%s.", interface->interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Register Ipv6 Multicast Address +// =========================================== +static SmErrorT sm_msg_register_ipv6_multicast( + SmServiceDomainInterfaceT* interface ) +{ + int if_index; + struct ipv6_mreq mreq; + int result = 0; + SmIpv6AddressT* ipv6_multicast = &(interface->network_multicast.u.ipv6); + SmErrorT error; + + error = sm_hw_get_if_index( interface->interface_name, &if_index ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to convert interface name (%s) to interface index, " + "error=%s.", interface->interface_name, + sm_error_str( error ) ); + return( error ); + } + + memset( &mreq, 0, sizeof(mreq) ); + + mreq.ipv6mr_multiaddr = ipv6_multicast->sin6; + mreq.ipv6mr_interface = if_index; + + result = setsockopt( interface->multicast_socket, IPPROTO_IPV6, + IPV6_JOIN_GROUP, &mreq, sizeof(mreq) ); + if( 0 > result ) + { + DPRINTFE( "Failed to add multicast membership to interface (%s), " + "errno=%s.", interface->interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Deregister Ipv4 Multicast Address +// ============================================= +static SmErrorT sm_msg_deregister_ipv4_multicast( + SmServiceDomainInterfaceT* interface ) +{ + int if_index; + struct ip_mreqn mreq; + int result = 0; + SmIpv4AddressT* ipv4_multicast = &(interface->network_multicast.u.ipv4); + SmErrorT error; + + error = sm_hw_get_if_index( interface->interface_name, &if_index ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to convert interface name (%s) to interface index, " + "error=%s.", interface->interface_name, + sm_error_str( error ) ); + return( error ); + } + + memset( &mreq, 0, sizeof(mreq) ); + + mreq.imr_multiaddr.s_addr = ipv4_multicast->sin.s_addr; + mreq.imr_ifindex = if_index; + + result = setsockopt( interface->multicast_socket, IPPROTO_IP, + IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq) ); + if( 0 > result ) + { + DPRINTFE( "Failed to drop multicast membership from interface (%s), " + "errno=%s.", interface->interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Deregister Ipv6 Multicast Address +// ============================================= +static SmErrorT sm_msg_deregister_ipv6_multicast( + SmServiceDomainInterfaceT* interface ) +{ + int if_index; + struct ipv6_mreq mreq; + int result = 0; + SmIpv6AddressT* ipv6_multicast = &(interface->network_multicast.u.ipv6); + SmErrorT error; + + error = sm_hw_get_if_index( interface->interface_name, &if_index ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to convert interface name (%s) to interface index, " + "error=%s.", interface->interface_name, + sm_error_str( error ) ); + return( error ); + } + + memset( &mreq, 0, sizeof(mreq) ); + + mreq.ipv6mr_multiaddr = ipv6_multicast->sin6; + mreq.ipv6mr_interface = if_index; + + result = setsockopt( interface->multicast_socket, IPPROTO_IPV6, + IPV6_LEAVE_GROUP, &mreq, sizeof(mreq) ); + if( 0 > result ) + { + DPRINTFE( "Failed to drop multicast membership from interface (%s), " + "errno=%s.", interface->interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Open Ipv4 UDP Multicast Socket +// ========================================== +static SmErrorT sm_msg_open_ipv4_udp_multicast_socket( + SmServiceDomainInterfaceT* interface, int* socket_fd ) +{ + int flags; + int sock; + int result; + struct ifreq ifr; + struct sockaddr_in addr; + SmIpv4AddressT* ipv4_address = &(interface->network_address.u.ipv4); + SmIpv4AddressT* ipv4_multicast = &(interface->network_multicast.u.ipv4); + + *socket_fd = -1; + + // Create socket. + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to open socket for interface (%s), errno=%s.", + interface->interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + // Set socket to non-blocking. + flags = fcntl( sock, F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > fcntl( sock, F_SETFL, flags | O_NONBLOCK ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Close on exec. + flags = fcntl( sock, F_GETFD, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > fcntl( sock, F_SETFD, flags | FD_CLOEXEC ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Allow address reuse on socket. + flags = 1; + result = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, + (void*) &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set reuseaddr socket option on interface (%s), " + "errno=%s.", interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind address to socket. + memset( &addr, 0, sizeof(addr) ); + + addr.sin_family = AF_INET; + addr.sin_port = htons(interface->network_port); + addr.sin_addr.s_addr = ipv4_multicast->sin.s_addr; + + result = bind( sock, (struct sockaddr *) &addr, sizeof(addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind multicast address to socket for " + "interface (%s), error=%s.", interface->interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast interface on socket. + result = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_IF, + (struct in_addr*) &(ipv4_address->sin.s_addr), + sizeof(struct in_addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set unicast address on socket for " + "interface (%s), error=%s.", interface->interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind socket to interface. + memset(&ifr, 0, sizeof(ifr)); + snprintf( ifr.ifr_name, sizeof(ifr.ifr_name), "%s", + interface->interface_name ); + + result = setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, + (void *)&ifr, sizeof(ifr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind socket to interface (%s), errno=%s.", + interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast TTL. + flags = 1; + result = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_TTL, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set multicast ttl for interface (%s), errno=%s.", + interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Disable looping of sent multicast packets on socket. + flags = 0; + result = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to stop looping of multicast messages for " + "interface (%s), errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket send priority on interface. + flags = IPTOS_CLASS_CS6; + result = setsockopt( sock, IPPROTO_IP, IP_TOS, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + flags = 6; + result = setsockopt( sock, SOL_SOCKET, SO_PRIORITY, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket receive packet information. + flags = 1; + result = setsockopt( sock, SOL_IP, IP_PKTINFO, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket receive packet information for " + "interface (%s) multicast messages, errno=%s.", + interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + *socket_fd = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Open IPv6 UDP Multicast Socket +// ========================================== +static SmErrorT sm_msg_open_ipv6_udp_multicast_socket( + SmServiceDomainInterfaceT* interface, int* socket_fd ) +{ + int flags; + int sock; + int result; + struct ifreq ifr; + struct sockaddr_in6 addr; + SmIpv6AddressT* ipv6_multicast = &(interface->network_multicast.u.ipv6); + + *socket_fd = -1; + + // Create socket. + sock = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to open socket for interface (%s), errno=%s.", + interface->interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + // Set socket to non-blocking. + flags = fcntl( sock, F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > fcntl( sock, F_SETFL, flags | O_NONBLOCK ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Close on exec. + flags = fcntl( sock, F_GETFD, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > fcntl( sock, F_SETFD, flags | FD_CLOEXEC ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Allow address reuse on socket. + flags = 1; + result = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, + (void*) &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set reuseaddr socket option on interface (%s), " + "errno=%s.", interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind address to socket. + memset( &addr, 0, sizeof(addr) ); + + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(interface->network_port); + addr.sin6_addr = ipv6_multicast->sin6; + + result = bind( sock, (struct sockaddr *) &addr, sizeof(addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind multicast address to socket for " + "interface (%s), error=%s.", interface->interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast interface on socket. + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_IF, + &(interface->id), sizeof(interface->id) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set unicast address on socket for " + "interface (%s), error=%s.", interface->interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind socket to interface. + memset( &ifr, 0, sizeof(ifr) ); + snprintf( ifr.ifr_name, sizeof(ifr.ifr_name), "%s", + interface->interface_name ); + + result = setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, + (void* )&ifr, sizeof(ifr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind socket to interface (%s), errno=%s.", + interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set multicast TTL. + flags = 1; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set multicast ttl for interface (%s), errno=%s.", + interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Disable looping of sent multicast packets on socket. + flags = 0; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to stop looping of multicast messages for " + "interface (%s), errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket send priority on interface. + flags = IPTOS_CLASS_CS6; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_TCLASS, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + flags = 6; + result = setsockopt( sock, SOL_SOCKET, SO_PRIORITY, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "multicast messages, errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket receive packet information. + flags = 1; + result = setsockopt( sock, SOL_IPV6, IPV6_RECVPKTINFO, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket receive packet information for " + "interface (%s) multicast messages, errno=%s.", + interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + *socket_fd = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Open Ipv4 UDP Unicast Socket +// ======================================== +static SmErrorT sm_msg_open_ipv4_udp_unicast_socket( + SmServiceDomainInterfaceT* interface, int* socket_fd ) +{ + int flags; + int sock; + int result; + struct sockaddr_in src_addr; + SmIpv4AddressT* ipv4_address = &(interface->network_address.u.ipv4); + + *socket_fd = -1; + + // Create socket. + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to open socket for interface (%s), errno=%s.", + interface->interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + // Set socket to non-blocking. + flags = fcntl( sock, F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > fcntl( sock, F_SETFL, flags | O_NONBLOCK ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Close on exec. + if( 0 > fcntl( sock, F_SETFD, FD_CLOEXEC ) ) + { + DPRINTFE( "Failed to set fd, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Allow address reuse on socket. + flags = 1; + result = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, + (void*) &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set reuseaddr socket option on interface (%s), " + "errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind address to socket. + memset( &src_addr, 0, sizeof(src_addr) ); + + src_addr.sin_family = AF_INET; + src_addr.sin_port = htons(interface->network_port); + src_addr.sin_addr.s_addr = ipv4_address->sin.s_addr; + + result = bind( sock, (struct sockaddr *) &src_addr, sizeof(src_addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind unicast address to socket for " + "interface (%s), error=%s.", interface->interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind socket to interface. + result = setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, + interface->interface_name, + strlen(interface->interface_name)+1 ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind socket to interface (%s), " + "errno=%s.", interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Disable looping of sent multicast packets on socket. + flags = 0; + result = setsockopt( sock, IPPROTO_IP, IP_MULTICAST_LOOP, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to stop looping of unicast messages for " + "interface (%s), errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket send priority on interface. + flags = IPTOS_CLASS_CS6; + result = setsockopt( sock, IPPROTO_IP, IP_TOS, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "unicast messages, errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + flags = 6; + result = setsockopt( sock, SOL_SOCKET, SO_PRIORITY, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "unicast messages, errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket receive packet information. + flags = 1; + result = setsockopt( sock, SOL_IP, IP_PKTINFO, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket receive packet information for " + "interface (%s) unicast messages, errno=%s.", + interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + *socket_fd = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Open IPv6 UDP Unicast Socket +// ======================================== +static SmErrorT sm_msg_open_ipv6_udp_unicast_socket( + SmServiceDomainInterfaceT* interface, int* socket_fd ) +{ + int flags; + int sock; + int result; + struct sockaddr_in6 src_addr; + SmIpv6AddressT* ipv6_address = &(interface->network_address.u.ipv6); + + *socket_fd = -1; + + // Create socket. + sock = socket( AF_INET6, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to open socket for interface (%s), errno=%s.", + interface->interface_name, strerror(errno) ); + return( SM_FAILED ); + } + + // Set socket to non-blocking. + flags = fcntl( sock, F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + if( 0 > fcntl( sock, F_SETFL, flags | O_NONBLOCK ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Close on exec. + if( 0 > fcntl( sock, F_SETFD, FD_CLOEXEC ) ) + { + DPRINTFE( "Failed to set fd, error=%s.", strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Allow address reuse on socket. + flags = 1; + result = setsockopt( sock, SOL_SOCKET, SO_REUSEADDR, + (void*) &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set reuseaddr socket option on interface (%s), " + "errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind address to socket. + memset( &src_addr, 0, sizeof(src_addr) ); + + src_addr.sin6_family = AF_INET6; + src_addr.sin6_port = htons(interface->network_port); + src_addr.sin6_addr = ipv6_address->sin6; + + result = bind( sock, (struct sockaddr *) &src_addr, sizeof(src_addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind unicast address to socket for " + "interface (%s), error=%s.", interface->interface_name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + // Bind socket to interface. + result = setsockopt( sock, SOL_SOCKET, SO_BINDTODEVICE, + interface->interface_name, + strlen(interface->interface_name)+1 ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind socket to interface (%s), " + "errno=%s.", interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Disable looping of sent multicast packets on socket. + flags = 0; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to stop looping of unicast messages for " + "interface (%s), errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket send priority on interface. + flags = IPTOS_CLASS_CS6; + result = setsockopt( sock, IPPROTO_IPV6, IPV6_TCLASS, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "unicast messages, errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + flags = 6; + result = setsockopt( sock, SOL_SOCKET, SO_PRIORITY, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket send priority for interface (%s) " + "unicast messages, errno=%s.", interface->interface_name, + strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + // Set socket receive packet information. + flags = 1; + result = setsockopt( sock, SOL_IPV6, IPV6_RECVPKTINFO, + &flags, sizeof(flags) ); + if( 0 > result ) + { + DPRINTFE( "Failed to set socket receive packet information for " + "interface (%s) unicast messages, errno=%s.", + interface->interface_name, strerror(errno) ); + close( sock ); + return( SM_FAILED ); + } + + *socket_fd = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Open Sockets +// ======================== +SmErrorT sm_msg_open_sockets( SmServiceDomainInterfaceT* interface ) +{ + SmErrorT error; + + if( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type ) + { + int unicast_socket, multicast_socket; + + error = sm_msg_open_ipv4_udp_unicast_socket( interface, + &unicast_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open unicast socket for interface (%s), " + "error=%s.", interface->interface_name, + sm_error_str(error) ); + return( error ); + } + + error = sm_selobj_register( unicast_socket, sm_msg_dispatch_ipv4_udp, + (int64_t) false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + close( unicast_socket ); + return( SM_FAILED ); + } + + if( interface->network_multicast.type != SM_NETWORK_TYPE_NIL ) + { + error = sm_msg_open_ipv4_udp_multicast_socket( interface, + &multicast_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open multicast socket for interface (%s), " + "error=%s.", interface->interface_name, + sm_error_str(error) ); + close( unicast_socket ); + return( error ); + } + + error = sm_selobj_register( multicast_socket, sm_msg_dispatch_ipv4_udp, + (int64_t) false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + close( unicast_socket ); + close( multicast_socket ); + return( SM_FAILED ); + } + + interface->unicast_socket = unicast_socket; + interface->multicast_socket = multicast_socket; + + error = sm_msg_register_ipv4_multicast( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register multicast address for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + close( unicast_socket ); + interface->unicast_socket = -1; + close( multicast_socket ); + interface->multicast_socket = -1; + return( SM_FAILED ); + } + } else + { + DPRINTFD( "Multicast not configured in the interface %s", interface->interface_name ); + interface->unicast_socket = unicast_socket; + interface->multicast_socket = -1; + } + + return( SM_OKAY ); + + } else if( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type ) { + int unicast_socket, multicast_socket; + + error = sm_msg_open_ipv6_udp_unicast_socket( interface, + &unicast_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open unicast socket for interface (%s), " + "error=%s.", interface->interface_name, + sm_error_str(error) ); + return( error ); + } + + error = sm_selobj_register( unicast_socket, sm_msg_dispatch_ipv6_udp, + (int64_t) false); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + close( unicast_socket ); + return( SM_FAILED ); + } + + if( interface->network_multicast.type != SM_NETWORK_TYPE_NIL ) + { + error = sm_msg_open_ipv6_udp_multicast_socket( interface, + &multicast_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open multicast socket for interface (%s), " + "error=%s.", interface->interface_name, + sm_error_str(error) ); + close( unicast_socket ); + return( error ); + } + + error = sm_selobj_register( multicast_socket, sm_msg_dispatch_ipv6_udp, + (int64_t) false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + close( unicast_socket ); + close( multicast_socket ); + return( SM_FAILED ); + } + + interface->unicast_socket = unicast_socket; + interface->multicast_socket = multicast_socket; + + error = sm_msg_register_ipv6_multicast( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register multicast address for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + close( unicast_socket ); + interface->unicast_socket = -1; + close( multicast_socket ); + interface->multicast_socket = -1; + return( SM_FAILED ); + } + } else + { + interface->unicast_socket = unicast_socket; + interface->multicast_socket = -1; + } + return( SM_OKAY ); + + } else { + DPRINTFE( "Unsupported network type (%s).", + sm_network_type_str( interface->network_type ) ); + return( SM_FAILED ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Close Sockets +// ========================= +SmErrorT sm_msg_close_sockets( SmServiceDomainInterfaceT* interface ) +{ + SmErrorT error; + + if( -1 < interface->unicast_socket ) + { + error = sm_selobj_deregister( interface->unicast_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + } + + close( interface->unicast_socket ); + interface->unicast_socket = -1; + } + + if( -1 < interface->multicast_socket ) + { + error = sm_selobj_deregister( interface->multicast_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + } + + if(( SM_NETWORK_TYPE_IPV4_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV4 == interface->network_type )) + { + error = sm_msg_deregister_ipv4_multicast( interface ); + + } else if(( SM_NETWORK_TYPE_IPV6_UDP == interface->network_type )|| + ( SM_NETWORK_TYPE_IPV6 == interface->network_type )) + { + error = sm_msg_deregister_ipv6_multicast( interface ); + } + + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister multicast address for " + "interface (%s), error=%s.", interface->interface_name, + sm_error_str(error) ); + } + + close( interface->multicast_socket ); + interface->multicast_socket = -1; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Dump Data +// ===================== +void sm_msg_dump_data( FILE* log ) +{ + fprintf( log, "--------------------------------------------------------------------\n" ); + fprintf( log, "MESSAGING DATA\n" ); + fprintf( log, " rcvd_total_msgs..............................%"PRIu64"\n", _rcvd_total_msgs ); + fprintf( log, " rcvd_msgs_while_disabled.....................%"PRIu64"\n", _rcvd_msgs_while_disabled ); + fprintf( log, " rcvd_bad_msg_auth............................%"PRIu64"\n", _rcvd_bad_msg_auth ); + fprintf( log, " rcvd_bad_msg_version.........................%"PRIu64"\n", _rcvd_bad_msg_version ); + fprintf( log, " send_node_hello_count........................%"PRIu64"\n", _send_node_hello_cnt ); + fprintf( log, " rcvd_node_hello_count........................%"PRIu64"\n", _rcvd_node_hello_cnt ); + fprintf( log, " send_node_update_count.......................%"PRIu64"\n", _send_node_update_cnt ); + fprintf( log, " rcvd_node_update_count.......................%"PRIu64"\n", _rcvd_node_update_cnt ); + fprintf( log, " send_node_swact_count........................%"PRIu64"\n", _send_node_swact_cnt ); + fprintf( log, " rcvd_node_swact_count........................%"PRIu64"\n", _rcvd_node_swact_cnt ); + fprintf( log, " send_node_swact_ack_count....................%"PRIu64"\n", _send_node_swact_ack_cnt ); + fprintf( log, " rcvd_node_swact_ack_count....................%"PRIu64"\n", _rcvd_node_swact_ack_cnt ); + fprintf( log, " send_service_domain_hello_count..............%"PRIu64"\n", _send_service_domain_hello_cnt ); + fprintf( log, " rcvd_service_domain_hello_count..............%"PRIu64"\n", _rcvd_service_domain_hello_cnt ); + fprintf( log, " send_service_domain_pause_count..............%"PRIu64"\n", _send_service_domain_pause_cnt ); + fprintf( log, " rcvd_service_domain_pause_count..............%"PRIu64"\n", _rcvd_service_domain_pause_cnt ); + fprintf( log, " send_service_domain_exchange_start_count.....%"PRIu64"\n", _send_service_domain_exchange_start_cnt ); + fprintf( log, " rcvd_service_domain_exchange_start_count.....%"PRIu64"\n", _rcvd_service_domain_exchange_start_cnt ); + fprintf( log, " send_service_domain_exchange_count...........%"PRIu64"\n", _send_service_domain_exchange_cnt ); + fprintf( log, " rcvd_service_domain_exchange_count...........%"PRIu64"\n", _rcvd_service_domain_exchange_cnt ); + fprintf( log, " send_service_domain_member_request_count.....%"PRIu64"\n", _send_service_domain_member_request_cnt ); + fprintf( log, " rcvd_service_domain_member_request_count.....%"PRIu64"\n", _rcvd_service_domain_member_request_cnt ); + fprintf( log, " send_service_domain_member_update_count......%"PRIu64"\n", _send_service_domain_member_update_cnt ); + fprintf( log, " rcvd_service_domain_member_update_count......%"PRIu64"\n", _rcvd_service_domain_member_update_cnt ); + fprintf( log, "--------------------------------------------------------------------\n" ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Initialize +// ====================== +SmErrorT sm_msg_initialize( void ) +{ + SmErrorT error; + + _hostname[0] = '\0'; + + error = sm_node_utils_get_hostname( _hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get local hostname." ); + return( SM_FAILED ); + } + + _messaging_enabled = false; + sm_uuid_create( _msg_instance ); + DPRINTFI( "Message instance (%s) created.", _msg_instance ); + + + DPRINTFV( "Hello message size is %i.", sizeof(SmMsgNodeHelloT) ); + DPRINTFV( "Node update message size is %i.", sizeof(SmMsgNodeUpdateT) ); + DPRINTFV( "Swact message size is %i.", sizeof(SmMsgNodeSwactT) ); + DPRINTFV( "Swact ack message size is %i.", sizeof(SmMsgNodeSwactAckT) ); + DPRINTFV( "Service Domain Hello message size is %i.", + sizeof(SmMsgServiceDomainHelloT) ); + DPRINTFV( "Service Domain Pause message size is %i.", + sizeof(SmMsgServiceDomainPauseT) ); + DPRINTFV( "Service Domain Exchange Start message size is %i.", + sizeof(SmMsgServiceDomainExchangeStartT) ); + DPRINTFV( "Service Domain Exchange message size is %i.", + sizeof(SmMsgServiceDomainExchangeT) ); + DPRINTFV( "Service Domain Member Request message size is %i.", + sizeof(SmMsgServiceDomainMemberRequestT) ); + DPRINTFV( "Service Domain Member Update message size is %i.", + sizeof(SmMsgServiceDomainMemberUpdateT) ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Messaging - Finalize +// ==================== +SmErrorT sm_msg_finalize( void ) +{ + _hostname[0] = '\0'; + _messaging_enabled = false; + memset( _msg_instance, 0, sizeof(_msg_instance) ); + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_msg.h b/service-mgmt/sm-1.0.0/src/sm_msg.h new file mode 100644 index 00000000..ca04bb32 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_msg.h @@ -0,0 +1,264 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_MSG_H__ +#define __SM_MSG_H__ + +#include +#include +#include + +#include "sm_types.h" +#include "sm_uuid.h" +#include "sm_service_domain_interface_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmMsgNodeHelloCallbackT) (SmNetworkAddressT* network_address, + int network_port, int version, int revision, char node_name[], + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status, SmNodeReadyStateT ready_state, + SmUuidT state_uuid, long uptime); + +typedef void (*SmMsgNodeUpdateCallbackT) (SmNetworkAddressT* network_address, + int network_port, int version, int revision, char node_name[], + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status, SmNodeReadyStateT ready_state, + SmUuidT old_state_uuid, SmUuidT state_uuid, long uptime, bool force); + +typedef void (*SmMsgNodeSwactCallbackT) ( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char node_name[], bool force, SmUuidT request_uuid ); + +typedef void (*SmMsgNodeSwactAckCallbackT) ( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char node_name[], bool force, SmUuidT request_uuid ); + +typedef void (*SmMsgHelloCallbackT) (SmNetworkAddressT* network_address, + int network_port, int version, int revision, char service_domain[], + char node_name[], char orchestration[], char designation[], + int generation, int priority, int hello_interval, int dead_interval, + int wait_interval, int exchange_interval, char leader[]); + +typedef void (*SmMsgPauseCallbackT) (SmNetworkAddressT* network_address, + int network_port, int version, int revision, char service_domain[], + char node_name[], int pause_interval); + +typedef void (*SmMsgExchangeStartCallbackT) (SmNetworkAddressT* network_address, + int network_port, int version, int revision, char service_domain[], + char node_name[], int exchange_seq); + +typedef void (*SmMsgExchangeCallbackT) (SmNetworkAddressT* network_address, + int network_port, int version, int revision, char service_domain[], + char node_name[], int exchange_seq, int64_t member_id, + char member_name[], SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t member_health, + char reason_text[], bool more_members, int64_t last_received_member_id ); + +typedef void (*SmMsgMemberRequestCallbackT) (SmNetworkAddressT* network_address, + int network_port, int version, int revision, char service_domain[], + char node_name[], char member_node_name[], int64_t member_id, + char member_name[], SmServiceGroupActionT member_action, + SmServiceGroupActionFlagsT member_action_flags ); + +typedef void (*SmMsgMemberUpdateCallbackT) (SmNetworkAddressT* network_address, + int network_port, int version, int revision, char service_domain[], + char node_name[], char member_node_name[], int64_t member_id, + char member_name[], SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT condition, int64_t member_health, + char reason_text[] ); + +typedef struct +{ + // Node Message Callbacks + SmMsgNodeHelloCallbackT node_hello; + SmMsgNodeUpdateCallbackT node_update; + SmMsgNodeSwactCallbackT node_swact; + SmMsgNodeSwactCallbackT node_swact_ack; + + // Service Domain Message Callbacks + SmMsgHelloCallbackT hello; + SmMsgPauseCallbackT pause; + SmMsgExchangeStartCallbackT exchange_start; + SmMsgExchangeCallbackT exchange; + SmMsgMemberRequestCallbackT member_request; + SmMsgMemberUpdateCallbackT member_update; +} SmMsgCallbacksT; + +// **************************************************************************** +// Messaging - Enable +// ================== +extern void sm_msg_enable( void ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Disable +// =================== +extern void sm_msg_disable( void ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Add Peer Interface +// ============================== +extern SmErrorT sm_msg_add_peer_interface( char interface_name[], + SmNetworkAddressT* network_address, int network_port, + SmAuthTypeT auth_type, char auth_key[] ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Delete Peer Interface +// ================================= +extern SmErrorT sm_msg_delete_peer_interface( char interface_name[], + SmNetworkAddressT* network_address, int network_port ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Register Callbacks +// ============================== +extern SmErrorT sm_msg_register_callbacks( SmMsgCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Deregister Callbacks +// ================================ +extern SmErrorT sm_msg_deregister_callbacks( SmMsgCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Increment Sequence Number +// ===================================== +extern void sm_msg_increment_seq_num( void ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Node Hello +// =========================== +extern SmErrorT sm_msg_send_node_hello( char node_name[], + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status, SmNodeReadyStateT ready_state, + SmUuidT state_uuid, long uptime, SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Node Update +// ============================ +extern SmErrorT sm_msg_send_node_update( char node_name[], + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status, SmNodeReadyStateT ready_state, + SmUuidT old_state_uuid, SmUuidT state_uuid, long uptime, bool force, + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Node Swact +// =========================== +extern SmErrorT sm_msg_send_node_swact( char node_name[], bool force, + SmUuidT request_uuid, SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Node Swact Ack +// =============================== +extern SmErrorT sm_msg_send_node_swact_ack( char node_name[], bool force, + SmUuidT request_uuid, SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Hello +// ===================================== +extern SmErrorT sm_msg_send_service_domain_hello( char node_name[], + SmOrchestrationTypeT orchestration, SmDesignationTypeT designation, + int generation, int priority, int hello_interval, int dead_interval, + int wait_interval, int exchange_interval, char leader[], + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Pause +// ===================================== +extern SmErrorT sm_msg_send_service_domain_pause( char node_name[], + int pause_interval, SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Exchange Start +// ============================================== +extern SmErrorT sm_msg_send_service_domain_exchange_start( char node_name[], + char exchange_node_name[], int exchange_seq, + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Exchange +// ======================================== +extern SmErrorT sm_msg_send_service_domain_exchange( char node_name[], + char exchange_node_name[], int exchange_seq, int64_t member_id, + char member_name[], SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t member_health, + char reason_text[], bool more_members, int64_t last_received_member_id, + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Member Request +// ============================================== +extern SmErrorT sm_msg_send_service_domain_member_request( char node_name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupActionT member_action, + SmServiceGroupActionFlagsT member_action_flags, + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Send Service Domain Member Update +// ============================================= +extern SmErrorT sm_msg_send_service_domain_member_update( char node_name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t member_health, + const char reason_text[], SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Open Sockets +// ======================== +extern SmErrorT sm_msg_open_sockets( SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Close Sockets +// ========================= +extern SmErrorT sm_msg_close_sockets( SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Dump Data +// ===================== +extern void sm_msg_dump_data( FILE* log ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Initialize +// ====================== +extern SmErrorT sm_msg_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Messaging - Finalize +// ==================== +extern SmErrorT sm_msg_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_MSG_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_node_api.cpp b/service-mgmt/sm-1.0.0/src/sm_node_api.cpp new file mode 100644 index 00000000..8ea9203f --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_api.cpp @@ -0,0 +1,1108 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_node_api.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_selobj.h" +#include "sm_time.h" +#include "sm_timer.h" +#include "sm_uuid.h" +#include "sm_msg.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_nodes.h" +#include "sm_db_node_history.h" +#include "sm_node_utils.h" +#include "sm_node_fsm.h" +#include "sm_service_domain_scheduler.h" +#include "sm_service_domain_interface_table.h" +#include "sm_log.h" +#include "sm_alarm.h" +#include "sm_log.h" +#include "sm_troubleshoot.h" +#include "sm_node_swact_monitor.h" + +#define SM_REBOOT_DELAY_IN_MS 30000 +#define SM_REBOOT_TIMEOUT_IN_MINS 8 +#define SM_REBOOT_TIMEOUT_IN_MS (SM_REBOOT_TIMEOUT_IN_MINS*60*1000) + +static SmDbHandleT* _sm_db_handle = NULL; +static SmMsgCallbacksT _msg_callbacks = {0}; + +static SmTimerIdT _reboot_delay_timer_id = SM_TIMER_ID_INVALID; +static SmTimerIdT _reboot_timer_id = SM_TIMER_ID_INVALID; + +// **************************************************************************** +// Node API - Get Host Name +// ======================== +SmErrorT sm_node_api_get_hostname( char node_name[] ) +{ + return( sm_node_utils_get_hostname( node_name ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Configuration Complete +// ================================= +SmErrorT sm_node_api_config_complete( char node_name[], bool* complete ) +{ + return( sm_node_utils_config_complete( complete ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Interface Send Node Hello +// ==================================== +static void sm_node_api_interface_send_node_hello( void* user_data[], + SmServiceDomainInterfaceT* interface ) +{ + SmDbNodeT* node = (SmDbNodeT*) user_data[0]; + long uptime = *(long*) user_data[1]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_node_hello( node->name, node->admin_state, + node->oper_state, node->avail_status, + node->ready_state, node->state_uuid, + uptime, interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send node (%s) hello, error=%s.", + node->name, sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Send Node Hello +// ========================== +static SmErrorT sm_node_api_send_node_hello( SmDbNodeT* node ) +{ + long uptime; + void* user_data[] = {node, &uptime}; + SmErrorT error; + + error = sm_node_utils_get_uptime( &uptime ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to to get local node uptime, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach( user_data, + sm_node_api_interface_send_node_hello ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Interface Send Node Update +// ===================================== +static void sm_node_api_interface_send_node_update( void* user_data[], + SmServiceDomainInterfaceT* interface ) +{ + SmUuidPtrT old_state_uuid = (SmUuidPtrT) user_data[0]; + SmDbNodeT* node = (SmDbNodeT*) user_data[1]; + long uptime = *(long*) user_data[2]; + bool force = *(bool*) user_data[3]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_node_update( node->name, node->admin_state, + node->oper_state, node->avail_status, + node->ready_state, old_state_uuid, + node->state_uuid, uptime, force, + interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send node (%s) update, error=%s.", + node->name, sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Send Node Update +// =========================== +static SmErrorT sm_node_api_send_node_update( SmUuidT old_state_uuid, + SmDbNodeT* node, bool force ) +{ + long uptime; + void* user_data[] = {old_state_uuid, node, &uptime, &force}; + SmErrorT error; + + error = sm_node_utils_get_uptime( &uptime ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to to get local node uptime, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach( user_data, + sm_node_api_interface_send_node_update ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Interface Send Node Swact +// ==================================== +static void sm_node_api_interface_send_node_swact( void* user_data[], + SmServiceDomainInterfaceT* interface ) +{ + SmUuidPtrT request_uuid = (SmUuidPtrT) user_data[0]; + SmDbNodeT* node = (SmDbNodeT*) user_data[1]; + bool force = *(bool*) user_data[2]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_node_swact( node->name, force, request_uuid, + interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send node (%s) swact, error=%s.", + node->name, sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Send Node Swact +// ========================== +static SmErrorT sm_node_api_send_node_swact( SmDbNodeT* node, bool force, + SmUuidT request_uuid ) +{ + void* user_data[] = {request_uuid, node, &force}; + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach( user_data, + sm_node_api_interface_send_node_swact ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Node Hello Callback +// ============================== +static void sm_node_api_node_hello_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char node_name[], SmNodeAdminStateT admin_state, + SmNodeOperationalStateT oper_state, SmNodeAvailStatusT avail_status, + SmNodeReadyStateT ready_state, SmUuidT state_uuid, long uptime ) +{ + long local_uptime; + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmUuidT new_state_uuid; + SmDbNodeT node; + SmDbNodeHistoryT node_history; + SmErrorT error; + + sm_uuid_create( new_state_uuid ); + + error = sm_node_utils_get_uptime( &local_uptime ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to to get local node uptime, error=%s.", + sm_error_str( error ) ); + return; + } + + error = sm_db_nodes_read( _sm_db_handle, node_name, &node ); + if( SM_OKAY == error ) + { + if( 0 == strcmp( state_uuid, node.state_uuid ) ) + { + if(( admin_state == node.admin_state )&& + ( oper_state == node.oper_state ) && + ( ready_state == node.ready_state )) + { + DPRINTFD( "Node (%s) info up to date.", node_name ); + return; + } + + if( admin_state != node.admin_state ) + { + sm_log_node_state_change( node_name, + sm_node_state_str( node.admin_state, node.ready_state ), + sm_node_state_str( admin_state, node.ready_state ), + "customer action" ); + } + + node.admin_state = admin_state; + node.oper_state = oper_state; + node.avail_status = avail_status; + node.ready_state = ready_state; + + error = sm_db_nodes_update( _sm_db_handle, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return; + } + + return; + + } else { + DPRINTFI( "Node (%s) received=%s, have=%s.", node_name, + state_uuid, node.state_uuid ); + } + + snprintf( db_query, sizeof(db_query), "%s = '%s' and %s = '%s'", + SM_NODES_TABLE_COLUMN_NAME, node_name, + SM_NODES_TABLE_COLUMN_STATE_UUID, state_uuid ); + + error = sm_db_node_history_query( _sm_db_handle, db_query, + &node_history ); + if( SM_OKAY == error ) + { + DPRINTFI( "Send update for node (%s) uuid=%s.", node_name, + state_uuid ); + + error = sm_node_api_send_node_update( state_uuid, &node, false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send node (%s) update, error=%s.", + node_name, sm_error_str( error ) ); + return; + } + } else if( SM_NOT_FOUND ) { + if( uptime <= local_uptime ) + { + DPRINTFI( "Send update for node (%s) uuid=%s, uptime=%ld, " + "local_uptime=%ld.", node_name, state_uuid, uptime, + local_uptime ); + + error = sm_node_api_send_node_update( state_uuid, &node, + false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send node (%s) update, error=%s.", + node_name, sm_error_str( error ) ); + return; + } + } else { + DPRINTFI( "Update node (%s) uuid=%s, was=%s.", node_name, + state_uuid, node.state_uuid ); + + snprintf( node_history.name, sizeof(node_history.name), + "%s", node.name ); + node_history.admin_state = node.admin_state; + node_history.oper_state = node.oper_state; + node_history.avail_status = node.avail_status; + node_history.ready_state = node.ready_state; + snprintf( node_history.state_uuid, + sizeof(node_history.state_uuid), + "%s", node.state_uuid ); + + error = sm_db_node_history_insert( _sm_db_handle, + &node_history ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to save node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return; + } + + if( admin_state != node.admin_state ) + { + sm_log_node_state_change( node_name, + sm_node_state_str( node.admin_state, node.ready_state ), + sm_node_state_str( admin_state, node.ready_state ), + "customer action" ); + } + + node.admin_state = admin_state; + node.oper_state = oper_state; + node.avail_status = avail_status; + node.ready_state = ready_state; + snprintf( node.state_uuid, sizeof(node.state_uuid), "%s", + state_uuid ); + + error = sm_db_nodes_update( _sm_db_handle, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return; + } + } + } else { + DPRINTFE( "Failed to read node history (%s), error=%s.", + node_name, sm_error_str( error ) ); + return; + } + + } else if( SM_NOT_FOUND == error ) { + DPRINTFI( "Inserting node (%s), uuid=%s.", node_name, + new_state_uuid ); + + snprintf( node.name, SM_NODE_NAME_MAX_CHAR, "%s", node_name ); + node.admin_state = admin_state; + node.oper_state = oper_state; + node.avail_status = avail_status; + node.ready_state = ready_state; + snprintf( node.state_uuid, sizeof(node.state_uuid), "%s", + new_state_uuid ); + + error = sm_db_nodes_insert( _sm_db_handle, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to insert node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return; + } + + sm_log_node_state_change( node_name, + sm_node_state_str( SM_NODE_ADMIN_STATE_UNKNOWN, + SM_NODE_READY_STATE_UNKNOWN ), + sm_node_state_str( node.admin_state, node.ready_state ), + "customer action" ); + + } else { + DPRINTFE( "Failed to read node (%s), error=%s.", node_name, + sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Node Update Callback +// =============================== +static void sm_node_api_node_update_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char node_name[], SmNodeAdminStateT admin_state, + SmNodeOperationalStateT oper_state, SmNodeAvailStatusT avail_status, + SmNodeReadyStateT ready_state, SmUuidT old_state_uuid, SmUuidT state_uuid, + long uptime, bool force ) +{ + bool update = false; + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbNodeT node; + SmDbNodeHistoryT node_history; + SmErrorT error; + + if( force ) + { + error = sm_db_nodes_query( _sm_db_handle, NULL, &node ); + if( SM_OKAY == error ) + { + update = true; + DPRINTFI("Updating node (%s) info.", node_name ); + + } else if( SM_NOT_FOUND != error ) { + DPRINTFE( "Failed to read node (%s), error=%s.", node_name, + sm_error_str( error ) ); + return; + } + } else { + snprintf( db_query, sizeof(db_query), "%s = '%s' and %s = '%s'", + SM_NODES_TABLE_COLUMN_NAME, node_name, + SM_NODES_TABLE_COLUMN_STATE_UUID, old_state_uuid ); + + error = sm_db_nodes_query( _sm_db_handle, db_query, &node ); + if( SM_OKAY == error ) + { + update = true; + DPRINTFI("Updating node (%s) info.", node_name ); + + } else if( SM_NOT_FOUND != error ) { + DPRINTFE( "Failed to read node (%s), error=%s.", node_name, + sm_error_str( error ) ); + return; + } + } + + if( update ) + { + if( admin_state != node.admin_state ) + { + sm_log_node_state_change( node_name, + sm_node_state_str( node.admin_state, node.ready_state ), + sm_node_state_str( admin_state, node.ready_state ), + "customer action" ); + } + + snprintf( node_history.name, sizeof(node_history.name), + "%s", node.name ); + node_history.admin_state = node.admin_state; + node_history.oper_state = node.oper_state; + node_history.avail_status = node.avail_status; + node_history.ready_state = node.ready_state; + snprintf( node_history.state_uuid, sizeof(node_history.state_uuid), + "%s", node.state_uuid ); + + error = sm_db_node_history_insert( _sm_db_handle, &node_history ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to save node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return; + } + + node.admin_state = admin_state; + node.oper_state = oper_state; + node.avail_status = avail_status; + node.ready_state = ready_state; + snprintf( node.state_uuid, sizeof(node.state_uuid), "%s", + state_uuid ); + + error = sm_db_nodes_update( _sm_db_handle, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Add Node +// =================== +SmErrorT sm_node_api_add_node( char node_name[] ) +{ + SmDbNodeT node; + SmUuidT state_uuid; + SmErrorT error; + + sm_uuid_create( state_uuid ); + + error = sm_db_nodes_read( _sm_db_handle, node_name, &node ); + if( SM_OKAY == error ) + { + DPRINTFD( "Already added node (%s).", node_name ); + + } else if( SM_NOT_FOUND == error ) { + + snprintf( node.name, SM_NODE_NAME_MAX_CHAR, "%s", node_name ); + node.admin_state = SM_NODE_ADMIN_STATE_UNLOCKED; + node.oper_state = SM_NODE_OPERATIONAL_STATE_ENABLED; + node.avail_status = SM_NODE_AVAIL_STATUS_AVAILABLE; + node.ready_state = SM_NODE_READY_STATE_UNKNOWN; + snprintf( node.state_uuid, sizeof(node.state_uuid), "%s", + state_uuid ); + + error = sm_db_nodes_insert( _sm_db_handle, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to insert node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + DPRINTFI( "Added node (%s).", node.name ); + + sm_log_node_state_change( node_name, + sm_node_state_str( SM_NODE_ADMIN_STATE_UNKNOWN, + SM_NODE_READY_STATE_UNKNOWN ), + sm_node_state_str( node.admin_state, node.ready_state ), + "customer action" ); + + } else { + DPRINTFE( "Failed to read node (%s) information, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Update Node +// ====================== +SmErrorT sm_node_api_update_node( char node_name[], + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status ) +{ + bool send_update = false; + SmUuidT old_state_uuid; + SmUuidT new_state_uuid; + SmDbNodeT node; + SmDbNodeHistoryT node_history; + SmErrorT error; + + sm_uuid_create( new_state_uuid ); + + error = sm_db_nodes_read( _sm_db_handle, node_name, &node ); + if( SM_OKAY == error ) + { + if( admin_state != node.admin_state ) + { + sm_log_node_state_change( node_name, + sm_node_state_str( node.admin_state, node.ready_state ), + sm_node_state_str( admin_state, node.ready_state ), + "customer action" ); + } + + if( oper_state != node.oper_state ) + { + sm_log_node_state_change( node_name, + sm_node_oper_state_str( node.oper_state ), + sm_node_oper_state_str( oper_state ), + "oper state changed" ); + } + + if(( admin_state != node.admin_state )|| + ( oper_state != node.oper_state )) + { + memcpy( old_state_uuid, node.state_uuid, sizeof(old_state_uuid) ); + + snprintf( node_history.name, sizeof(node_history.name), + "%s", node.name ); + + node_history.admin_state = node.admin_state; + node_history.oper_state = node.oper_state; + node_history.avail_status = node.avail_status; + node_history.ready_state = node.ready_state; + snprintf( node_history.state_uuid, sizeof(node_history.state_uuid), + "%s", node.state_uuid ); + + error = sm_db_node_history_insert( _sm_db_handle, &node_history ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to save node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + node.admin_state = admin_state; + node.oper_state = oper_state; + node.avail_status = avail_status; + snprintf( node.state_uuid, sizeof(node.state_uuid), "%s", + new_state_uuid ); + + error = sm_db_nodes_update( _sm_db_handle, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + send_update = true; + } + } else if( SM_NOT_FOUND == error ) { + + memset( old_state_uuid, 0, sizeof(old_state_uuid) ); + + snprintf( node.name, SM_NODE_NAME_MAX_CHAR, "%s", node_name ); + + node.admin_state = admin_state; + node.oper_state = oper_state; + node.avail_status = avail_status; + node.ready_state = SM_NODE_READY_STATE_DISABLED; + snprintf( node.state_uuid, sizeof(node.state_uuid), "%s", + new_state_uuid ); + + error = sm_db_nodes_insert( _sm_db_handle, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to insert node (%s) info, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + sm_log_node_state_change( node_name, + sm_node_state_str( SM_NODE_ADMIN_STATE_UNKNOWN, + SM_NODE_READY_STATE_UNKNOWN ), + sm_node_state_str( node.admin_state, node.ready_state ), + "customer action" ); + + send_update = true; + + } else { + DPRINTFE( "Failed to read node (%s) information, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + if( send_update ) + { + error = sm_node_api_send_node_update( old_state_uuid, &node, true ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send node (%s) node update, error=%s.", + node_name, sm_error_str(error) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Fail Node +// ====================== +SmErrorT sm_node_api_fail_node( char node_name[] ) +{ + SmDbNodeT node; + SmErrorT error; + error = sm_db_nodes_read( _sm_db_handle, node_name, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read node (%s) information, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + if( node.oper_state == SM_NODE_OPERATIONAL_STATE_DISABLED && + node.avail_status == SM_NODE_AVAIL_STATUS_FAILED ) + { + DPRINTFD("Already in failure mode %s", node_name); + } + + DPRINTFE("Node %s is entering to failure mode.", node_name); + + error = sm_node_api_update_node( + node_name, + node.admin_state, + SM_NODE_OPERATIONAL_STATE_DISABLED, + SM_NODE_AVAIL_STATUS_FAILED); + + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set node (%s) failed, error=%s.", + node_name, sm_error_str( error ) ); + } + return( error ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Delete Node +// ====================== +SmErrorT sm_node_api_delete_node( char node_name[] ) +{ + SmErrorT error; + + error = sm_db_nodes_delete( _sm_db_handle, node_name ); + + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to delete node, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Swact +// ================ +SmErrorT sm_node_api_swact( char node_name[], bool force ) +{ + SmUuidT request_uuid; + SmDbNodeT node; + SmErrorT error; + + sm_uuid_create( request_uuid ); + + error = sm_db_nodes_read( _sm_db_handle, node_name, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read node (%s) information, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + error = sm_node_api_send_node_swact( &node, force, request_uuid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send node (%s) swact, error=%s.", + node_name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_scheduler_swact_node( node_name, force, + request_uuid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set node scheduling state, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Reboot Timeout +// ========================= +static bool sm_node_api_reboot_timeout( SmTimerIdT timer_id, int64_t user_data ) +{ + int sysrq_handler_fd; + int sysrq_tigger_fd; + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + } + + // Enable sysrq handling. + sysrq_handler_fd = open( "/proc/sys/kernel/sysrq", O_RDWR | O_CLOEXEC ); + if( 0 > sysrq_handler_fd ) + { + DPRINTFE( "Failed to open sysrq handler file, error=%s.", + strerror(errno) ); + return( true ); + } + + write( sysrq_handler_fd, "1", 1 ); + close( sysrq_handler_fd ); + + // Trigger sysrq command. + sysrq_tigger_fd = open( "/proc/sysrq-trigger", O_RDWR | O_CLOEXEC ); + if( 0 > sysrq_tigger_fd ) + { + DPRINTFE( "Failed to open sysrq trigger file, error=%s.", + strerror(errno) ); + return( true ); + } + + snprintf( reason_text, sizeof(reason_text), "timed out after %i minute%s " + "waiting for a controlled reboot, escalating to a forced reboot", + SM_REBOOT_TIMEOUT_IN_MINS, + (1 == SM_REBOOT_TIMEOUT_IN_MINS) ? "" : "s" ); + + sm_log_node_reboot( hostname, reason_text, true ); + + DPRINTFI( "******************************************************" + "************************************" ); + DPRINTFI( "** Issuing an immediate reboot of the system, without " + "unmounting or syncing filesystems **" ); + DPRINTFI( "******************************************************" + "************************************" ); + + sleep(5); // wait 5 seconds before a forced reboot. + write( sysrq_tigger_fd, "b", 1 ); + close( sysrq_tigger_fd ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Reboot Delay +// ======================= +static bool sm_node_api_reboot_delay( SmTimerIdT timer_id, int64_t user_data ) +{ + pid_t pid; + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + } + + snprintf( reason_text, sizeof(reason_text), "reboot delay expired, " + "issuing reboot" ); + + sm_log_node_reboot( hostname, reason_text, false ); + + DPRINTFI( "***********************************************" ); + DPRINTFI( "** Issuing a controlled reboot of the system **" ); + DPRINTFI( "***********************************************" ); + + pid = fork(); + if( 0 > pid ) + { + DPRINTFE( "Failed to fork process for reboot, error=%s.", + strerror( errno ) ); + return( true ); + + } else if( 0 == pid ) { + // Child process. + struct rlimit file_limits; + char reboot_cmd[] = "reboot"; + char* reboot_argv[] = {reboot_cmd, NULL}; + char* reboot_env[] = {NULL}; + + setpgid( 0, 0 ); + + if( 0 == getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + unsigned int fd_i; + for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i ) + { + close( fd_i ); + } + + open( "/dev/null", O_RDONLY ); // stdin + open( "/dev/null", O_WRONLY ); // stdout + open( "/dev/null", O_WRONLY ); // stderr + } + + execve( "/sbin/reboot", reboot_argv, reboot_env ); + + // Shouldn't get this far, else there was an error. + exit(-1); + + } else { + // Parent process. + SmErrorT error; + + DPRINTFI( "Child process (%i) created for reboot.", (int) pid ); + + error = sm_timer_register( "reboot force", SM_REBOOT_TIMEOUT_IN_MS, + sm_node_api_reboot_timeout, 0, + &_reboot_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create reboot timer, error=%s.", + sm_error_str( error ) ); + return( true ); + } + } + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Reboot +// ================= +SmErrorT sm_node_api_reboot( char reason_text[] ) +{ + if( SM_TIMER_ID_INVALID == _reboot_delay_timer_id ) + { + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Reboot of %s requested, reason=%s.", hostname, + reason_text ); + + sm_log_node_reboot( hostname, reason_text, false ); + + sm_troubleshoot_dump_data( reason_text ); + + // Give some time to allow the dump data to finish before + // actually attempting a reboot. + error = sm_timer_register( "reboot delay", SM_REBOOT_DELAY_IN_MS, + sm_node_api_reboot_delay, 0, + &_reboot_delay_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create reboot delay timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Send Event +// ===================== +static SmErrorT sm_node_api_send_event( void* user_data[], void* record ) +{ + SmNodeEventT* event = (SmNodeEventT*) user_data[0]; + const char* reason_text = (char*) user_data[1]; + SmDbNodeT* node = (SmDbNodeT*) record; + SmErrorT error; + + error = sm_node_api_send_node_hello( node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send hello for node (%s), error=%s.", + node->name, sm_error_str( error ) ); + } + + error = sm_node_fsm_event_handler( node->name, *event, NULL, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for node (%s), error=%s.", + sm_node_event_str( *event ), node->name, + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Audit +// ================ +SmErrorT sm_node_api_audit( void ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = "audit requested"; + SmNodeEventT event = SM_NODE_EVENT_AUDIT; + SmDbNodeT node; + SmErrorT error; + void* user_data[] = { &event, reason_text }; + + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", sm_error_str( error ) ); + return( error ); + } + + snprintf( db_query, sizeof(db_query), "%s = '%s'", + SM_NODES_TABLE_COLUMN_NAME, hostname ); + + error = sm_db_foreach( SM_DATABASE_NAME, SM_NODES_TABLE_NAME, db_query, + &node, sm_db_nodes_convert, sm_node_api_send_event, + user_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over nodes, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** +void sm_node_api_node_swact_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char node_name[], bool force, SmUuidT request_uuid ) +{ + SmNodeSwactMonitor::SwactStart(SM_NODE_STATE_ACTIVE); +} + +// **************************************************************************** +// Node API - Initialize +// ===================== +SmErrorT sm_node_api_initialize( void ) +{ + SmErrorT error; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_node_fsm_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node fsm, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + memset( &_msg_callbacks, 0, sizeof(_msg_callbacks) ); + + _msg_callbacks.node_hello = sm_node_api_node_hello_callback; + _msg_callbacks.node_update = sm_node_api_node_update_callback; + _msg_callbacks.node_swact = sm_node_api_node_swact_callback; + + error = sm_msg_register_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register messaging callbacks, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node API - Finalize +// =================== +SmErrorT sm_node_api_finalize( void ) +{ + SmErrorT error; + + error = sm_msg_deregister_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister messaging callbacks, error=%s.", + sm_error_str( error ) ); + } + + memset( &_msg_callbacks, 0, sizeof(_msg_callbacks) ); + + error = sm_node_fsm_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize node fsm, error=%s.", + sm_error_str( error ) ); + } + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_node_api.h b/service-mgmt/sm-1.0.0/src/sm_node_api.h new file mode 100644 index 00000000..da3b2e43 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_api.h @@ -0,0 +1,90 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NODE_API_H__ +#define __SM_NODE_API_H__ + +#include + +#include "sm_types.h" +#include "sm_uuid.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Node API - Get Host Name +// ======================== +extern SmErrorT sm_node_api_get_hostname( char node_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Configuration Complete +// ================================= +extern SmErrorT sm_node_api_config_complete( char node_name[], bool* complete ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Add Node +// =================== +extern SmErrorT sm_node_api_add_node( char node_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Update Node +// ====================== +extern SmErrorT sm_node_api_update_node( char node_name[], + SmNodeAdminStateT admin_state, SmNodeOperationalStateT oper_state, + SmNodeAvailStatusT avail_status ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Fail Node +// ====================== +SmErrorT sm_node_api_fail_node( char node_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Delete Node +// ====================== +extern SmErrorT sm_node_api_delete_node( char node_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Swact +// ================ +extern SmErrorT sm_node_api_swact( char node_name[], bool force ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Reboot +// ================= +extern SmErrorT sm_node_api_reboot( char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Audit +// ================ +extern SmErrorT sm_node_api_audit( void ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Initialize +// ===================== +extern SmErrorT sm_node_api_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Node API - Finalize +// =================== +extern SmErrorT sm_node_api_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NODE_API_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_node_disabled_state.c b/service-mgmt/sm-1.0.0/src/sm_node_disabled_state.c new file mode 100644 index 00000000..e5bc028e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_disabled_state.c @@ -0,0 +1,131 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_node_disabled_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_hw.h" +#include "sm_db.h" +#include "sm_db_nodes.h" +#include "sm_node_utils.h" +#include "sm_node_fsm.h" + +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Node Disabled State - Entry +// =========================== +SmErrorT sm_node_disabled_state_entry( SmDbNodeT* node ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Exit +// ========================== +SmErrorT sm_node_disabled_state_exit( SmDbNodeT* node ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Transition +// ================================ +SmErrorT sm_node_disabled_state_transition( SmDbNodeT* node, + SmNodeReadyStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Event Handler +// =================================== +SmErrorT sm_node_disabled_state_event_handler( SmDbNodeT* node, + SmNodeEventT event, void* event_data[] ) +{ + bool enabled; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + switch( event ) + { + case SM_NODE_EVENT_ENABLED: + error = sm_node_fsm_set_state( node->name, + SM_NODE_READY_STATE_ENABLED, + "node ready" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of node (%s) failed, error=%s.", + sm_node_ready_state_str( SM_NODE_READY_STATE_ENABLED ), + node->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_EVENT_DISABLED: + // Ignoring, already disabled. + break; + + case SM_NODE_EVENT_AUDIT: + error = sm_node_utils_enabled( &enabled, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if node (%s) is enabled, " + "error=%s.", node->name, sm_error_str( error ) ); + return( error ); + } + + if( enabled ) + { + error = sm_node_fsm_set_state( node->name, + SM_NODE_READY_STATE_ENABLED, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of node (%s) failed, error=%s.", + sm_node_ready_state_str( SM_NODE_READY_STATE_ENABLED ), + node->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + default: + DPRINTFD( "Node (%s) ignoring event (%s).", node->name, + sm_node_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Initialize +// ================================ +SmErrorT sm_node_disabled_state_initialize( SmDbHandleT* sm_db_handle ) +{ + _sm_db_handle = sm_db_handle; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Finalize +// ============================== +SmErrorT sm_node_disabled_state_finalize( void ) +{ + _sm_db_handle = NULL; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_node_disabled_state.h b/service-mgmt/sm-1.0.0/src/sm_node_disabled_state.h new file mode 100644 index 00000000..677f45ba --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_disabled_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NODE_DISABLED_STATE_H__ +#define __SM_NODE_DISABLED_STATE_H__ + +#include "sm_types.h" +#include "sm_db.h" +#include "sm_db_nodes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Node Disabled State - Entry +// =========================== +extern SmErrorT sm_node_disabled_state_entry( SmDbNodeT* node ); +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Exit +// ========================== +extern SmErrorT sm_node_disabled_state_exit( SmDbNodeT* node ); +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Transition +// ================================ +extern SmErrorT sm_node_disabled_state_transition( SmDbNodeT* node, + SmNodeReadyStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Event Handler +// =================================== +extern SmErrorT sm_node_disabled_state_event_handler( SmDbNodeT* node, + SmNodeEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Initialize +// ================================ +extern SmErrorT sm_node_disabled_state_initialize( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Node Disabled State - Finalize +// ============================== +extern SmErrorT sm_node_disabled_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NODE_DISABLED_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_node_enabled_state.c b/service-mgmt/sm-1.0.0/src/sm_node_enabled_state.c new file mode 100644 index 00000000..7ef46e09 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_enabled_state.c @@ -0,0 +1,134 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_node_enabled_state.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_msg.h" +#include "sm_hw.h" +#include "sm_db.h" +#include "sm_db_nodes.h" +#include "sm_node_utils.h" +#include "sm_node_fsm.h" + +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Node Enabled State - Entry +// ========================== +SmErrorT sm_node_enabled_state_entry( SmDbNodeT* node ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Exit +// ========================= +SmErrorT sm_node_enabled_state_exit( SmDbNodeT* node ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Transition +// =============================== +SmErrorT sm_node_enabled_state_transition( SmDbNodeT* node, + SmNodeReadyStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Event Handler +// ================================== +SmErrorT sm_node_enabled_state_event_handler( SmDbNodeT* node, + SmNodeEventT event, void* event_data[] ) +{ + bool enabled; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + switch( event ) + { + case SM_NODE_EVENT_ENABLED: + // Ignore, already enabled. + break; + + case SM_NODE_EVENT_DISABLED: + error = sm_node_fsm_set_state( node->name, + SM_NODE_READY_STATE_DISABLED, + "node not ready" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of node (%s), error=%s.", + sm_node_ready_state_str( SM_NODE_READY_STATE_DISABLED ), + node->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_EVENT_AUDIT: + error = sm_node_utils_enabled( &enabled, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if node (%s) is enabled, " + "error=%s.", node->name, sm_error_str( error ) ); + return( error ); + } + + if( !enabled ) + { + error = sm_node_fsm_set_state( node->name, + SM_NODE_READY_STATE_DISABLED, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of node (%s), error=%s.", + sm_node_ready_state_str( SM_NODE_READY_STATE_DISABLED ), + node->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + default: + DPRINTFD( "Node (%s) ignoring event (%s).", node->name, + sm_node_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Initialize +// =============================== +SmErrorT sm_node_enabled_state_initialize( SmDbHandleT* sm_db_handle ) +{ + _sm_db_handle = sm_db_handle; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Finalize +// ============================= +SmErrorT sm_node_enabled_state_finalize( void ) +{ + _sm_db_handle = NULL; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_node_enabled_state.h b/service-mgmt/sm-1.0.0/src/sm_node_enabled_state.h new file mode 100644 index 00000000..8b4f2087 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_enabled_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NODE_ENABLED_STATE_H__ +#define __SM_NODE_ENABLED_STATE_H__ + +#include "sm_types.h" +#include "sm_db.h" +#include "sm_db_nodes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Node Enabled State - Entry +// ========================== +extern SmErrorT sm_node_enabled_state_entry( SmDbNodeT* node ); +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Exit +// ========================= +extern SmErrorT sm_node_enabled_state_exit( SmDbNodeT* node ); +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Transition +// =============================== +extern SmErrorT sm_node_enabled_state_transition( SmDbNodeT* node, + SmNodeReadyStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Event Handler +// ================================== +extern SmErrorT sm_node_enabled_state_event_handler( SmDbNodeT* node, + SmNodeEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Initialize +// =============================== +extern SmErrorT sm_node_enabled_state_initialize( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Node Enabled State - Finalize +// ============================= +extern SmErrorT sm_node_enabled_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NODE_ENABLED_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_node_fsm.c b/service-mgmt/sm-1.0.0/src/sm_node_fsm.c new file mode 100644 index 00000000..ddac9575 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_fsm.c @@ -0,0 +1,515 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_node_fsm.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_nodes.h" +#include "sm_node_unknown_state.h" +#include "sm_node_enabled_state.h" +#include "sm_node_disabled_state.h" +#include "sm_log.h" + +static SmDbHandleT* _sm_db_handle = NULL; +static char _reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; +static SmListT* _callbacks = NULL; + +// **************************************************************************** +// Node FSM - Register Callback +// ============================ +SmErrorT sm_node_fsm_register_callback( SmNodeFsmCallbackT callback ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Deregister Callback +// ============================== +SmErrorT sm_node_fsm_deregister_callback( SmNodeFsmCallbackT callback ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Notify +// ================= +static void sm_node_fsm_notify( SmDbNodeT* node ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmNodeFsmCallbackT callback; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callback = (SmNodeFsmCallbackT) entry_data; + + callback( node->name, node->ready_state ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Enter State +// ====================== +static SmErrorT sm_node_fsm_enter_state( SmDbNodeT* node ) +{ + SmErrorT error; + + switch( node->ready_state ) + { + case SM_NODE_READY_STATE_UNKNOWN: + error = sm_node_unknown_state_entry( node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to enter state (%s), error=%s.", + node->name, + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_READY_STATE_ENABLED: + error = sm_node_enabled_state_entry( node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to enter state (%s), error=%s.", + node->name, + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_READY_STATE_DISABLED: + error = sm_node_disabled_state_entry( node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to enter state (%s), error=%s.", + node->name, + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown node (%s) state (%s).", node->name, + sm_node_ready_state_str( node->ready_state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Exit State +// ===================== +static SmErrorT sm_node_fsm_exit_state( SmDbNodeT* node ) +{ + SmErrorT error; + + switch( node->ready_state ) + { + case SM_NODE_READY_STATE_UNKNOWN: + error = sm_node_unknown_state_exit( node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to exit state (%s), error=%s.", + node->name, + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_READY_STATE_ENABLED: + error = sm_node_enabled_state_exit( node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to exit state (%s), error=%s.", + node->name, + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_READY_STATE_DISABLED: + error = sm_node_disabled_state_exit( node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to exit state (%s), error=%s.", + node->name, + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown node (%s) state (%s).", node->name, + sm_node_ready_state_str( node->ready_state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Transition State +// =========================== +static SmErrorT sm_node_fsm_transition_state( SmDbNodeT* node, + SmNodeReadyStateT from_state ) +{ + SmErrorT error; + + switch( node->ready_state ) + { + case SM_NODE_READY_STATE_UNKNOWN: + error = sm_node_unknown_state_transition( node, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", node->name, + sm_node_ready_state_str( from_state ), + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_READY_STATE_ENABLED: + error = sm_node_enabled_state_transition( node, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", node->name, + sm_node_ready_state_str( from_state ), + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_READY_STATE_DISABLED: + error = sm_node_disabled_state_transition( node, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", node->name, + sm_node_ready_state_str( from_state ), + sm_node_ready_state_str( node->ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown node (%s) state (%s).", node->name, + sm_node_ready_state_str( node->ready_state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Set State +// ==================== +SmErrorT sm_node_fsm_set_state( char node_name[], SmNodeReadyStateT state, + const char reason_text[] ) +{ + SmNodeReadyStateT prev_state; + SmDbNodeT node; + SmErrorT error, error2; + + error = sm_db_nodes_read( _sm_db_handle, node_name, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read node (%s), error=%s.", node_name, + sm_error_str( error ) ); + return( error ); + } + + prev_state = node.ready_state; + + error = sm_node_fsm_exit_state( &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to exit state (%s) node (%s), error=%s.", + sm_node_ready_state_str( node.ready_state ), node.name, + sm_error_str( error ) ); + return( error ); + } + + node.ready_state = state; + + error = sm_db_nodes_update( _sm_db_handle, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update node (%s), error=%s.", + node.name, sm_error_str( error ) ); + return( error ); + } + + error = sm_node_fsm_transition_state( &node, prev_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to transition to state (%s) node (%s), " + "error=%s.", sm_node_ready_state_str( node.ready_state ), + node.name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + error = sm_node_fsm_enter_state( &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enter state (%s) node (%s), error=%s.", + sm_node_ready_state_str( node.ready_state ), node.name, + sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + if( '\0' != reason_text[0] ) + { + snprintf( _reason_text, sizeof(_reason_text), "%s", reason_text ); + } + + return( SM_OKAY ); + +STATE_CHANGE_ERROR: + error2 = sm_node_fsm_exit_state( &node ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to exit state (%s) node (%s), error=%s.", + sm_node_ready_state_str( node.ready_state ), + node.name, sm_error_str( error2 ) ); + abort(); + } + + node.ready_state = prev_state; + + error2 = sm_db_nodes_update( _sm_db_handle, &node ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to update node (%s), error=%s.", + node.name, sm_error_str( error2 ) ); + abort(); + } + + error2 = sm_node_fsm_transition_state( &node, state ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to transition to state (%s) node (%s), " + "error=%s.", sm_node_ready_state_str( node.ready_state ), + node.name, sm_error_str( error2 ) ); + abort(); + } + + error2 = sm_node_fsm_enter_state( &node ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to enter state (%s) node (%s), error=%s.", + sm_node_ready_state_str( node.ready_state ), node.name, + sm_error_str( error2 ) ); + abort(); + } + + return( error ); +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Event Handler +// ======================== +SmErrorT sm_node_fsm_event_handler( char node_name[], SmNodeEventT event, + void* event_data[], const char reason_text[] ) +{ + SmNodeReadyStateT prev_state; + SmDbNodeT node; + SmErrorT error; + + snprintf( _reason_text, sizeof(_reason_text), "%s", reason_text ); + + error = sm_db_nodes_read( _sm_db_handle, node_name, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read node (%s), error=%s.", node_name, + sm_error_str( error ) ); + return( error ); + } + + prev_state = node.ready_state; + + switch( node.ready_state ) + { + case SM_NODE_READY_STATE_UNKNOWN: + error = sm_node_unknown_state_event_handler( &node, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to handle event (%s) " + "in state (%s), error=%s.", node.name, + sm_node_event_str( event ), + sm_node_ready_state_str( node.ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_READY_STATE_ENABLED: + error = sm_node_enabled_state_event_handler( &node, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to handle event (%s) " + "in state (%s), error=%s.", node.name, + sm_node_event_str( event ), + sm_node_ready_state_str( node.ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_READY_STATE_DISABLED: + error = sm_node_disabled_state_event_handler( &node, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Node (%s) unable to handle event (%s) " + "in state (%s), error=%s.", node.name, + sm_node_event_str( event ), + sm_node_ready_state_str( node.ready_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown state (%s) for node (%s).", + sm_node_ready_state_str( node.ready_state ), + node.name ); + break; + } + + error = sm_db_nodes_read( _sm_db_handle, node_name, &node ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read node (%s), error=%s.", node_name, + sm_error_str( error ) ); + return( error ); + } + + if( prev_state != node.ready_state ) + { + DPRINTFI( "Node (%s) received event (%s) was in the %s state and " + "is now in the %s.", node.name, sm_node_event_str( event ), + sm_node_ready_state_str( prev_state ), + sm_node_ready_state_str( node.ready_state ) ); + + sm_log_node_state_change( node_name, + sm_node_state_str( node.admin_state, prev_state ), + sm_node_state_str( node.admin_state, node.ready_state ), + _reason_text ); + + sm_node_fsm_notify( &node ); + + } else if( SM_NODE_EVENT_AUDIT == event ) { + sm_node_fsm_notify( &node ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Initialize +// ===================== +SmErrorT sm_node_fsm_initialize( void ) +{ + SmErrorT error; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_node_unknown_state_initialize( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node unknown state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_node_enabled_state_initialize( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node enabled state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_node_disabled_state_initialize( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node disabled state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Finalize +// =================== +SmErrorT sm_node_fsm_finalize( void ) +{ + SmErrorT error; + + error = sm_node_unknown_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize node unknown state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_node_enabled_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize node enabled state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_node_disabled_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize node disabled state module, " + "error=%s.", sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_node_fsm.h b/service-mgmt/sm-1.0.0/src/sm_node_fsm.h new file mode 100644 index 00000000..411f4970 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_fsm.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NODE_FSM_H__ +#define __SM_NODE_FSM_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmNodeFsmCallbackT) (char node_name[], + SmNodeReadyStateT ready_state ); + +// **************************************************************************** +// Node FSM - Register Callback +// ============================ +extern SmErrorT sm_node_fsm_register_callback( SmNodeFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Deregister Callback +// ============================== +extern SmErrorT sm_node_fsm_deregister_callback( SmNodeFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Set State +// ==================== +extern SmErrorT sm_node_fsm_set_state( char node_name[], + SmNodeReadyStateT state, const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Event Handler +// ======================== +extern SmErrorT sm_node_fsm_event_handler( char node_name[], + SmNodeEventT event, void* event_data[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Initialize +// ===================== +extern SmErrorT sm_node_fsm_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Node FSM - Finalize +// =================== +extern SmErrorT sm_node_fsm_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NODE_FSM_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_node_swact_monitor.cpp b/service-mgmt/sm-1.0.0/src/sm_node_swact_monitor.cpp new file mode 100644 index 00000000..306326af --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_swact_monitor.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_node_swact_monitor.h" +#include "sm_debug.h" +#include "sm_node_utils.h" +#include "sm_swact_state.h" +#include "sm_service_enable.h" + +bool SmNodeSwactMonitor::swact_started = false; +static bool duplex = false; +SmNodeScheduleStateT SmNodeSwactMonitor::my_role = SM_NODE_STATE_UNKNOWN; + +void SmNodeSwactMonitor::SwactStart(SmNodeScheduleStateT my_role) +{ + sm_node_utils_is_aio_duplex(&duplex); + if( duplex ) + { + // US102803: Set the swact state to start so task affining thread + // can affine tasks to all idle cores to speed up swact activity. + DPRINTFI("Start of swact: affining tasks to idle cores..."); + sm_set_swact_state(SM_SWACT_STATE_START); + sm_service_enable_throttle_add_cores(true); + } + SmNodeSwactMonitor::swact_started = true; + SmNodeSwactMonitor::my_role = my_role; + DPRINTFI("Swact has started, host will be %s", sm_node_schedule_state_str(my_role)); +} + +void SmNodeSwactMonitor::SwactUpdate(const char* hostname, SmNodeScheduleStateT node_state) +{ + if( SmNodeSwactMonitor::swact_started ) + { + DPRINTFI("Swact update: %s is now %s", hostname, + sm_node_schedule_state_str(node_state)); + if( SM_NODE_STATE_ACTIVE == node_state ) + { + SmNodeSwactMonitor::SwactCompleted( + SM_NODE_STATE_ACTIVE == SmNodeSwactMonitor::my_role ); + } + + } +} + +void SmNodeSwactMonitor::SwactCompleted(bool result) +{ + if( duplex ) + { + // US102803: Set the swact state to end so task affining thread + // can reaffine tasks back to the platform cores. + DPRINTFI("End of swact: reaffining tasks back to platform cores..."); + sm_set_swact_state(SM_SWACT_STATE_END); + sm_service_enable_throttle_add_cores(false); + } + DPRINTFI("Swact has %s.", result ? "completed successfully": "failed"); +} diff --git a/service-mgmt/sm-1.0.0/src/sm_node_swact_monitor.h b/service-mgmt/sm-1.0.0/src/sm_node_swact_monitor.h new file mode 100644 index 00000000..6ee08957 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_swact_monitor.h @@ -0,0 +1,22 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NODE_SWACT_MONITOR_H__ +#define __SM_NODE_SWACT_MONITOR_H__ +#include "sm_types.h" + +class SmNodeSwactMonitor +{ + public: + static void SwactStart(SmNodeScheduleStateT my_role); + static void SwactUpdate(const char* hostname, SmNodeScheduleStateT node_state); + static void SwactCompleted(bool result); + + private: + static bool swact_started; + static SmNodeScheduleStateT my_role; +}; + +#endif diff --git a/service-mgmt/sm-1.0.0/src/sm_node_unknown_state.c b/service-mgmt/sm-1.0.0/src/sm_node_unknown_state.c new file mode 100644 index 00000000..a129b008 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_unknown_state.c @@ -0,0 +1,144 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_node_unknown_state.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_hw.h" +#include "sm_db.h" +#include "sm_db_nodes.h" +#include "sm_node_utils.h" +#include "sm_node_fsm.h" + +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Node Unknown State - Entry +// ========================== +SmErrorT sm_node_unknown_state_entry( SmDbNodeT* node ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Exit +// ========================= +SmErrorT sm_node_unknown_state_exit( SmDbNodeT* node ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Transition +// =============================== +SmErrorT sm_node_unknown_state_transition( SmDbNodeT* node, + SmNodeReadyStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Event Handler +// ================================== +SmErrorT sm_node_unknown_state_event_handler( SmDbNodeT* node, + SmNodeEventT event, void* event_data[] ) +{ + bool enabled; + SmNodeReadyStateT state; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + switch( event ) + { + case SM_NODE_EVENT_ENABLED: + error = sm_node_fsm_set_state( node->name, + SM_NODE_READY_STATE_ENABLED, + "node ready" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of node (%s) failed, error=%s.", + sm_node_ready_state_str( SM_NODE_READY_STATE_ENABLED ), + node->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_EVENT_DISABLED: + error = sm_node_fsm_set_state( node->name, + SM_NODE_READY_STATE_DISABLED, + "node not ready" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of node (%s) failed, error=%s.", + sm_node_ready_state_str( SM_NODE_READY_STATE_DISABLED ), + node->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_NODE_EVENT_AUDIT: + error = sm_node_utils_enabled( &enabled, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if node (%s) is enabled, " + "error=%s.", node->name, sm_error_str( error ) ); + return( error ); + } + + if( enabled ) + { + state = SM_NODE_READY_STATE_ENABLED; + } else { + state = SM_NODE_READY_STATE_DISABLED; + } + + error = sm_node_fsm_set_state( node->name, state, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of node (%s) failed, error=%s.", + sm_node_ready_state_str( state ), node->name, + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Node (%s) ignoring event (%s).", node->name, + sm_node_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Initialize +// =============================== +SmErrorT sm_node_unknown_state_initialize( SmDbHandleT* sm_db_handle ) +{ + _sm_db_handle = sm_db_handle; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Finalize +// ============================= +SmErrorT sm_node_unknown_state_finalize( void ) +{ + _sm_db_handle = NULL; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_node_unknown_state.h b/service-mgmt/sm-1.0.0/src/sm_node_unknown_state.h new file mode 100644 index 00000000..94af4e91 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_node_unknown_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NODE_UNKNOWN_STATE_H__ +#define __SM_NODE_UNKNOWN_STATE_H__ + +#include "sm_types.h" +#include "sm_db.h" +#include "sm_db_nodes.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Node Unknown State - Entry +// ========================== +extern SmErrorT sm_node_unknown_state_entry( SmDbNodeT* node ); +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Exit +// ========================= +extern SmErrorT sm_node_unknown_state_exit( SmDbNodeT* node ); +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Transition +// =============================== +extern SmErrorT sm_node_unknown_state_transition( SmDbNodeT* node, + SmNodeReadyStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Event Handler +// ================================== +extern SmErrorT sm_node_unknown_state_event_handler( SmDbNodeT* node, + SmNodeEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Initialize +// =============================== +extern SmErrorT sm_node_unknown_state_initialize( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Node Unknown State - Finalize +// ============================= +extern SmErrorT sm_node_unknown_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NODE_UNKNOWN_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_notify_api.c b/service-mgmt/sm-1.0.0/src/sm_notify_api.c new file mode 100644 index 00000000..5ea7b3c5 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_notify_api.c @@ -0,0 +1,270 @@ +// +// Copyright (c) 2015 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_notify_api.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_selobj.h" + +#define SM_NOTIFY_API_MSG_ADDRESS "/tmp/.sm_notify_api" + +#define SM_NOTIFY_API_MSG_VERSION "1" +#define SM_NOTIFY_API_MSG_REVISION "1" +#define SM_NOTIFY_API_MSG_TYPE_SERVICE_EVENT "SERVICE_EVENT" + +#define SM_NOTIFY_API_MSG_SERVICE_EVENT_SYNC_START "sync-start" +#define SM_NOTIFY_API_MSG_SERVICE_EVENT_SYNC_END "sync-end" + +#define SM_NOTIFY_API_MSG_VERSION_FIELD 0 +#define SM_NOTIFY_API_MSG_REVISION_FIELD 1 +#define SM_NOTIFY_API_MSG_TYPE_FIELD 2 +#define SM_NOTIFY_API_MSG_ORIGIN_FIELD 3 +#define SM_NOTIFY_API_MSG_SERVICE_NAME_FIELD 4 +#define SM_NOTIFY_API_MSG_SERVICE_EVENT_FIELD 5 + +#define SM_NOTIFY_API_MAX_MSG_SIZE 256 + +static int _sm_notify_api_socket = -1; +static char _rx_buffer[SM_NOTIFY_API_MAX_MSG_SIZE] __attribute__((aligned)); +static SmNotifyApiCallbacksT _callbacks = {0}; + +// **************************************************************************** +// Notify API - Register Callbacks +// =============================== +SmErrorT sm_notify_api_register_callbacks( SmNotifyApiCallbacksT* callbacks ) +{ + memcpy( &_callbacks, callbacks, sizeof(SmNotifyApiCallbacksT) ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Notify API - Deregister Callbacks +// ================================= +SmErrorT sm_notify_api_deregister_callbacks( SmNotifyApiCallbacksT* callbacks ) +{ + memset( &_callbacks, 0, sizeof(SmNotifyApiCallbacksT) ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Notify API - Service Event Value +// ================================ +static SmNotifyServiceEventT sm_notify_api_service_event_value( + const char* event_str ) +{ + if( 0 == strcmp( SM_NOTIFY_API_MSG_SERVICE_EVENT_SYNC_START, + event_str ) ) + { + return( SM_NOTIFY_SERVICE_EVENT_SYNC_START ); + + } else if( 0 == strcmp( SM_NOTIFY_API_MSG_SERVICE_EVENT_SYNC_END, + event_str ) ) + { + return( SM_NOTIFY_SERVICE_EVENT_SYNC_END ); + + } else { + return( SM_NOTIFY_SERVICE_EVENT_UNKNOWN ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Notify API - Dispatch +// ===================== +static void sm_notify_api_dispatch( int selobj, int64_t user_data ) +{ + char* service_name; + gchar** params; + int bytes_read; + SmNotifyServiceEventT service_event; + + int retry_count; + for( retry_count = 5; retry_count != 0; --retry_count ) + { + memset( _rx_buffer, 0, sizeof(_rx_buffer) ); + + bytes_read = recv( selobj, &_rx_buffer, sizeof(_rx_buffer), 0 ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_count, strerror( errno ) ); + } + + params = g_strsplit( _rx_buffer, ",", -1 ); + if( params[SM_NOTIFY_API_MSG_VERSION_FIELD] == NULL ) + { + DPRINTFE( "Missing version field in received message." ); + goto ERROR; + } + + if( 0 != strcmp( SM_NOTIFY_API_MSG_VERSION, + params[SM_NOTIFY_API_MSG_VERSION_FIELD] ) ) + { + DPRINTFE( "Unsupported version (%s) received, expected=%s.", + params[SM_NOTIFY_API_MSG_VERSION_FIELD], + SM_NOTIFY_API_MSG_VERSION ); + goto ERROR; + } + + if( params[SM_NOTIFY_API_MSG_REVISION_FIELD] == NULL ) + { + DPRINTFE( "Missing revision field in received message." ); + goto ERROR; + } + + if( params[SM_NOTIFY_API_MSG_TYPE_FIELD] == NULL ) + { + DPRINTFE( "Missing message-type field in received message." ); + goto ERROR; + } + + if( 0 == strcmp( SM_NOTIFY_API_MSG_TYPE_SERVICE_EVENT, + params[SM_NOTIFY_API_MSG_TYPE_FIELD] ) ) + { + if( params[SM_NOTIFY_API_MSG_ORIGIN_FIELD] == NULL ) + { + DPRINTFE( "Missing origin field in received message." ); + goto ERROR; + } + + if( params[SM_NOTIFY_API_MSG_SERVICE_NAME_FIELD] == NULL ) + { + DPRINTFE( "Missing service-name field in received message." ); + goto ERROR; + } + + service_name = (char*) params[SM_NOTIFY_API_MSG_SERVICE_NAME_FIELD]; + + if( params[SM_NOTIFY_API_MSG_SERVICE_EVENT_FIELD] == NULL ) + { + DPRINTFE( "Missing service-event field in received message." ); + goto ERROR; + } + + service_event = sm_notify_api_service_event_value( (char*) + params[SM_NOTIFY_API_MSG_SERVICE_EVENT_FIELD]); + + if( NULL != _callbacks.service_event ) + { + _callbacks.service_event( service_name, service_event ); + } + + } else { + DPRINTFE( "Unknown/unsupported message-type (%s) received.", + params[SM_NOTIFY_API_MSG_TYPE_FIELD] ); + goto ERROR; + } + + g_strfreev( params ); + return; + +ERROR: + g_strfreev( params ); + return; +} +// *************************************************************************** + +// *************************************************************************** +// Notify API - Initialize +// ======================= +SmErrorT sm_notify_api_initialize( void ) +{ + int sock; + socklen_t len; + struct sockaddr_un src_addr; + int result; + SmErrorT error; + + memset( &src_addr, 0, sizeof(src_addr) ); + + src_addr.sun_family = AF_UNIX; + snprintf( src_addr.sun_path, sizeof(src_addr.sun_path), + SM_NOTIFY_API_MSG_ADDRESS ); + + sock = socket( AF_LOCAL, SOCK_DGRAM, 0 ); + if( 0 > sock ) + { + DPRINTFE( "Failed to create socket for sm-notify-api, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + unlink( src_addr.sun_path ); + + len = strlen(src_addr.sun_path) + sizeof(src_addr.sun_family); + + result = bind( sock, (struct sockaddr *) &src_addr, len ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind address (%s) to socket for sm-notify-api, " + "error=%s.", src_addr.sun_path, strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + _sm_notify_api_socket = sock; + + error = sm_selobj_register( _sm_notify_api_socket, + sm_notify_api_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Notify API - Finalize +// ===================== +SmErrorT sm_notify_api_finalize( void ) +{ + SmErrorT error; + + memset( &_callbacks, 0, sizeof(_callbacks) ); + + if( -1 < _sm_notify_api_socket ) + { + error = sm_selobj_deregister( _sm_notify_api_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + } + + return( SM_OKAY ); +} +// *************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_notify_api.h b/service-mgmt/sm-1.0.0/src/sm_notify_api.h new file mode 100644 index 00000000..66de5b58 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_notify_api.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2015 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NOTIFY_API_H__ +#define __SM_NOTIFY_API_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + SM_NOTIFY_SERVICE_EVENT_UNKNOWN, + SM_NOTIFY_SERVICE_EVENT_SYNC_START, + SM_NOTIFY_SERVICE_EVENT_SYNC_END, + SM_NOTIFY_SERVICE_EVENT_MAX +} SmNotifyServiceEventT; + +typedef void (*SmNotifyApiServiceEventCallbackT) ( char service_name[], + SmNotifyServiceEventT event ); + +typedef struct +{ + SmNotifyApiServiceEventCallbackT service_event; +} SmNotifyApiCallbacksT; + +// **************************************************************************** +// Notify API - Register Callbacks +// =============================== +extern SmErrorT sm_notify_api_register_callbacks( + SmNotifyApiCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// Notify API - Deregister Callbacks +// ================================= +extern SmErrorT sm_notify_api_deregister_callbacks( + SmNotifyApiCallbacksT* callbacks ); +// **************************************************************************** + +// *************************************************************************** +// Notify API - Initialize +// ======================= +extern SmErrorT sm_notify_api_initialize( void ); +// *************************************************************************** + +// *************************************************************************** +// Notify API - Finalize +// ===================== +extern SmErrorT sm_notify_api_finalize( void ); +// *************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NOTIFY_API_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_process.c b/service-mgmt/sm-1.0.0/src/sm_process.c new file mode 100644 index 00000000..e1e54cd9 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_process.c @@ -0,0 +1,854 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_process.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_utils.h" +#include "sm_selobj.h" +#include "sm_timer.h" +#include "sm_heartbeat.h" +#include "sm_log.h" +#include "sm_alarm.h" +#include "sm_thread_health.h" +#include "sm_process_death.h" +#include "sm_hw.h" +#include "sm_msg.h" +#include "sm_db.h" +#include "sm_node_utils.h" +#include "sm_node_stats.h" +#include "sm_node_api.h" +#include "sm_service_domain_api.h" +#include "sm_service_domain_interface_api.h" +#include "sm_service_group_api.h" +#include "sm_service_api.h" +#include "sm_service_action.h" +#include "sm_service_heartbeat_api.h" +#include "sm_service_heartbeat_thread.h" +#include "sm_service_domain_scheduler.h" +#include "sm_main_event_handler.h" +#include "sm_troubleshoot.h" +#include "sm_service_action_table.h" +#include "sm_heartbeat_thread.h" +#include "sm_failover.h" +#include "sm_failover_thread.h" +#include "sm_task_affining_thread.h" + +#define SM_PROCESS_DB_CHECKPOINT_INTERVAL_IN_MS 30000 +#define SM_PROCESS_TICK_INTERVAL_IN_MS 200 +#define SM_PROCESS_PAUSE_IN_MS 30000 + +static sig_atomic_t _stay_on = 1; +static sig_atomic_t _reap_children = 0; +static sig_atomic_t _do_reload_data = 0; +static sig_atomic_t _do_dump_data = 0; +static sig_atomic_t _about_to_patch = 0; +static int _last_signum = 0; +static bool _is_aio = false; +static bool _is_aio_simplex = false; +static bool _is_aio_duplex = false; + +// **************************************************************************** +// Process - Reap Children +// ======================= +static void sm_process_reap_children( void ) +{ + if( _reap_children ) + { + pid_t pid; + int status; + + while( 0 < (pid = waitpid( -1, &status, WNOHANG | WUNTRACED )) ) + { + if( WIFEXITED( status ) ) + { + sm_process_death_save( pid, WEXITSTATUS( status ) ); + } else { + sm_process_death_save( pid, SM_PROCESS_FAILED ); + } + } + + _reap_children = 0; + } +} +// **************************************************************************** + +// **************************************************************************** +// Process - Signal Handler +// ======================== +static void sm_process_signal_handler( int signum ) +{ + switch( signum ) + { + case SIGINT: + case SIGTERM: + case SIGQUIT: + _stay_on = 0; + break; + + case SIGCHLD: + _reap_children = 1; + break; + + case SIGHUP: + _do_reload_data = 1; + break; + + case SIGUSR1: + _do_dump_data = 1; + break; + + case SIGUSR2: + _about_to_patch = 1; + break; + + case SIGCONT: + DPRINTFD( "Ignoring signal SIGCONT (%i).", signum ); + break; + + case SIGPIPE: + DPRINTFD( "Ignoring signal SIGPIPE (%i).", signum ); + break; + + default: + DPRINTFD( "Signal (%i) ignored.", signum ); + break; + } + + _last_signum = signum; +} +// **************************************************************************** + +// **************************************************************************** +// Process - Setup Signal Handler +// ============================== +static void sm_process_setup_signal_handler( void ) +{ + struct sigaction sa; + + memset( &sa, 0, sizeof(sa) ); + sa.sa_handler = sm_process_signal_handler; + + sigaction( SIGINT, &sa, NULL ); + sigaction( SIGTERM, &sa, NULL ); + sigaction( SIGQUIT, &sa, NULL ); + sigaction( SIGCHLD, &sa, NULL ); + sigaction( SIGUSR1, &sa, NULL ); + sigaction( SIGUSR2, &sa, NULL ); + sigaction( SIGCONT, &sa, NULL ); + sigaction( SIGPIPE, &sa, NULL ); + sigaction( SIGHUP, &sa, NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Process - Initialize +// ==================== +static SmErrorT sm_process_initialize( void ) +{ + SmErrorT error; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_initialize( SM_PROCESS_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_hw_initialize( NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize hardware module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_msg_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize messaging module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_node_stats_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node stats module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_thread_health_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize thread health module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_alarm_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize alarm module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_log_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize log module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + if (_is_aio_simplex) + { + sm_heartbeat_thread_disable_heartbeat(); + } + else + { + error = sm_heartbeat_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize heartbeat module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + } + + error = sm_process_death_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize process death module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_db_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize database module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_node_api_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node api module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_domain_api_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain api module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_domain_interface_api_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain interface api module, " + "error=%s.", sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_group_api_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group api module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_action_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service action module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_api_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service api module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_heartbeat_api_initialize( true ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service heartbeat api module, " + "error=%s.", sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_heartbeat_thread_start(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed start service heartbeat thread, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_main_event_handler_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize main event handler module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_failover_thread_start(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start the failover thread, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_failover_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize failover handler module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + // US102803: Start a task affining thread for AIO duplex system + if(_is_aio_duplex) + { + error = sm_task_affining_thread_start(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start the task affining thread, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Process - Finalize +// ================== +static SmErrorT sm_process_finalize( void ) +{ + SmErrorT error; + + // US102803: Stop the task affining thread if it is AIO duplex + if(_is_aio_duplex) + { + error = sm_task_affining_thread_stop(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop task affining thread, error=%s.", + sm_error_str( error ) ); + } + } + + error = sm_failover_thread_stop(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop failover thread, error=%s.", + sm_error_str( error ) ); + } + + error = sm_failover_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize failover handler module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_main_event_handler_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize main event handler module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_heartbeat_thread_stop(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed start service heartbeat thread, error=%s.", + sm_error_str(error) ); + } + + error = sm_service_heartbeat_api_finalize( true ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service heartbeat api module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_api_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service api module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_action_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service action module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_group_api_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group api module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_interface_api_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain interface api module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_api_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain api module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_node_api_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize interface api module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_db_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize database module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_process_death_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize process death module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_heartbeat_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize heartbeat module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_log_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize log module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_alarm_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize alarm module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_thread_health_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize thread health module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_node_stats_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize node stats module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_msg_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize messaging module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_hw_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize hardware module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize timer module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Process - Wait For Node Configuration +// ===================================== +static SmErrorT sm_process_wait_node_configuration( void ) +{ + bool config_complete; + SmErrorT error; + + while( _stay_on ) + { + error = sm_node_utils_config_complete( &config_complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if node configuration " + "completed, error=%s.", sm_error_str(error) ); + sleep( 10 ); + continue; + } + + if( config_complete ) + { + DPRINTFI( "Node configuration completed." ); + break; + + } else { + DPRINTFI( "Waiting for node configuration to complete." ); + sleep( 10 ); + } + } + + if( _stay_on ) + { + error = SM_OKAY; + } else { + DPRINTFI( "Shutdown signalled, last-signal=%i.", _last_signum ); + error = SM_FAILED; + } + return error; +} +// **************************************************************************** + +// **************************************************************************** +// Process - Main +// ============== +SmErrorT sm_process_main( int argc, char *argv[], char *envp[] ) +{ + int result; + long ms_expired; + bool thread_health; + bool do_patch = false; + SmTimeT db_checkpoint_time_prev; + SmTimeT patch_time_prev; + SmErrorT error; + + int opt = 0; + static struct option long_options[] = { + {"interval-extension", 1, 0, 'i'}, + {"timeout-extension", 1, 0, 't'}, + {0, 0, 0, 0} + }; + int long_index = 0; + + sm_process_setup_signal_handler(); + + DPRINTFI( "Starting" ); + + if( sm_utils_process_running( SM_PROCESS_PID_FILENAME ) ) + { + DPRINTFI( "Already running an instance of sm." ); + return( SM_OKAY ); + } + + if( !sm_utils_set_pid_file( SM_PROCESS_PID_FILENAME ) ) + { + DPRINTFE( "Failed to write pid file for sm, error=%s.", + strerror(errno) ); + return( SM_FAILED ); + } + + result = setpriority( PRIO_PROCESS, getpid(), -2 ); + if( 0 > result ) + { + DPRINTFE( "Failed to set priority of process, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + if( 0 > mkdir( SM_RUN_DIRECTORY, 0700 ) ) + { + if( EEXIST == errno ) + { + DPRINTFI( "Run directory (%s) exists.", SM_RUN_DIRECTORY ); + } else { + DPRINTFE( "Run directory (%s) creation failed, error=%s.", + SM_RUN_DIRECTORY, strerror(errno) ); + return( SM_FAILED ); + } + } + + // Check for cmdline args + while ((opt = getopt_long(argc, argv, "i:t:", + long_options, + &long_index)) != -1) + { + switch (opt) + { + case 'i': + { + sm_service_action_table_set_interval_extension( atoi(optarg) ); + break; + } + case 't': + { + sm_service_action_table_set_timeout_extension( atoi(optarg) ); + break; + } + default: + { + DPRINTFE( "Failed to process cmdline arg." ); + return( SM_FAILED ); + } + } + } + + error = sm_process_wait_node_configuration(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to wait for node configuration, error=%s.", + sm_error_str(error) ); + return( error ); + } + + DPRINTFI( "Configuring Databases" ); + + error = sm_db_configure( SM_DATABASE_NAME, SM_DB_TYPE_MAIN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed configuring database, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_db_configure( SM_HEARTBEAT_DATABASE_NAME, SM_DB_TYPE_HEARTBEAT ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed configuring heartbeat database, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_node_utils_is_aio(&_is_aio); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check for AIO system, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_node_utils_is_aio_simplex(&_is_aio_simplex); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check for AIO simplex system, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_node_utils_is_aio_duplex(&_is_aio_duplex); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check for AIO duplex system, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_process_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed initialize process, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_utils_set_boot_complete(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set boot complete, error=%s.", + sm_error_str(error) ); + return( error ); + } + + DPRINTFI( "Started." ); + + sm_time_get( &db_checkpoint_time_prev ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_PROCESS_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + + sm_process_reap_children(); + + ms_expired = sm_time_get_elapsed_ms( &db_checkpoint_time_prev ); + if( SM_PROCESS_DB_CHECKPOINT_INTERVAL_IN_MS <= ms_expired ) + { + error = sm_db_checkpoint( SM_DATABASE_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Database (%s) checkpoint failed, error=%s.", + SM_DATABASE_NAME, sm_error_str(error) ); + } + + error = sm_db_checkpoint( SM_HEARTBEAT_DATABASE_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Database (%s) checkpoint failed, error=%s.", + SM_HEARTBEAT_DATABASE_NAME, sm_error_str(error) ); + } + + sm_time_get( &db_checkpoint_time_prev ); + } + + error = sm_thread_health_check( &thread_health ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check thread health, error=%s.", + sm_error_str(error) ); + break; + } + + if( !thread_health ) + { + DPRINTFE( "Thread health check failed." ); + sm_troubleshoot_dump_data( "thread health check failed" ); + break; + } + + if( _do_reload_data ) + { + DPRINTFI( "Reload data signalled." ); + sm_main_event_handler_reload_data(); + _do_reload_data = 0; + } + + if( _do_dump_data ) + { + DPRINTFI( "Dump data signalled." ); + sm_troubleshoot_dump_data( "user request" ); + _do_dump_data = 0; + } + + if( _about_to_patch ) + { + do_patch = true; + sm_time_get( &patch_time_prev ); + _about_to_patch = 0; + DPRINTFI( "About to patch signalled." ); + } + + if( do_patch ) + { + ms_expired = sm_time_get_elapsed_ms( &patch_time_prev ); + if( SM_PROCESS_PAUSE_IN_MS < ms_expired ) + { + do_patch = false; + DPRINTFI( "Too much time elapsed between patch signal and " + "shutdown, ms_expired=%li, max=%i.", ms_expired, + SM_PROCESS_PAUSE_IN_MS ); + } + } + } + + if( do_patch ) + { + ms_expired = sm_time_get_elapsed_ms( &patch_time_prev ); + if( SM_PROCESS_PAUSE_IN_MS < ms_expired ) + { + DPRINTFI( "Too much time elapsed between patch signal and " + "shutdown, ms_expired=%li, max=%i.", ms_expired, + SM_PROCESS_PAUSE_IN_MS ); + } else { + DPRINTFI( "Sending pause signal." ); + + int retry_i; + for( retry_i=0; 5 > retry_i; ++retry_i ) + { + sm_service_domain_api_pause_all( SM_PROCESS_PAUSE_IN_MS ); + } + } + } + + DPRINTFI( "Shutting down." ); + + error = sm_process_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed finalize process, error=%s.", + sm_error_str(error) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_process.h b/service-mgmt/sm-1.0.0/src/sm_process.h new file mode 100644 index 00000000..84752cc3 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_process.h @@ -0,0 +1,27 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_PROCESS_H__ +#define __SM_PROCESS_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Process - Main +// ============== +extern SmErrorT sm_process_main( int argc, char *argv[], char *envp[] ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_PROCESS_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_process_death.c b/service-mgmt/sm-1.0.0/src/sm_process_death.c new file mode 100644 index 00000000..8198608b --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_process_death.c @@ -0,0 +1,425 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_process_death.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_selobj.h" + +#define __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ +#ifdef __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + +#define SM_KERNEL_NOTIFY_EXITED 0x02 +#define SM_KERNEL_NOTIFY_KILLED 0x04 +#define SM_KERNEL_NOTIFY_DUMPED 0x08 +#define SM_KERNEL_NOTIFY_TRAPPED 0x10 +#define SM_KERNEL_NOTIFY_STOPPED 0x20 +#define SM_KERNEL_NOTIFY_CONTINUED 0x40 + +// Note: SM_KERNEL_NOTIFY_TRAPPED is for debug purposes. +#define SM_KERNEL_NOTIFY_FLAGS \ + ( SM_KERNEL_NOTIFY_EXITED | SM_KERNEL_NOTIFY_KILLED ) + +// Set/get notification for task state changes. +#define PR_DO_NOTIFY_TASK_STATE 17 + +#define SM_KERNEL_NOTIFY_SIGNAL (SIGRTMIN+1) + +// This is the data structure for requestion process death +// (and other state change) information. Sig of -1 means +// query, sig of 0 means deregistration, positive sig means +// that you want to set it. sig and events are value-result +// and will be updated with the previous values on every +// successful call. +struct task_state_notify_info +{ + pid_t pid; + int sig; + unsigned int events; +}; +#endif // __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + +#define SM_PROCESS_DEATH_MAX 1024 +#define SM_PROCESS_DEATH_INFO_VALID 0xFDFDFDFD +#define SM_PROCESS_DEATH_MAX_DISPATCH 8 + +typedef struct +{ + uint32_t valid; + pid_t pid; + int exit_code; +} SmProcessDeathInfoT; + +typedef struct +{ + uint32_t valid; + pid_t pid; + bool child_process; + int64_t user_data; + SmProcessDeathCallbackT death_callback; +} SmProcessCallbackInfoT; + +static int _process_death_fd = -1; +static SmProcessCallbackInfoT _callbacks[SM_PROCESS_DEATH_MAX]; +static SmProcessDeathInfoT _process_deaths[SM_PROCESS_DEATH_MAX]; +static uint64_t _process_death_count = 0; + +// **************************************************************************** +// Process Death - Already Registered +// ================================== +bool sm_process_death_already_registered( pid_t pid, + SmProcessDeathCallbackT death_callback ) +{ + SmProcessCallbackInfoT* callback; + + unsigned int callbacks_i; + for( callbacks_i=0; SM_PROCESS_DEATH_MAX > callbacks_i; ++callbacks_i ) + { + callback = &(_callbacks[callbacks_i]); + + if( SM_PROCESS_DEATH_INFO_VALID == callback->valid ) + { + if(( pid == callback->pid )&& + ( death_callback == callback->death_callback )) + { + return( true ); + } + } + } + + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Process Death - Register +// ======================== +SmErrorT sm_process_death_register( pid_t pid, bool child_process, + SmProcessDeathCallbackT death_callback, int64_t user_data ) +{ + SmProcessCallbackInfoT* callback = NULL; + +#ifdef __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + if( !child_process ) + { + struct task_state_notify_info info; + + info.pid = pid ; + info.sig = SM_KERNEL_NOTIFY_SIGNAL; + info.events = SM_KERNEL_NOTIFY_FLAGS; + + if( -1 > prctl( PR_DO_NOTIFY_TASK_STATE, &info ) ) + { + DPRINTFE( "Failed to register for kernel notifications for " + "pid (%i), error=%s.", (int) pid, strerror(errno) ); + } + + DPRINTFD( "Register for kernel notifications for pid (%i).", + (int) pid ); + } +#endif // __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + + unsigned int callbacks_i; + for( callbacks_i=0; SM_PROCESS_DEATH_MAX > callbacks_i; ++callbacks_i ) + { + callback = &(_callbacks[callbacks_i]); + + if( SM_PROCESS_DEATH_INFO_VALID == callback->valid ) + { + if( pid == callback->pid ) + { + callback->child_process = child_process; + callback->death_callback = death_callback; + callback->user_data = user_data; + break; + } + } else { + callback->valid = SM_PROCESS_DEATH_INFO_VALID; + callback->pid = pid; + callback->child_process = child_process; + callback->death_callback = death_callback; + callback->user_data = user_data; + break; + } + } + + if( SM_PROCESS_DEATH_MAX <= callbacks_i ) + { + DPRINTFE( "Failed to register process death callback for pid (%i).", + (int) pid ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Process Death - Deregister +// ========================== +SmErrorT sm_process_death_deregister( pid_t pid ) +{ + SmProcessCallbackInfoT* callback = NULL; + + unsigned int callbacks_i; + for( callbacks_i=0; SM_PROCESS_DEATH_MAX > callbacks_i; ++callbacks_i ) + { + callback = &(_callbacks[callbacks_i]); + + if( SM_PROCESS_DEATH_INFO_VALID != callback->valid ) + continue; + + if( pid != callback->pid ) + continue; + +#ifdef __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + if( !callback->child_process ) + { + struct task_state_notify_info info; + + info.pid = pid ; + info.sig = 0 ; + info.events = SM_KERNEL_NOTIFY_FLAGS; + + if( -1 > prctl( PR_DO_NOTIFY_TASK_STATE, &info ) ) + { + DPRINTFE( "Failed to register for kernel notifications for " + "pid (%i), error=%s.", (int) pid, strerror(errno) ); + } + } +#endif // __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + + callback->valid = 0; + callback->pid = 0; + callback->death_callback = NULL; + callback->user_data = 0; + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Process Death - Save +// ==================== +SmErrorT sm_process_death_save( pid_t pid, int exit_code ) +{ + uint64_t process_death_count = ++_process_death_count; + SmProcessDeathInfoT* info = NULL; + + if( 0 > write( _process_death_fd, &process_death_count, + sizeof(process_death_count) ) ) + { + DPRINTFE( "Failed to signal process death, error=%s", + strerror( errno ) ); + } + + DPRINTFD( "Process (%i) died.", (int) pid ); + + unsigned int death_i; + for( death_i=0; SM_PROCESS_DEATH_MAX > death_i; ++death_i ) + { + info = &(_process_deaths[death_i]); + + if( SM_PROCESS_DEATH_INFO_VALID == info->valid ) + { + if( pid == info->pid ) + { + info->exit_code = exit_code; + break; + } + } else { + info->valid = SM_PROCESS_DEATH_INFO_VALID; + info->pid = pid; + info->exit_code = exit_code; + break; + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Process Death - Dispatch +// ======================== +static void sm_process_death_dispatch( int selobj, int64_t user_data ) +{ + static unsigned int _last_entry = 0; + + uint64_t process_death_count; + SmProcessDeathInfoT* info = NULL; + SmProcessCallbackInfoT* callback = NULL; + unsigned int num_process_death_dispatched = 0; + + read( _process_death_fd, &process_death_count, + sizeof(process_death_count) ); + + unsigned int death_i; + for( death_i=_last_entry; SM_PROCESS_DEATH_MAX > death_i; ++death_i ) + { + info = &(_process_deaths[death_i]); + + if( SM_PROCESS_DEATH_INFO_VALID != info->valid ) + continue; + + if( 0 == info->pid ) + continue; + + DPRINTFD( "Process (%i) exited with %i.", (int) info->pid, + info->exit_code ); + + unsigned int callbacks_i; + for( callbacks_i=0; SM_PROCESS_DEATH_MAX > callbacks_i; ++callbacks_i ) + { + callback = &(_callbacks[callbacks_i]); + + if( SM_PROCESS_DEATH_INFO_VALID == callback->valid ) + { + if( info->pid == callback->pid ) + { + if( NULL != callback->death_callback ) + { + callback->death_callback( info->pid, info->exit_code, + callback->user_data ); + callback->valid = 0; + } + } + } + } + + info->valid = 0; + + if( SM_PROCESS_DEATH_MAX_DISPATCH <= ++num_process_death_dispatched ) + { + DPRINTFD( "Maximum process death dispatches (%i) reached.", + SM_PROCESS_DEATH_MAX_DISPATCH ); + } + } + + if( SM_PROCESS_DEATH_MAX <= death_i ) + { + _last_entry = 0; + } else { + _last_entry = death_i; + } + + // Check for outstanding process deaths to handle. + for( death_i=0; SM_PROCESS_DEATH_MAX > death_i; ++death_i ) + { + info = &(_process_deaths[death_i]); + + if( SM_PROCESS_DEATH_INFO_VALID != info->valid ) + continue; + + if( 0 == info->pid ) + continue; + + if( 0 > write( _process_death_fd, &process_death_count, + sizeof(process_death_count) ) ) + { + DPRINTFE( "Failed to signal process death, error=%s", + strerror( errno ) ); + } + break; + } +} +// **************************************************************************** + +#ifdef __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ +// **************************************************************************** +// Process Death - Signal Handler +// ============================== +static void sm_process_death_signal_handler( int sig_num, siginfo_t* info, + void* context ) +{ + if( NULL != info ) + { + DPRINTFD( "Kernel process (%i) death notification, exit=%i.", + (int) info->si_pid, info->si_status ); + + sm_process_death_save( info->si_pid, SM_PROCESS_FAILED ); + } +} +#endif // __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + +// **************************************************************************** +// Process Death - Initialize +// ========================== +SmErrorT sm_process_death_initialize( void ) +{ + SmErrorT error; + + _process_death_fd = eventfd( 0, EFD_CLOEXEC | EFD_NONBLOCK ); + if( 0 > _process_death_fd ) + { + DPRINTFE( "Failed to open process death file descriptor,error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + error = sm_selobj_register( _process_death_fd, + sm_process_death_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + close( _process_death_fd ); + _process_death_fd = -1; + return( error ); + } + +#ifdef __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + struct sigaction sa; + + memset( &sa, 0, sizeof(sa) ); + sa.sa_sigaction = sm_process_death_signal_handler; + sa.sa_flags = (SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO); + sigaction( SM_KERNEL_NOTIFY_SIGNAL, &sa, NULL ); + + DPRINTFI( "Kernel notify signal (%i) registered.", + SM_KERNEL_NOTIFY_SIGNAL ); +#endif // __SM_PROCESS_DEATH_KERNEL_NOTIFICATION_SUPPORTED__ + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Process Death - Finalize +// ======================== +SmErrorT sm_process_death_finalize( void ) +{ + SmErrorT error; + + if( 0 <= _process_death_fd ) + { + error = sm_selobj_deregister( _process_death_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + close( _process_death_fd ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_process_death.h b/service-mgmt/sm-1.0.0/src/sm_process_death.h new file mode 100644 index 00000000..837f50c9 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_process_death.h @@ -0,0 +1,65 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_PROCESS_DEATH_H__ +#define __SM_PROCESS_DEATH_H__ + +#include +#include +#include +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmProcessDeathCallbackT) (pid_t pid, int exit_code, + int64_t user_data); + +// **************************************************************************** +// Process Death - Already Registered +// ================================== +extern bool sm_process_death_already_registered( pid_t pid, + SmProcessDeathCallbackT death_callback ); +// **************************************************************************** + +// **************************************************************************** +// Process Death - Register +// ======================== +extern SmErrorT sm_process_death_register( pid_t pid, bool child_process, + SmProcessDeathCallbackT death_callback, int64_t user_data ); +// **************************************************************************** + +// **************************************************************************** +// Process Death - Deregister +// ========================== +extern SmErrorT sm_process_death_deregister( pid_t pid ); +// **************************************************************************** + +// **************************************************************************** +// Process Death - Save +// ==================== +extern SmErrorT sm_process_death_save( pid_t pid, int exit_code ); +// **************************************************************************** + +// **************************************************************************** +// Process Death - Initialize +// ========================== +extern SmErrorT sm_process_death_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Process Death - Finalize +// ======================== +extern SmErrorT sm_process_death_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_PROCESS_DEATH_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_action.c b/service-mgmt/sm-1.0.0/src/sm_service_action.c new file mode 100644 index 00000000..973a9137 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_action.c @@ -0,0 +1,909 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_action.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_utils.h" +#include "sm_debug.h" +#include "sm_sha512.h" +#include "sm_service_action_table.h" +#include "sm_service_action_result_table.h" + +#define SM_SERVICE_ACTION_MAX_DELAY_IN_SECS 4 +#define SM_SERVICE_ACTION_TIMER_SKEW_IN_MS 60000 +#define SM_SERVICE_ACTION_VALIDATE_TIMER_IN_MS 60000 + +// **************************************************************************** +// Service Action - Validate +// ========================= +static void sm_service_action_validate( SmServiceActionDataT* action_data ) +{ + int bytes; + FILE* fp; + long ms_expired; + unsigned char data[2048]; + SmSha512HashT hash; + SmSha512ContextT context; + char plugin_exec[SM_SERVICE_ACTION_PLUGIN_EXEC_MAX_CHAR]; + + ms_expired = sm_time_get_elapsed_ms( &(action_data->last_hash_validate) ); + if( ms_expired < SM_SERVICE_ACTION_VALIDATE_TIMER_IN_MS ) + { + DPRINTFD( "Not enough time has elapsed, since last validate." ); + return; + } + + sm_time_get( &(action_data->last_hash_validate) ); + + if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_LSB_SCRIPT, + action_data->plugin_type ) ) + { + snprintf( plugin_exec, sizeof(plugin_exec), "%s/%s", + SM_SERVICE_ACTION_PLUGIN_TYPE_LSB_DIR, + action_data->plugin_name ); + + } else if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT, + action_data->plugin_type ) ) + { + snprintf( plugin_exec, sizeof(plugin_exec), "%s/%s/%s", + SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_PLUGIN_DIR, + action_data->plugin_class, action_data->plugin_name ); + } else { + snprintf( plugin_exec, sizeof(plugin_exec), "%s", + action_data->plugin_name ); + } + + fp = fopen( plugin_exec, "rb" ); + if( NULL == fp ) + { + DPRINTFE( "Failed to open file (%s).", plugin_exec ); + return; + } + + sm_sha512_initialize( &context ); + + while( 0 != (bytes = fread( data, 1, 2048, fp )) ) + { + sm_sha512_update( &context, data, bytes ); + } + + sm_sha512_finalize( &context, &hash ); + + if( 0 != memcmp( &(action_data->hash.bytes[0]), &(hash.bytes[0]), + SM_SHA512_HASH_SIZE ) ) + { + char was_hash_str[SM_SHA512_HASH_STR_SIZE]; + char now_hash_str[SM_SHA512_HASH_STR_SIZE]; + + sm_sha512_hash_str( was_hash_str, &(action_data->hash) ); + sm_sha512_hash_str( now_hash_str, &hash ); + + DPRINTFI( "Plugin (%s) has been changed, was=%s, now=%s.", + plugin_exec, was_hash_str, now_hash_str ); + + memcpy( &(action_data->hash), &hash, sizeof(hash) ); + } + + fclose( fp ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Exist +// ====================== +SmErrorT sm_service_action_exist( char service_name[], SmServiceActionT action ) +{ + SmServiceActionDataT* action_data; + + action_data = sm_service_action_table_read( service_name, action ); + if( NULL == action_data ) + { + DPRINTFD( "Service (%s) action (%s) does not exist.", service_name, + sm_service_action_str( action ) ); + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Interval +// ========================= +SmErrorT sm_service_action_interval( char service_name[], + SmServiceActionT action, int* interval_in_ms ) +{ + SmServiceActionDataT* action_data; + + *interval_in_ms = 0; + + action_data = sm_service_action_table_read( service_name, action ); + if( NULL == action_data ) + { + DPRINTFD( "Service (%s) action (%s) does not exist.", service_name, + sm_service_action_str( action ) ); + return( SM_NOT_FOUND ); + } + + *interval_in_ms = action_data->interval_in_secs * 1000; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Maximum Retries +// ================================ +SmErrorT sm_service_action_max_retries( char service_name[], + SmServiceActionT action, int* max_failure_retries, + int* max_timeout_retries, int* max_total_retries ) +{ + SmServiceActionDataT* action_data; + + *max_failure_retries = 0; + *max_timeout_retries = 0; + *max_total_retries = 0; + + action_data = sm_service_action_table_read( service_name, action ); + if( NULL == action_data ) + { + DPRINTFD( "Service (%s) action (%s) does not exist.", service_name, + sm_service_action_str( action ) ); + return( SM_NOT_FOUND ); + } + + *max_failure_retries = action_data->max_failure_retries; + *max_timeout_retries = action_data->max_timeout_retries; + *max_total_retries = action_data->max_total_retries; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Plugin Result +// ============================== +static SmErrorT sm_service_action_plugin_result( char service_name[], + SmServiceActionT action, char plugin_type[], char plugin_name[], + char plugin_command[], char plugin_exit_code[], + SmServiceActionResultDataT** action_result ) +{ + char plugin_command_default[] = "default"; + char plugin_exit_code_other[] = "other"; + + // Map the plugin result to an action result with the given data. + *action_result = sm_service_action_result_table_read( plugin_type, + plugin_name, plugin_command, plugin_exit_code ); + if( NULL != *action_result ) + { + DPRINTFD( "Read service (%s) action (%s) plugin (%s, %s, %s, %s) data.", + service_name, sm_service_action_str( action ), plugin_type, + plugin_name, plugin_command, plugin_exit_code ); + return( SM_OKAY ); + } + + // Map the plugin result to an action result with the plugin exit + // code set to "other". + *action_result = sm_service_action_result_table_read( plugin_type, + plugin_name, plugin_command, plugin_exit_code_other ); + if( NULL != *action_result ) + { + DPRINTFD( "Read service (%s) action (%s) plugin (%s, %s, %s, other) " + "data.", service_name, sm_service_action_str( action ), + plugin_type, plugin_name, plugin_command ); + return( SM_OKAY ); + } + + // Map the plugin result to an action result with the plugin command + // set to "default". + *action_result = sm_service_action_result_table_read( plugin_type, + plugin_name, plugin_command_default, plugin_exit_code ); + if( NULL != *action_result ) + { + DPRINTFD( "Read service (%s) action (%s) plugin (%s, %s, default, %s) " + "data.", service_name, sm_service_action_str( action ), + plugin_type, plugin_name, plugin_exit_code ); + return( SM_OKAY ); + } + + // Map the plugin result to an action result with the plugin + // command set to "default" and the plugin exit code set to "other". + *action_result = sm_service_action_result_table_read( plugin_type, + plugin_name, plugin_command_default, + plugin_exit_code_other ); + if( NULL != *action_result ) + { + DPRINTFD( "Read service (%s) action (%s) plugin " + "(%s, %s, default, other) data.", service_name, + sm_service_action_str( action ), plugin_type, plugin_name ); + return( SM_OKAY ); + } + + return( SM_NOT_FOUND ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Result +// ======================= +SmErrorT sm_service_action_result( int exit_code, char service_name[], + SmServiceActionT action, SmServiceActionResultT* action_result, + SmServiceStateT* service_state, SmServiceStatusT* service_status, + SmServiceConditionT* service_condition, char reason_text[] ) +{ + char plugin_name_default[] = "default"; + char plugin_exit_code[SM_SERVICE_ACTION_PLUGIN_EXIT_CODE_MAX_CHAR]; + SmServiceActionDataT* action_data; + SmServiceActionResultDataT* result; + SmErrorT error; + + reason_text[0] = '\0'; + + if( SM_SERVICE_ACTION_PLUGIN_FAILURE == exit_code ) + { + snprintf( plugin_exit_code, sizeof(plugin_exit_code), + "plugin-failure" ); + + } else if( SM_SERVICE_ACTION_PLUGIN_TIMEOUT == exit_code ) { + snprintf( plugin_exit_code, sizeof(plugin_exit_code), + "plugin-timeout" ); + } else { + snprintf( plugin_exit_code, sizeof(plugin_exit_code), + "%i", exit_code ); + } + + *action_result = SM_SERVICE_ACTION_RESULT_UNKNOWN; + *service_state = SM_SERVICE_STATE_UNKNOWN; + *service_status = SM_SERVICE_STATUS_UNKNOWN; + *service_condition = SM_SERVICE_CONDITION_UNKNOWN; + + action_data = sm_service_action_table_read( service_name, action ); + if( NULL == action_data ) + { + DPRINTFD( "Service (%s) action (%s) does not exist.", service_name, + sm_service_action_str( action ) ); + return( SM_NOT_FOUND ); + } + + error = sm_service_action_plugin_result( service_name, action, + action_data->plugin_type, action_data->plugin_name, + action_data->plugin_command, plugin_exit_code, &result ); + if( SM_OKAY == error ) + { + *action_result = result->action_result; + *service_state = result->service_state; + *service_status = result->service_status; + *service_condition = result->service_condition; + return( SM_OKAY ); + + } else if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) { + DPRINTFE( "Failed to read service (%s) action (%s) plugin result " + "data, error=%s.", service_name, + sm_service_action_str( action ), sm_error_str( error ) ); + return( error ); + } + + error = sm_service_action_plugin_result( service_name, action, + action_data->plugin_type, plugin_name_default, + action_data->plugin_command, plugin_exit_code, &result ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read service (%s) action (%s) plugin result " + "data, error=%s.", service_name, + sm_service_action_str( action ), sm_error_str( error ) ); + return( error ); + } + + *action_result = result->action_result; + *service_state = result->service_state; + *service_status = result->service_status; + *service_condition = result->service_condition; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Abort +// ====================== +SmErrorT sm_service_action_abort( char service_name[], int process_id ) +{ +// +//TODO: Verify the process we are about to abort is the process we expect. +// + if( -1 == process_id ) + { + DPRINTFE( "Trying to abort a process (%i) for service (%s), " + "but pid is invalid.", process_id, service_name ); + return( SM_FAILED ); + } + + if( process_id == (int) getpid() ) + { + DPRINTFE( "Trying to abort a process (%i) for service (%s), " + "but pid is self.", process_id, service_name ); + return( SM_FAILED ); + } + + DPRINTFI( "Aborting service (%s) with kill signal, pid=%i.", + service_name, process_id ); + + if( 0 > kill( process_id, SIGKILL ) ) + { + if( ESRCH == errno ) + { + DPRINTFD( "Service (%s) action not running.", service_name ); + return( SM_OKAY ); + + } else { + DPRINTFE( "Failed to send kill signal to service (%s), " + "error=%s.", service_name, strerror( errno ) ); + return( SM_FAILED ); + } + } + + DPRINTFD( "Kill signal sent to service (%s).", service_name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Setup Instance Environment Variables +// ===================================================== +static SmErrorT sm_service_action_setup_instance_env_vars( char instance_name[], + char instance_params[], SmServiceActionDataT* action_data ) +{ + char looking_for = '='; + char key_storage[SM_SERVICE_INSTANCE_PARAMS_MAX_CHAR+32]; + char value_storage[SM_SERVICE_INSTANCE_PARAMS_MAX_CHAR+32]; + char* key = NULL; + char* value = NULL; + char* param = NULL; + + if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT, + action_data->plugin_type ) ) + { + if( 0 > setenv( "OCF_RA_VERSION_MAJOR", + SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_VERSION, 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(OCF_RA_VERSION_MAJOR), error=%s.", strerror( errno ) ); + goto ERROR; + } + + if( 0 > setenv( "OCF_RA_VERSION_MINOR", + SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_REVISION, 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(OCF_RA_VERSION_MINOR), error=%s.", strerror( errno ) ); + goto ERROR; + } + + if( 0 > setenv( "OCF_ROOT", + SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_DIR, 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(OCF_ROOT), error=%s.", strerror( errno ) ); + goto ERROR; + } + + if( 0 > setenv( "OCF_RESOURCE_INSTANCE", instance_name, 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(OCF_RESOURCE_INSTANCE), error=%s.", strerror( errno ) ); + goto ERROR; + } + + if( 0 > setenv( "OCF_RESOURCE_TYPE", + action_data->plugin_name, 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(OCF_RESOURCE_TYPE), error=%s.", strerror( errno ) ); + goto ERROR; + } + } + + param = &(value_storage[sizeof(value_storage)-1]); + *param = '\0'; --param; + + int char_i; + for( char_i=strlen(instance_params)-1; 0 <= char_i; --char_i ) + { + if( looking_for == instance_params[char_i] ) + { + if( ',' == looking_for ) + { + key = param+1; + + if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT, + action_data->plugin_type ) ) + { + key -= strlen("OCF_RESKEY_"); + memcpy( key, "OCF_RESKEY_", strlen("OCF_RESKEY_") ); + } + + DPRINTFD( "%s set environment: %s=%s", instance_name, key, + value ); + + if( 0 > setenv( key, value, 1 ) ) + { + DPRINTFE( "Failed to set environment variable (%s=%s), " + "error=%s.", key, value, strerror( errno ) ); + goto ERROR; + } + + key = NULL; + value = NULL; + param = &(value_storage[sizeof(value_storage)-1]); + *param = '\0'; --param; + looking_for = '='; + + } else { + key = NULL; + value = param+1; + param = &(key_storage[sizeof(key_storage)-1]); + *param = '\0'; --param; + looking_for = ','; + } + } else { + *param = instance_params[char_i]; + --param; + } + } + + if( NULL != value ) + { + key = param+1; + + if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT, + action_data->plugin_type ) ) + { + key -= strlen("OCF_RESKEY_"); + memcpy( key, "OCF_RESKEY_", strlen("OCF_RESKEY_") ); + } + + DPRINTFD( "%s set environment: %s=%s", instance_name, key, + value ); + + if( 0 > setenv( key, value, 1 ) ) + { + DPRINTFE( "Failed to set environment variable (%s=%s), " + "error=%s.", key, value, strerror( errno ) ); + goto ERROR; + } + } + + return( SM_OKAY ); + +ERROR: + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Setup Plugin Environment Variables +// =================================================== +static SmErrorT sm_service_action_setup_plugin_env_vars( + SmServiceActionDataT* action_data ) +{ + char looking_for = '='; + char key_storage[SM_SERVICE_ACTION_PLUGIN_PARAMS_MAX_CHAR+32]; + char value_storage[SM_SERVICE_ACTION_PLUGIN_PARAMS_MAX_CHAR+32]; + char* key = NULL; + char* value = NULL; + char* param = NULL; + + if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_LSB_SCRIPT, + action_data->plugin_type ) ) + { + if( 0 > setenv( "SYSTEMCTL_SKIP_REDIRECT", "1", 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(SYSTEMCTL_SKIP_REDIRECT), error=%s.", + strerror( errno ) ); + goto ERROR; + } + + } else if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT, + action_data->plugin_type ) ) + { + if( 0 > setenv( "HA_LOGFACILITY", "daemon", 1 ) ) + { + DPRINTFE( "Failed to set environment variable (HA_LOGFACILITY), " + "error=%s.", strerror( errno ) ); + goto ERROR; + } + } + + param = &(value_storage[sizeof(value_storage)-1]); + *param = '\0'; --param; + + int char_i; + for( char_i=strlen(action_data->plugin_params)-1; 0 <= char_i; --char_i ) + { + if( looking_for == action_data->plugin_params[char_i] ) + { + if( ',' == looking_for ) + { + key = param+1; + + if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT, + action_data->plugin_type ) ) + { + key -= strlen("OCF_RESKEY_CRM_meta_"); + memcpy( key, "OCF_RESKEY_CRM_meta_", + strlen("OCF_RESKEY_CRM_meta_") ); + } + + DPRINTFD( "%s set environment: %s=%s", + action_data->service_name, key, value ); + + if( 0 > setenv( key, value, 1 ) ) + { + DPRINTFE( "Failed to set environment variable (%s=%s), " + "error=%s.", key, value, strerror( errno ) ); + goto ERROR; + } + + param = &(value_storage[sizeof(value_storage)-1]); + *param = '\0'; --param; + looking_for = '='; + + } else { + value = param+1; + param = &(key_storage[sizeof(key_storage)-1]); + *param = '\0'; --param; + looking_for = ','; + } + } else { + *param = action_data->plugin_params[char_i]; + --param; + } + } + + if( NULL != value ) + { + key = param+1; + + if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT, + action_data->plugin_type ) ) + { + key -= strlen("OCF_RESKEY_CRM_meta_"); + memcpy( key, "OCF_RESKEY_CRM_meta_", strlen("OCF_RESKEY_CRM_meta_") ); + } + + DPRINTFD( "%s set environment: %s=%s", action_data->service_name, + key, value ); + + if( 0 > setenv( key, value, 1 ) ) + { + DPRINTFE( "Failed to set environment variable (%s=%s), " + "error=%s.", key, value, strerror( errno ) ); + goto ERROR; + } + } + + return( SM_OKAY ); + +ERROR: + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Setup Environment +// ================================== +static SmErrorT sm_service_action_setup_env( char instance_name[], + char instance_params[], SmServiceActionDataT* action_data ) +{ + SmErrorT error; + + error = sm_service_action_setup_instance_env_vars( instance_name, + instance_params, action_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set instance environment variables for service " + "(%s) action (%s), error=%s.", action_data->service_name, + sm_service_action_str( action_data->action ), + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_action_setup_plugin_env_vars( action_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set plugin environment variables for service " + "(%s) action (%s), error=%s.", action_data->service_name, + sm_service_action_str( action_data->action ), + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Run +// ==================== +SmErrorT sm_service_action_run( char service_name[], char instance_name[], + char instance_params[], SmServiceActionT action, int* process_id, + int* timeout_in_ms ) +{ + pid_t pid; + bool service_managed = true; + struct stat stat_data; + char plugin_exec[SM_SERVICE_ACTION_PLUGIN_EXEC_MAX_CHAR]; + int result; + SmServiceActionDataT* action_data; + SmErrorT error; + + *process_id = -1; + *timeout_in_ms = 0; + + action_data = sm_service_action_table_read( service_name, action ); + if( NULL == action_data ) + { + DPRINTFD( "Service (%s) action (%s) does not exist.", service_name, + sm_service_action_str( action ) ); + return( SM_NOT_FOUND ); + } + + snprintf( plugin_exec, sizeof(plugin_exec), "%s/%s.unmanaged", + SM_RUN_SERVICES_DIRECTORY, service_name ); + if( 0 == access( plugin_exec, F_OK ) ) + { + DPRINTFI( "Service (%s) is unmanaged, actions are force-passed.", + service_name ); + service_managed = false; + } + + if( service_managed ) + { + sm_service_action_validate( action_data ); + + if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_LSB_SCRIPT, + action_data->plugin_type ) ) + { + snprintf( plugin_exec, sizeof(plugin_exec), "%s/%s", + SM_SERVICE_ACTION_PLUGIN_TYPE_LSB_DIR, + action_data->plugin_name ); + + } else if( 0 == strcmp( SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT, + action_data->plugin_type ) ) + { + snprintf( plugin_exec, sizeof(plugin_exec), "%s/%s/%s", + SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_PLUGIN_DIR, + action_data->plugin_class, action_data->plugin_name ); + } else { + snprintf( plugin_exec, sizeof(plugin_exec), "%s", + action_data->plugin_name ); + } + + DPRINTFD( "Plugin executable (%s) for service (%s).", plugin_exec, + action_data->service_name ); + + if( 0 > access( plugin_exec, F_OK | X_OK ) ) + { + DPRINTFE( "Service (%s) plugin (%s) access failed, error=%s.", + action_data->service_name, plugin_exec, + strerror( errno ) ); + return( SM_FAILED ); + } + + if( 0 > stat( plugin_exec, &stat_data ) ) + { + DPRINTFE( "Service (%s) plugin (%s) stat failed, error=%s.", + action_data->service_name, plugin_exec, + strerror( errno ) ); + return( SM_FAILED ); + } + + if( 0 >= stat_data.st_size ) + { + DPRINTFE( "Service (%s) plugin (%s) has zero size.", + action_data->service_name, action_data->plugin_name ); + return( SM_FAILED ); + } + } + + pid = fork(); + if( 0 > pid ) + { + DPRINTFE( "Failed to fork process for service (%s), error=%s.", + action_data->service_name, strerror( errno ) ); + return( SM_FAILED ); + + } else if( 0 == pid ) { + // Child process. + struct rlimit file_limits; + + DPRINTFD( "Child process created for service (%s).", + action_data->service_name ); + + if( 0 > setpgid( 0, 0 ) ) + { + DPRINTFE( "Failed to set process group id for service (%s), " + "error=%s.", action_data->service_name, + strerror( errno ) ); + exit( SM_SERVICE_ACTION_PLUGIN_FAILURE ); + } + + if( 0 > getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + DPRINTFE( "Failed to get file limits for service (%s), " + "error=%s.", action_data->service_name, + strerror( errno ) ); + exit( SM_SERVICE_ACTION_PLUGIN_FAILURE ); + } + + unsigned int fd_i; + for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i ) + { + close( fd_i ); + } + + if( 0 > open( "/dev/null", O_RDONLY ) ) + { + DPRINTFE( "Failed to open stdin to /dev/null for service (%s), " + "error=%s.", action_data->service_name, + strerror( errno ) ); + } + + if( 0 > open( "/dev/null", O_WRONLY ) ) + { + DPRINTFE( "Failed to open stdout to /dev/null for service (%s), " + "error=%s.", action_data->service_name, + strerror( errno ) ); + } + + if( 0 > open( "/dev/null", O_WRONLY ) ) + { + DPRINTFE( "Failed to open stderr to /dev/null for service (%s), " + "error=%s.", action_data->service_name, + strerror( errno ) ); + } + + result = setpriority( PRIO_PROCESS, getpid(), -1 ); + if( 0 > result ) + { + DPRINTFE( "Failed to set priority of process, error=%s.", + strerror( errno ) ); + exit( SM_SERVICE_ACTION_PLUGIN_FAILURE ); + } + + if( !service_managed ) + { + exit( SM_SERVICE_ACTION_PLUGIN_FORCE_SUCCESS ); + } + + error = sm_service_action_setup_env( instance_name, instance_params, + action_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to setup environment for service (%s), " + "error=%s.", action_data->service_name, + sm_error_str( error ) ); + exit( SM_SERVICE_ACTION_PLUGIN_FAILURE ); + } + +#ifdef SM_SERVICE_ACTION_TIME_PLUGIN + char time_exec[] = "/usr/bin/time"; + char time_append[] = "-a"; + char time_output[] = "-o"; + char time_file[80]; + char* argv[] = {time_exec, time_append, time_output, time_file, + plugin_exec, action_data->plugin_command, NULL}; + + snprintf( time_file, sizeof(time_file), "/tmp/%s_%s-timing.txt", + action_data->service_name, action_data->plugin_command ); + + if( 0 > execv( time_exec, argv ) ) + { + DPRINTFE( "Failed to exec command for service (%s), " + "error=%s.", action_data->service_name, + strerror( errno ) ); + } +#else + char* argv[] = {plugin_exec, action_data->plugin_command, NULL}; + + if( 0 > execv( plugin_exec, argv ) ) + { + DPRINTFE( "Failed to exec command for service (%s), " + "error=%s.", action_data->service_name, + strerror( errno ) ); + } +#endif // SM_SERVICE_ACTION_TIME_PLUGIN + + exit( SM_SERVICE_ACTION_PLUGIN_FAILURE ); + + } else { + // Parent process. + *process_id = (int) pid; + *timeout_in_ms = action_data->timeout_in_secs * 1000; + + if( sm_utils_watchdog_delayed( SM_SERVICE_ACTION_MAX_DELAY_IN_SECS ) ) + { + DPRINTFI( "Service (%s) timeout %d secs increased by %d ms, " + "sm-watchdog delayed.", action_data->service_name, + action_data->timeout_in_secs, + SM_SERVICE_ACTION_TIMER_SKEW_IN_MS ); + *timeout_in_ms += SM_SERVICE_ACTION_TIMER_SKEW_IN_MS; + } + + DPRINTFD( "Child process (%i) created for service (%s).", *process_id, + action_data->service_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Initialize +// =========================== +SmErrorT sm_service_action_initialize( void ) +{ + SmErrorT error; + + error = sm_service_action_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service action table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_action_result_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service action result table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action - Finalize +// ========================= +SmErrorT sm_service_action_finalize( void ) +{ + SmErrorT error; + + error = sm_service_action_result_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service action result table, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_action_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service action table, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_action.h b/service-mgmt/sm-1.0.0/src/sm_service_action.h new file mode 100644 index 00000000..4ffdfa24 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_action.h @@ -0,0 +1,79 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ACTION_H__ +#define __SM_SERVICE_ACTION_H__ + +#include +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Action - Exist +// ====================== +extern SmErrorT sm_service_action_exist( char service_name[], + SmServiceActionT action ); +// **************************************************************************** + +// **************************************************************************** +// Service Action - Interval +// ========================= +extern SmErrorT sm_service_action_interval( char service_name[], + SmServiceActionT action, int* interval_in_ms ); +// **************************************************************************** + +// **************************************************************************** +// Service Action - Maximum Retries +// ================================ +extern SmErrorT sm_service_action_max_retries( char service_name[], + SmServiceActionT action, int* max_failure_retries, + int* max_timeout_retries, int* max_total_retries ); +// **************************************************************************** + +// **************************************************************************** +// Service Action - Result +// ======================= +extern SmErrorT sm_service_action_result( int exit_code, char service_name[], + SmServiceActionT action, SmServiceActionResultT* action_result, + SmServiceStateT* service_state, SmServiceStatusT* service_status, + SmServiceConditionT* service_condition, char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Action - Abort +// ====================== +extern SmErrorT sm_service_action_abort( char service_name[], int process_id ); +// **************************************************************************** + +// **************************************************************************** +// Service Action - Run +// ==================== +extern SmErrorT sm_service_action_run( char service_name[], + char instance_name[], char instance_params[], SmServiceActionT action, + int* process_id, int* timeout_in_ms ); +// **************************************************************************** + +// **************************************************************************** +// Service Action - Initialize +// =========================== +extern SmErrorT sm_service_action_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Action - Finalize +// ========================= +extern SmErrorT sm_service_action_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ACTION_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_action_result_table.c b/service-mgmt/sm-1.0.0/src/sm_service_action_result_table.c new file mode 100644 index 00000000..cf63225d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_action_result_table.c @@ -0,0 +1,195 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_action_result_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_action_results.h" + +static SmListT* _service_action_results = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Action Result Table - Read +// ================================== +SmServiceActionResultDataT* sm_service_action_result_table_read( + char plugin_type[], char plugin_name[], char plugin_command[], + char plugin_exit_code[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceActionResultDataT* service_action_result; + + SM_LIST_FOREACH( _service_action_results, entry, entry_data ) + { + service_action_result = (SmServiceActionResultDataT*) entry_data; + + if(( 0 == strcmp( plugin_type, service_action_result->plugin_type ) )&& + ( 0 == strcmp( plugin_name, service_action_result->plugin_name ) )&& + ( 0 == strcmp( plugin_command, + service_action_result->plugin_command ) )&& + ( 0 == strcmp( plugin_exit_code, + service_action_result->plugin_exit_code ) )) + { + return( service_action_result ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Result Table - Add +// ================================= +static SmErrorT sm_service_action_result_table_add( void* user_data[], + void* record ) +{ + SmServiceActionResultDataT* service_action_result; + SmDbServiceActionResultT* db_service_action_result; + + db_service_action_result = (SmDbServiceActionResultT*) record; + + service_action_result = sm_service_action_result_table_read( + db_service_action_result->plugin_type, + db_service_action_result->plugin_name, + db_service_action_result->plugin_command, + db_service_action_result->plugin_exit_code ); + if( NULL == service_action_result ) + { + service_action_result = (SmServiceActionResultDataT*) + malloc( sizeof(SmServiceActionResultDataT) ); + if( NULL == service_action_result ) + { + DPRINTFE( "Failed to allocate service action result table entry." ); + return( SM_FAILED ); + } + + memset( service_action_result, 0, sizeof(SmServiceActionResultDataT) ); + + snprintf( service_action_result->plugin_type, + sizeof(service_action_result->plugin_type), "%s", + db_service_action_result->plugin_type ); + snprintf( service_action_result->plugin_name, + sizeof(service_action_result->plugin_name), "%s", + db_service_action_result->plugin_name ); + snprintf( service_action_result->plugin_command, + sizeof(service_action_result->plugin_command), "%s", + db_service_action_result->plugin_command ); + snprintf( service_action_result->plugin_exit_code, + sizeof(service_action_result->plugin_exit_code), "%s", + db_service_action_result->plugin_exit_code ); + service_action_result->action_result + = db_service_action_result->action_result; + service_action_result->service_state + = db_service_action_result->service_state; + service_action_result->service_status + = db_service_action_result->service_status; + service_action_result->service_condition + = db_service_action_result->service_condition; + + SM_LIST_PREPEND( _service_action_results, + (SmListEntryDataPtrT) service_action_result ); + + } else { + service_action_result->action_result + = db_service_action_result->action_result; + service_action_result->service_state + = db_service_action_result->service_state; + service_action_result->service_status + = db_service_action_result->service_status; + service_action_result->service_condition + = db_service_action_result->service_condition; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Result Table - Load +// ================================== +SmErrorT sm_service_action_result_table_load( void ) +{ + SmDbServiceActionResultT service_action_result; + SmErrorT error; + + error = sm_db_foreach( SM_DATABASE_NAME, SM_SERVICE_ACTION_RESULTS_TABLE_NAME, + NULL, &service_action_result, + sm_db_service_action_results_convert, + sm_service_action_result_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service action results in database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Result Table - Initialize +// ======================================== +SmErrorT sm_service_action_result_table_initialize( void ) +{ + SmErrorT error; + + _service_action_results = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_action_result_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service action results from database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Result Table - Finalize +// ====================================== +SmErrorT sm_service_action_result_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_action_results ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_action_result_table.h b/service-mgmt/sm-1.0.0/src/sm_service_action_result_table.h new file mode 100644 index 00000000..2d7edc00 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_action_result_table.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ACTION_RESULT_TABLE_H__ +#define __SM_SERVICE_ACTION_RESULT_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + char plugin_type[SM_SERVICE_ACTION_PLUGIN_TYPE_MAX_CHAR]; + char plugin_name[SM_SERVICE_ACTION_PLUGIN_NAME_MAX_CHAR]; + char plugin_command[SM_SERVICE_ACTION_PLUGIN_COMMAND_MAX_CHAR]; + char plugin_exit_code[SM_SERVICE_ACTION_PLUGIN_EXIT_CODE_MAX_CHAR]; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; +} SmServiceActionResultDataT; + +// **************************************************************************** +// Service Action Result Table - Read +// ================================== +extern SmServiceActionResultDataT* sm_service_action_result_table_read( + char plugin_type[], char plugin_name[], char plugin_command[], + char plugin_exit_code[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Action Result Table - Load +// ================================== +extern SmErrorT sm_service_action_result_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Action Result Table - Initialize +// ======================================== +extern SmErrorT sm_service_action_result_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Action Result Table - Finalize +// ====================================== +extern SmErrorT sm_service_action_result_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ACTION_RESULT_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_action_table.c b/service-mgmt/sm-1.0.0/src/sm_service_action_table.c new file mode 100644 index 00000000..ffbd3b19 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_action_table.c @@ -0,0 +1,255 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_action_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_time.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_services.h" +#include "sm_db_service_actions.h" + +static SmListT* _service_actions = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +static int _interval_extension_in_secs = 0; +static int _timeout_extension_in_secs = 0; + +// **************************************************************************** +// Service Action Table - Set Interval Extension +// ============================================= +void sm_service_action_table_set_interval_extension( + int interval_extension_in_secs ) +{ + _interval_extension_in_secs = interval_extension_in_secs; +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Set Timeout Extension +// ============================================ +void sm_service_action_table_set_timeout_extension( + int timeout_extension_in_secs ) +{ + _timeout_extension_in_secs = timeout_extension_in_secs; +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Read +// =========================== +SmServiceActionDataT* sm_service_action_table_read( char service_name[], + SmServiceActionT action ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceActionDataT* service_action; + + SM_LIST_FOREACH( _service_actions, entry, entry_data ) + { + service_action = (SmServiceActionDataT*) entry_data; + + if(( action == service_action->action )&& + ( 0 == strcmp( service_name, service_action->service_name ) )) + { + return( service_action ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Add +// ========================== +static SmErrorT sm_service_action_table_add( void* user_data[], void* record ) +{ + SmDbServiceT db_service; + SmServiceActionDataT* service_action; + SmDbServiceActionT* db_service_action = (SmDbServiceActionT*) record; + SmErrorT error; + + error = sm_db_services_read( _sm_db_handle, + db_service_action->service_name, + &db_service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + db_service_action->service_name, sm_error_str( error ) ); + return( SM_FAILED ); + } + + if( !(db_service.provisioned) ) + { + return( SM_OKAY ); + } + + service_action = sm_service_action_table_read( + db_service_action->service_name, + db_service_action->action ); + if( NULL == service_action ) + { + service_action + = (SmServiceActionDataT*) malloc( sizeof(SmServiceActionDataT) ); + if( NULL == service_action ) + { + DPRINTFE( "Failed to allocate service action table entry." ); + return( SM_FAILED ); + } + + memset( service_action, 0, sizeof(SmServiceActionDataT) ); + + snprintf( service_action->service_name, + sizeof(service_action->service_name), "%s", + db_service_action->service_name ); + service_action->action = db_service_action->action; + snprintf( service_action->plugin_type, + sizeof(service_action->plugin_type), "%s", + db_service_action->plugin_type ); + snprintf( service_action->plugin_class, + sizeof(service_action->plugin_class), "%s", + db_service_action->plugin_class ); + snprintf( service_action->plugin_name, + sizeof(service_action->plugin_name), "%s", + db_service_action->plugin_name ); + snprintf( service_action->plugin_command, + sizeof(service_action->plugin_command), "%s", + db_service_action->plugin_command ); + snprintf( service_action->plugin_params, + sizeof(service_action->plugin_params), "%s", + db_service_action->plugin_params ); + service_action->max_failure_retries + = db_service_action->max_failure_retries; + service_action->max_timeout_retries + = db_service_action->max_timeout_retries; + service_action->max_total_retries + = db_service_action->max_total_retries; + service_action->timeout_in_secs + = db_service_action->timeout_in_secs + _timeout_extension_in_secs; + service_action->interval_in_secs + = db_service_action->interval_in_secs + _interval_extension_in_secs; + memset( &(service_action->hash), 0, sizeof(service_action->hash) ); + sm_time_get( &(service_action->last_hash_validate) ); + + SM_LIST_PREPEND( _service_actions, + (SmListEntryDataPtrT) service_action ); + } else { + snprintf( service_action->plugin_type, + sizeof(service_action->plugin_type), "%s", + db_service_action->plugin_type ); + snprintf( service_action->plugin_class, + sizeof(service_action->plugin_class), "%s", + db_service_action->plugin_class ); + snprintf( service_action->plugin_name, + sizeof(service_action->plugin_name), "%s", + db_service_action->plugin_name ); + snprintf( service_action->plugin_command, + sizeof(service_action->plugin_command), "%s", + db_service_action->plugin_command ); + snprintf( service_action->plugin_params, + sizeof(service_action->plugin_params), "%s", + db_service_action->plugin_params ); + service_action->max_failure_retries + = db_service_action->max_failure_retries; + service_action->max_timeout_retries + = db_service_action->max_timeout_retries; + service_action->max_total_retries + = db_service_action->max_total_retries; + service_action->timeout_in_secs + = db_service_action->timeout_in_secs + _timeout_extension_in_secs; + service_action->interval_in_secs + = db_service_action->interval_in_secs + _interval_extension_in_secs; + memset( &(service_action->hash), 0, sizeof(service_action->hash) ); + sm_time_get( &(service_action->last_hash_validate) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Load +// =========================== +SmErrorT sm_service_action_table_load( void ) +{ + SmDbServiceActionT service_action; + SmErrorT error; + + error = sm_db_foreach( SM_DATABASE_NAME, SM_SERVICE_ACTIONS_TABLE_NAME, + NULL, &service_action, sm_db_service_actions_convert, + sm_service_action_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service actions in database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Initialize +// ================================= +SmErrorT sm_service_action_table_initialize( void ) +{ + SmErrorT error; + + _service_actions = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_action_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service actions from database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Finalize +// =============================== +SmErrorT sm_service_action_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_actions ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_action_table.h b/service-mgmt/sm-1.0.0/src/sm_service_action_table.h new file mode 100644 index 00000000..f1089cfe --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_action_table.h @@ -0,0 +1,81 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ACTION_TABLE_H__ +#define __SM_SERVICE_ACTION_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_time.h" +#include "sm_sha512.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + char service_name[SM_SERVICE_NAME_MAX_CHAR]; + SmServiceActionT action; + char plugin_type[SM_SERVICE_ACTION_PLUGIN_TYPE_MAX_CHAR]; + char plugin_class[SM_SERVICE_ACTION_PLUGIN_CLASS_MAX_CHAR]; + char plugin_name[SM_SERVICE_ACTION_PLUGIN_NAME_MAX_CHAR]; + char plugin_command[SM_SERVICE_ACTION_PLUGIN_COMMAND_MAX_CHAR]; + char plugin_params[SM_SERVICE_ACTION_PLUGIN_PARAMS_MAX_CHAR]; + int max_failure_retries; + int max_timeout_retries; + int max_total_retries; + int timeout_in_secs; + int interval_in_secs; + SmSha512HashT hash; + SmTimeT last_hash_validate; +} SmServiceActionDataT; + +// **************************************************************************** +// Service Action Table - Set Interval Extension +// ============================================= +extern void sm_service_action_table_set_interval_extension( + int interval_extension_in_secs ); +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Set Timeout Extension +// ============================================ +extern void sm_service_action_table_set_timeout_extension( + int timeout_extension_in_secs ); +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Read +// =========================== +extern SmServiceActionDataT* sm_service_action_table_read( char service_name[], + SmServiceActionT action ); +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Load +// =========================== +extern SmErrorT sm_service_action_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Initialize +// ================================= +extern SmErrorT sm_service_action_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Action Table - Finalize +// =============================== +extern SmErrorT sm_service_action_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ACTION_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_api.c b/service-mgmt/sm-1.0.0/src/sm_service_api.c new file mode 100644 index 00000000..cda8197e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_api.c @@ -0,0 +1,481 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_api.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_timer.h" +#include "sm_service_table.h" +#include "sm_service_dependency.h" +#include "sm_service_engine.h" +#include "sm_service_fsm.h" +#include "sm_service_go_active.h" +#include "sm_service_go_standby.h" +#include "sm_service_action.h" + +static SmListT* _callbacks = NULL; + +// **************************************************************************** +// Service API - Register Callback +// =============================== +SmErrorT sm_service_api_register_callback( SmServiceApiCallbackT callback ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Deregister Callback +// ================================= +SmErrorT sm_service_api_deregister_callback( SmServiceApiCallbackT callback ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Service Callback +// ============================== +static void sm_service_api_service_callback( char service_name[], + SmServiceStateT state, SmServiceStatusT status, + SmServiceConditionT condition ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceApiCallbackT callback; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return; + } + + if(( SM_SERVICE_STATE_ENABLED_STANDBY == service->desired_state )&& + ( SM_SERVICE_STATE_DISABLED == service->state ) && + ( SM_SERVICE_STATUS_NONE == service->status )) + { + bool exists; + + error = sm_service_go_standby_exists( service, &exists ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str( error ) ); + return; + } + + if( !exists ) + { + // No standby service action exists. Notify higher + // layers that the service is in the standby state. + state = SM_SERVICE_STATE_ENABLED_STANDBY; + } + } + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callback = (SmServiceApiCallbackT) entry_data; + + callback( service_name, state, status, condition ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Abort Action +// ========================== +static void sm_service_api_abort_action( void* user_data[], + SmServiceT* service ) +{ + SmErrorT error; + + if(( SM_SERVICE_ACTION_NIL == service->action_running )|| + ( SM_SERVICE_ACTION_UNKNOWN == service->action_running )|| + ( SM_SERVICE_ACTION_NONE == service->action_running )) + { + DPRINTFD( "Service (%s) not running an action.", service->name ); + return; + } + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort service (%s) action (%s, pid=%i), " + "error=%s.", service->name, + sm_service_action_str( service->action_running ), + service->action_pid, sm_error_str( error ) ); + return; + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop timer for action (%s) of " + "service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return; + } + + DPRINTFI( "Timer stopped for action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + service->action_attempts = -1; + return; +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Abort Actions +// =========================== +SmErrorT sm_service_api_abort_actions( void ) +{ + sm_service_table_foreach( NULL, sm_service_api_abort_action ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Go-Active +// ======================= +SmErrorT sm_service_api_go_active( char service_name[] ) +{ + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if( SM_SERVICE_STATE_ENABLED_ACTIVE != service->desired_state ) + { + service->desired_state = SM_SERVICE_STATE_ENABLED_ACTIVE; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_engine_signal( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service (%s), error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Go-Standby +// ======================== +SmErrorT sm_service_api_go_standby( char service_name[] ) +{ + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if( SM_SERVICE_STATE_ENABLED_STANDBY != service->desired_state ) + { + service->desired_state = SM_SERVICE_STATE_ENABLED_STANDBY; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_engine_signal( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service (%s), error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Disable +// ===================== +SmErrorT sm_service_api_disable( char service_name[] ) +{ + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if( SM_SERVICE_STATE_DISABLED != service->desired_state ) + { + service->desired_state = SM_SERVICE_STATE_DISABLED; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_engine_signal( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service (%s), error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Recover +// ===================== +SmErrorT sm_service_api_recover( char service_name[], + bool clear_fatal_condition ) +{ + SmServiceT* service; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if(( 0 < service->fail_count )||( 0 < service->action_fail_count )) + { + service->recover = true; + DPRINTFI( "Recovery of service (%s) requested.", service->name ); + } + + if(( clear_fatal_condition )&&( 0 < service->transition_fail_count )) + { + service->clear_fatal_condition = true; + DPRINTFI( "Recovery of service (%s) from fatal condition requested.", + service->name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Restart +// ===================== +SmErrorT sm_service_api_restart( char service_name[], int flag ) +{ + SmServiceT* service; + SmServiceEventT event = SM_SERVICE_EVENT_DISABLE; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR]; + SmErrorT error; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if ( flag & SM_SVC_RESTART_NO_DEP ) + { + snprintf( reason_text, sizeof(reason_text), "restart safe requested"); + service->disable_check_dependency = false; + service->disable_skip_dependent = true; + } else + { + snprintf( reason_text, sizeof(reason_text), "restart requested"); + } + + error = sm_service_fsm_event_handler( service->name, event, NULL, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service->name ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + + +// **************************************************************************** +// Service API - Audit +// =================== +SmErrorT sm_service_api_audit( char service_name[] ) +{ + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_AUDIT, NULL, + "forced audit" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform audit on service (%s), error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Initialize +// ======================== +SmErrorT sm_service_api_initialize( void ) +{ + SmErrorT error; + + error = sm_service_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_dependency_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service dependencies, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_engine_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to intialize service engine, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_fsm_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service fsm, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_fsm_register_callback( sm_service_api_service_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for service fsm state changes, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service API - Finalize +// ====================== +SmErrorT sm_service_api_finalize( void ) +{ + SmErrorT error; + + error = sm_service_fsm_deregister_callback( sm_service_api_service_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for service fsm state changes, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_fsm_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service fsm, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_engine_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service engine, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_dependency_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service dependency, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service table, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_api.h b/service-mgmt/sm-1.0.0/src/sm_service_api.h new file mode 100644 index 00000000..b05587ac --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_api.h @@ -0,0 +1,90 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_API_H__ +#define __SM_SERVICE_API_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmServiceApiCallbackT) (char service_name[], + SmServiceStateT state, SmServiceStatusT status, + SmServiceConditionT condition); + +// **************************************************************************** +// Service API - Register Callback +// =============================== +extern SmErrorT sm_service_api_register_callback( SmServiceApiCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Deregister Callback +// ================================= +extern SmErrorT sm_service_api_deregister_callback( SmServiceApiCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Abort Actions +// =========================== +extern SmErrorT sm_service_api_abort_actions( void ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Go-Active +// ======================= +extern SmErrorT sm_service_api_go_active( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Go-Standby +// ======================== +extern SmErrorT sm_service_api_go_standby( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Disable +// ===================== +extern SmErrorT sm_service_api_disable( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Recover +// ===================== +extern SmErrorT sm_service_api_recover( char service_name[], + bool clear_fatal_condition ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Restart +// ===================== +extern SmErrorT sm_service_api_restart( char service_name[], int flag ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Audit +// =================== +extern SmErrorT sm_service_api_audit( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Initialize +// ======================== +extern SmErrorT sm_service_api_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service API - Finalize +// ====================== +extern SmErrorT sm_service_api_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_API_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_audit.c b/service-mgmt/sm-1.0.0/src/sm_service_audit.c new file mode 100644 index 00000000..3bcf6295 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_audit.c @@ -0,0 +1,594 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_audit.h" + +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_process_death.h" +#include "sm_timer.h" +#include "sm_service_fsm.h" +#include "sm_service_action.h" +#include "sm_service_go_active.h" + +// **************************************************************************** +// Service Audit - Result Handler +// ============================== +static SmErrorT service_audit_result_handler( SmServiceT* service, + SmServiceActionT action_running, SmServiceActionResultT action_result, + SmServiceStateT service_state, SmServiceStatusT service_status, + SmServiceConditionT service_condition, const char reason_text[] ) +{ + bool retries_exhausted = true; + int max_failure_retries; + int max_timeout_retries; + int max_total_retries; + SmErrorT error; + + if( SM_SERVICE_ACTION_RESULT_SUCCESS == action_result ) + { + DPRINTFD( "Action (%s) of service (%s) completed with success.", + sm_service_action_str( action_running ), service->name ); + goto REPORT; + } + + error = sm_service_action_max_retries( service->name, action_running, + &max_failure_retries, + &max_timeout_retries, + &max_total_retries ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get max retries for action (%s) of service (%s), " + "error=%s.", sm_service_action_str( action_running ), + service->name, sm_error_str( error ) ); + goto REPORT; + } + + if( SM_SERVICE_ACTION_RESULT_FAILED == action_result ) + { + retries_exhausted = + (( max_failure_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + + } else if( SM_SERVICE_ACTION_RESULT_TIMEOUT == action_result ) { + retries_exhausted = + (( max_timeout_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + } + + if( retries_exhausted ) + { + DPRINTFI( "Max retires met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + goto REPORT; + } else { + DPRINTFI( "Max retires not met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + + if( SM_SERVICE_ACTION_AUDIT_ENABLED == action_running ) + { + error = sm_service_audit_enabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit-enabled service (%s), error=%s.", + service->name, sm_error_str( error ) ); + goto REPORT; + } + } else { + error = sm_service_audit_disabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit-disabled service (%s), error=%s.", + service->name, sm_error_str( error ) ); + goto REPORT; + } + } + } + + return( SM_OKAY ); + +REPORT: + service->action_attempts = 0; + + error = sm_service_fsm_action_complete_handler( service->name, + action_running, action_result, service_state, + service_status, service_condition, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service (%s) fsm action complete, " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Timeout +// ======================= +static bool sm_service_audit_timeout( SmTimerIdT timer_id, int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( false ); + } + + if(( SM_SERVICE_ACTION_AUDIT_ENABLED != service->action_running )&& + ( SM_SERVICE_ACTION_AUDIT_DISABLED != service->action_running )) + { + // timer will be deregistered after exit + service->action_timer_id = SM_TIMER_ID_INVALID; + DPRINTFE( "Service (%s) not running audit-enabled or audit-disabled " + "action.", service->name ); + return( false ); + } + + action_running = service->action_running; + + error = sm_service_action_result( SM_SERVICE_ACTION_PLUGIN_TIMEOUT, + service->name, service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) defaulting " + "to failed, exit_code=%i, error=%s.", service->name, + SM_SERVICE_ACTION_PLUGIN_TIMEOUT, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + + DPRINTFI( "Action (%s) timeout with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, SM_SERVICE_ACTION_PLUGIN_TIMEOUT ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_audit_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle go-active result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Complete +// ======================== +static void sm_service_audit_complete( pid_t pid, int exit_code, + int64_t user_data ) +{ + bool action_exists; + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + if( SM_PROCESS_FAILED == exit_code ) + { + exit_code = SM_SERVICE_ACTION_PLUGIN_FAILURE; + } + + service = sm_service_table_read_by_action_pid( (int) pid ); + if( NULL == service ) + { + DPRINTFE( "Failed to query service based on pid (%i), error=%s.", + (int) pid, sm_error_str(SM_NOT_FOUND) ); + return; + } + + if(( SM_SERVICE_ACTION_AUDIT_ENABLED != service->action_running )&& + ( SM_SERVICE_ACTION_AUDIT_DISABLED != service->action_running )) + { + DPRINTFE( "Service (%s) not running action (%s or %s).", service->name, + sm_service_action_str( SM_SERVICE_ACTION_AUDIT_ENABLED ), + sm_service_action_str( SM_SERVICE_ACTION_AUDIT_DISABLED ) ); + return; + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY == error ) + { + DPRINTFD( "Timer stopped for action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + } else { + DPRINTFE( "Failed to stop timer for action (%s) of " + "service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + } + + action_running = service->action_running; + + if( SM_SERVICE_ACTION_PLUGIN_FORCE_SUCCESS == exit_code ) + { + DPRINTFI( "Action (%s) for service (%s) force-passed.", + sm_service_action_str( action_running ), service->name ); + + action_result = SM_SERVICE_ACTION_RESULT_SUCCESS; + + if(( SM_SERVICE_STATE_INITIAL == service->state ) || + ( SM_SERVICE_STATE_UNKNOWN == service->state )) + { + service_state = SM_SERVICE_STATE_DISABLED; + + } else if( SM_SERVICE_STATE_ENABLED_GO_STANDBY == service->state ) { + service_state = SM_SERVICE_STATE_ENABLED_ACTIVE; + + } else { + service_state = service->state; + } + + service_status = SM_SERVICE_STATUS_NONE; + service_condition = SM_SERVICE_CONDITION_NONE; + + } else { + error = sm_service_action_result( exit_code, service->name, + service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) " + "defaulting to failed, exit_code=%i, error=%s.", + service->name, exit_code, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + } + + DPRINTFD( "Action (%s) completed with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, exit_code ); + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + if(( SM_SERVICE_STATE_UNKNOWN == service_state )&& + ( SM_SERVICE_ACTION_RESULT_SUCCESS == action_result )) + { + error = sm_service_go_active_exists( service, &action_exists ); + if( SM_OKAY == error ) + { + if( action_exists ) + { + service_state = SM_SERVICE_STATE_ENABLED_STANDBY; + } else { + service_state = SM_SERVICE_STATE_ENABLED_ACTIVE; + } + + DPRINTFD( "Action (%s) state (%s) result modified for service " + "(%s).", sm_service_action_str( action_running ), + sm_service_state_str( service_state ), service->name ); + } else { + DPRINTFE( "Failed to determine if go-active action for " + "service (%s) exists, error=%s.", service->name, + sm_error_str( error ) ); + abort(); + } + } + + error = service_audit_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle audit result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit +// ============= +static SmErrorT sm_service_audit( SmServiceT* service, SmServiceActionT action ) +{ + char timer_name[80] = ""; + int process_id = -1; + int timeout = 0; + SmTimerIdT timer_id = SM_TIMER_ID_INVALID; + SmErrorT error; + + if( action == service->action_running ) + { + DPRINTFI( "Service (%s) already running %s action.", service->name, + sm_service_action_str( service->action_running ) ); + return( SM_OKAY ); + } + + // Run action. + error = sm_service_action_run( service->name, + service->instance_name, + service->instance_params, + action, &process_id, &timeout ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to run %s action for service (%s), " + "error=%s.", sm_service_action_str( action ), + service->name, sm_error_str( error ) ); + return( error ); + } + + // Register for action script exit notification. + error = sm_process_death_register( process_id, true, + sm_service_audit_complete, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for %s action completion for " + "service (%s), error=%s.", sm_service_action_str( action ), + service->name, sm_error_str( error ) ); + abort(); + } + + // Create timer for action completion. + snprintf( timer_name, sizeof(timer_name), "%s %s action", + service->name, sm_service_action_str( action ) ); + + error = sm_timer_register( timer_name, timeout, sm_service_audit_timeout, + service->id, &timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create a timer for action (%s) for service (%s), " + "error=%s.", sm_service_action_str( action ), + service->name, sm_error_str( error ) ); + abort(); + } + + // Write to database that we are running an action. + service->action_running = action; + service->action_pid = process_id; + service->action_timer_id = timer_id; + service->action_attempts += 1; + + DPRINTFD( "Started %s action (%i) for service (%s).", + sm_service_action_str( action ), process_id, service->name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Abort +// ===================== +static SmErrorT sm_service_audit_abort( SmServiceT* service ) +{ + SmErrorT error; + + DPRINTFI( "Aborting action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Cancel timer for action (%s) of service (%s) failed, " + "error=%s.", service->name, + sm_service_action_str( service->action_running ), + sm_error_str( error ) ); + return( error ); + } + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + service->action_attempts = 0; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Enabled +// ======================= +SmErrorT sm_service_audit_enabled( SmServiceT* service ) +{ + return( sm_service_audit( service, SM_SERVICE_ACTION_AUDIT_ENABLED ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled +// ======================== +SmErrorT sm_service_audit_disabled( SmServiceT* service ) +{ + return( sm_service_audit( service, SM_SERVICE_ACTION_AUDIT_DISABLED ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Enabled Abort +// ============================= +SmErrorT sm_service_audit_enabled_abort( SmServiceT* service ) +{ + return( sm_service_audit_abort( service ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled Abort +// ============================== +SmErrorT sm_service_audit_disabled_abort( SmServiceT* service ) +{ + return( sm_service_audit_abort( service ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Enabled Interval +// ================================ +SmErrorT sm_service_audit_enabled_interval( SmServiceT* service, int* interval ) +{ + return( sm_service_action_interval( service->name, + SM_SERVICE_ACTION_AUDIT_ENABLED, + interval ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled Interval +// ================================ +SmErrorT sm_service_audit_disabled_interval( SmServiceT* service, int* interval ) +{ + return( sm_service_action_interval( service->name, + SM_SERVICE_ACTION_AUDIT_DISABLED, + interval ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Enabled Exists +// ============================== +SmErrorT sm_service_audit_enabled_exists( SmServiceT* service, bool* exists ) +{ + SmErrorT error; + + error = sm_service_action_exist( service->name, + SM_SERVICE_ACTION_AUDIT_ENABLED ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to determine if action (%s) exists for " + "service (%s), error=%s.", + sm_service_action_str( SM_SERVICE_ACTION_AUDIT_ENABLED ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_OKAY == error ) + { + *exists = true; + } else { + *exists = false; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled Exists +// =============================== +SmErrorT sm_service_audit_disabled_exists( SmServiceT* service, bool* exists ) +{ + SmErrorT error; + + error = sm_service_action_exist( service->name, + SM_SERVICE_ACTION_AUDIT_DISABLED ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to determine if action (%s) exists for " + "service (%s), error=%s.", + sm_service_action_str( SM_SERVICE_ACTION_AUDIT_DISABLED ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_OKAY == error ) + { + *exists = true; + } else { + *exists = false; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Initialized +// =========================== +SmErrorT sm_service_audit_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Finalize +// ======================== +SmErrorT sm_service_audit_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_audit.h b/service-mgmt/sm-1.0.0/src/sm_service_audit.h new file mode 100644 index 00000000..cc7000af --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_audit.h @@ -0,0 +1,96 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_AUDIT_H__ +#define __SM_SERVICE_AUDIT_H__ + +#include "sm_types.h" +#include "sm_service_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Audit - Enabled +// ======================= +extern SmErrorT sm_service_audit_enabled( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled +// ======================== +extern SmErrorT sm_service_audit_disabled( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Enabled Abort +// ============================= +extern SmErrorT sm_service_audit_enabled_abort( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled Abort +// ============================== +extern SmErrorT sm_service_audit_disabled_abort( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Enabled Abort +// ============================= +extern SmErrorT sm_service_audit_enabled_abort( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled Abort +// ============================== +extern SmErrorT sm_service_audit_disabled_abort( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Enabled Interval +// ================================ +extern SmErrorT sm_service_audit_enabled_interval( SmServiceT* service, + int* interval ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled Interval +// ================================= +extern SmErrorT sm_service_audit_disabled_interval( SmServiceT* service, + int* interval ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Enabled Exists +// ============================== +extern SmErrorT sm_service_audit_enabled_exists( SmServiceT* service, + bool* exists ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Disabled Exists +// =============================== +extern SmErrorT sm_service_audit_disabled_exists( SmServiceT* service, + bool* exists ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Initialized +// =========================== +extern SmErrorT sm_service_audit_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Audit - Finalize +// ======================== +extern SmErrorT sm_service_audit_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_AUDIT_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_dependency.c b/service-mgmt/sm-1.0.0/src/sm_service_dependency.c new file mode 100644 index 00000000..698e5474 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_dependency.c @@ -0,0 +1,510 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_dependency.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_service_table.h" +#include "sm_service_dependency_table.h" + +// **************************************************************************** +// Service Dependency - Dependent State Compare +// ============================================ +static void sm_service_dependency_dependent_state_compare( + void* user_data[], SmServiceDependencyT* service_dependency ) +{ + SmServiceT* service = (SmServiceT*) user_data[0]; + bool* met = (bool*) user_data[1]; + SmCompareOperatorT compare_operator = *(SmCompareOperatorT*) user_data[2]; + bool* at_least_one = (bool*) user_data[3]; + SmServiceT* dependent_service; + SmServiceStateT state_result; + + if( '\0' == service_dependency->dependent[0] ) + { + DPRINTFI( "Service (%s) has no dependencies.", service->name ); + return; + } + + dependent_service = sm_service_table_read( service_dependency->dependent ); + if( NULL == dependent_service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_dependency->service_name, + sm_error_str(SM_NOT_FOUND) ); + return; + } + + *at_least_one = true; + + state_result = sm_service_state_lesser( service_dependency->dependent_state, + dependent_service->state ); + + if( SM_COMPARE_OPERATOR_LE == compare_operator ) + { + if(( service_dependency->dependent_state == dependent_service->state )|| + ( state_result == service_dependency->dependent_state )) + { + DPRINTFD( "Dependency (%s) for service (%s) was met, " + "dependent_state=%s, dependency_state=%s, op=le.", + service_dependency->dependent, service->name, + sm_service_state_str(dependent_service->state), + sm_service_state_str(service_dependency->dependent_state) ); + } else { + DPRINTFD( "Dependency (%s) for service (%s) was not met, " + "dependent_state=%s, dependency_state=%s, op=le.", + service_dependency->dependent, service->name, + sm_service_state_str(dependent_service->state), + sm_service_state_str(service_dependency->dependent_state) ); + *met = false; + } + } else if( SM_COMPARE_OPERATOR_GE == compare_operator ) + { + if(( service_dependency->dependent_state == dependent_service->state )|| + ( state_result == dependent_service->state )) + { + DPRINTFD( "Dependency (%s) for service (%s) was met, " + "dependent_state=%s, dependency_state=%s, op=ge.", + service_dependency->dependent, service->name, + sm_service_state_str(dependent_service->state), + sm_service_state_str(service_dependency->dependent_state) ); + } else { + DPRINTFD( "Dependency (%s) for service (%s) was not met, " + "dependent_state=%s, dependency_state=%s, op=ge.", + service_dependency->dependent, service->name, + sm_service_state_str(dependent_service->state), + sm_service_state_str(service_dependency->dependent_state) ); + *met = false; + } + } else { + *met = false; + DPRINTFE( "Unknown compare operator (%i).", compare_operator ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Go-Active Met +// ================================== +SmErrorT sm_service_dependency_go_active_met( SmServiceT* service, bool* met ) +{ + bool at_least_one = false; + bool dependency_met = true; + SmCompareOperatorT compare_operator = SM_COMPARE_OPERATOR_LE; + void* user_data[] = {service, &dependency_met, &compare_operator, + &at_least_one}; + + *met = false; + + sm_service_dependency_table_foreach( SM_SERVICE_DEPENDENCY_TYPE_ACTION, + service->name, SM_SERVICE_STATE_NA, SM_SERVICE_ACTION_GO_ACTIVE, + user_data, sm_service_dependency_dependent_state_compare ); + + if( at_least_one ) + { + *met = dependency_met; + } else { + *met = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Go-Standby Met +// =================================== +SmErrorT sm_service_dependency_go_standby_met( SmServiceT* service, bool* met ) +{ + bool at_least_one = false; + bool dependency_met = true; + SmCompareOperatorT compare_operator = SM_COMPARE_OPERATOR_GE; + void* user_data[] = {service, &dependency_met, &compare_operator, + &at_least_one}; + + *met = false; + + sm_service_dependency_table_foreach( SM_SERVICE_DEPENDENCY_TYPE_ACTION, + service->name, SM_SERVICE_STATE_NA, SM_SERVICE_ACTION_GO_STANDBY, + user_data, sm_service_dependency_dependent_state_compare ); + + if( at_least_one ) + { + *met = dependency_met; + } else { + *met = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Enable Met +// =============================== +SmErrorT sm_service_dependency_enable_met( SmServiceT* service, bool* met ) +{ + bool at_least_one = false; + bool dependency_met = true; + SmCompareOperatorT compare_operator = SM_COMPARE_OPERATOR_LE; + void* user_data[] = {service, &dependency_met, &compare_operator, + &at_least_one}; + + *met = false; + sm_service_dependency_table_foreach( SM_SERVICE_DEPENDENCY_TYPE_ACTION, + service->name, SM_SERVICE_STATE_NA, SM_SERVICE_ACTION_ENABLE, + user_data, sm_service_dependency_dependent_state_compare ); + + if( at_least_one ) + { + *met = dependency_met; + } else { + *met = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Disable Met +// ================================ +SmErrorT sm_service_dependency_disable_met( SmServiceT* service, bool* met ) +{ + bool at_least_one = false; + bool dependency_met = true; + SmCompareOperatorT compare_operator = SM_COMPARE_OPERATOR_GE; + void* user_data[] = {service, &dependency_met, &compare_operator, + &at_least_one}; + + *met = false; + sm_service_dependency_table_foreach( SM_SERVICE_DEPENDENCY_TYPE_ACTION, + service->name, SM_SERVICE_STATE_NA, SM_SERVICE_ACTION_DISABLE, + user_data, sm_service_dependency_dependent_state_compare ); + + if( at_least_one ) + { + *met = dependency_met; + } else { + *met = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Enabled Active State Met +// ============================================= +SmErrorT sm_service_dependency_enabled_active_state_met( SmServiceT* service, + bool* met ) +{ + bool at_least_one = false; + bool dependency_met = true; + SmCompareOperatorT compare_operator = SM_COMPARE_OPERATOR_LE; + void* user_data[] = {service, &dependency_met, &compare_operator, + &at_least_one}; + + *met = false; + + sm_service_dependency_table_foreach( SM_SERVICE_DEPENDENCY_TYPE_STATE, + service->name, SM_SERVICE_STATE_ENABLED_ACTIVE, SM_SERVICE_ACTION_NA, + user_data, sm_service_dependency_dependent_state_compare ); + + if( at_least_one ) + { + *met = dependency_met; + } else { + *met = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Enabled Standby State Met +// ============================================== +SmErrorT sm_service_dependency_enabled_standby_state_met( SmServiceT* service, + bool* met ) +{ + bool at_least_one = false; + bool dependency_met = true; + SmCompareOperatorT compare_operator = SM_COMPARE_OPERATOR_LE; + void* user_data[] = {service, &dependency_met, &compare_operator, + &at_least_one}; + + *met = false; + + sm_service_dependency_table_foreach( SM_SERVICE_DEPENDENCY_TYPE_STATE, + service->name, SM_SERVICE_STATE_ENABLED_STANDBY, SM_SERVICE_ACTION_NA, + user_data, sm_service_dependency_dependent_state_compare ); + + + if( at_least_one ) + { + *met = dependency_met; + } else { + *met = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Dependent Action Require State +// =================================================== +static void sm_service_dependency_dependent_action_require_state( + void* user_data[], SmServiceDependencyT* service_dependency ) +{ + bool state_match = false; + SmServiceT* service = (SmServiceT*) user_data[0]; + SmServiceStateT required_state = *(SmServiceStateT*) user_data[1]; + bool* require_state = (bool*) user_data[2]; + bool* at_least_one = (bool*) user_data[3]; + SmServiceT* dependent_service; + + if( '\0' == service_dependency->dependent[0] ) + { + DPRINTFI( "Service (%s) has no dependencies.", service->name ); + return; + } + + dependent_service = sm_service_table_read( service_dependency->service_name ); + if( NULL == dependent_service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_dependency->service_name, + sm_error_str(SM_NOT_FOUND) ); + return; + } + + *at_least_one = true; + + switch( service_dependency->action ) + { + case SM_SERVICE_ACTION_ENABLE: + if( SM_SERVICE_STATE_ENABLING == dependent_service->state ) + { + state_match = true; + } + break; + + case SM_SERVICE_ACTION_DISABLE: + if( SM_SERVICE_STATE_DISABLING == dependent_service->state && + !dependent_service->disable_skip_dependent) + { + state_match = true; + } + break; + + case SM_SERVICE_ACTION_GO_ACTIVE: + if( SM_SERVICE_STATE_ENABLED_GO_ACTIVE == dependent_service->state ) + { + state_match = true; + } + break; + + case SM_SERVICE_ACTION_GO_STANDBY: + if( SM_SERVICE_STATE_ENABLED_GO_STANDBY == dependent_service->state ) + { + state_match = true; + } + break; + + case SM_SERVICE_ACTION_AUDIT_ENABLED: + case SM_SERVICE_ACTION_AUDIT_DISABLED: + // Ignore. + break; + + default: + DPRINTFE( "Unknown service (%s) dependency action(%s).", + service_dependency->service_name, + sm_service_action_str(service_dependency->action) ); + return; + } + + if( state_match ) + { + DPRINTFD( "Dependency (%s) for service (%s) requires state (%s), " + "dependent_state=%s, dependency_state=%s.", + service->name, service_dependency->service_name, + sm_service_state_str(required_state), + sm_service_state_str(dependent_service->state), + sm_service_state_str(service_dependency->dependent_state) ); + + *require_state = true; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - State Require State +// ======================================== +static void sm_service_dependency_dependent_state_require_state( + void* user_data[], SmServiceDependencyT* service_dependency ) +{ + SmServiceT* service = (SmServiceT*) user_data[0]; + SmServiceStateT required_state = *(SmServiceStateT*) user_data[1]; + bool* require_state = (bool*) user_data[2]; + bool* at_least_one = (bool*) user_data[3]; + SmServiceT* dependent_service; + + if( '\0' == service_dependency->dependent[0] ) + { + DPRINTFI( "Service (%s) has no dependencies.", service->name ); + return; + } + + dependent_service = sm_service_table_read( service_dependency->service_name ); + if( NULL == dependent_service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_dependency->service_name, + sm_error_str(SM_NOT_FOUND) ); + return; + } + + *at_least_one = true; + + if( service_dependency->state == dependent_service->state ) + { + if( service_dependency->dependent_state != service->state ) + { + DPRINTFD( "Dependency (%s) for service (%s) requires state (%s), " + "dependent_state=%s, dependency_state=%s.", + service->name, service_dependency->service_name, + sm_service_state_str(required_state), + sm_service_state_str(dependent_service->state), + sm_service_state_str(service_dependency->dependent_state) ); + + *require_state = true; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Dependents Require Disable +// =============================================== +SmErrorT sm_service_dependency_dependents_require_disable( SmServiceT* service, + bool* disable_required ) +{ + bool at_least_one = false; + bool require = false; + SmServiceStateT required_state = SM_SERVICE_STATE_DISABLED; + void* user_data[] = {service, &required_state, &require, &at_least_one}; + + *disable_required = false; + + if( SM_SERVICE_ACTION_NONE != service->action_running ) + { + DPRINTFD( "Service (%s) running an action.", service->name ); + return( SM_OKAY ); + } + + sm_service_dependency_table_foreach_dependent( + SM_SERVICE_DEPENDENCY_TYPE_ACTION, service->name, required_state, + user_data, sm_service_dependency_dependent_action_require_state ); + + if( at_least_one ) + { + *disable_required = require; + } else { + *disable_required = false; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Dependents Require Notification +// ==================================================== +SmErrorT sm_service_dependency_dependents_require_notification( + SmServiceT* service, bool* notification ) +{ + bool at_least_one = false; + bool require = false; + SmServiceStateT required_state = service->state; + void* user_data[] = {service, &required_state, &require, &at_least_one}; + + *notification = false; + + if( SM_SERVICE_ACTION_NONE != service->action_running ) + { + DPRINTFD( "Service (%s) running an action.", service->name ); + return( SM_OKAY ); + } + + sm_service_dependency_table_foreach_dependent( + SM_SERVICE_DEPENDENCY_TYPE_ACTION, service->name, required_state, + user_data, sm_service_dependency_dependent_action_require_state ); + + if( at_least_one ) + { + *notification = require; + } else { + *notification = false; + } + + at_least_one = false; + + sm_service_dependency_table_foreach_dependent( + SM_SERVICE_DEPENDENCY_TYPE_STATE, service->name, required_state, + user_data, sm_service_dependency_dependent_state_require_state ); + + if( at_least_one ) + { + *notification |= require; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Initialize +// =============================== +SmErrorT sm_service_dependency_initialize( void ) +{ + SmErrorT error; + + error = sm_service_dependency_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed initialize service dependency table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Finalize +// ============================= +SmErrorT sm_service_dependency_finalize( void ) +{ + SmErrorT error; + + error = sm_service_dependency_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed finalize service dependency table, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_dependency.h b/service-mgmt/sm-1.0.0/src/sm_service_dependency.h new file mode 100644 index 00000000..df2c3309 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_dependency.h @@ -0,0 +1,88 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DEPENDENCY_H__ +#define __SM_SERVICE_DEPENDENCY_H__ + +#include "sm_types.h" +#include "sm_service_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Dependency - Go-Active Met +// ================================== +extern SmErrorT sm_service_dependency_go_active_met( SmServiceT* service, + bool* met ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Go-Standby Met +// =================================== +extern SmErrorT sm_service_dependency_go_standby_met( SmServiceT* service, + bool* met ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Enable Met +// =============================== +extern SmErrorT sm_service_dependency_enable_met( SmServiceT* service, + bool* met ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Disable Met +// ================================ +extern SmErrorT sm_service_dependency_disable_met( SmServiceT* service, + bool* met ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Enabled Active State Met +// ============================================= +extern SmErrorT sm_service_dependency_enabled_active_state_met( + SmServiceT* service, bool* met ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Enabled Standby State Met +// ============================================== +extern SmErrorT sm_service_dependency_enabled_standby_state_met( + SmServiceT* service, bool* met ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Dependents Require Disable +// =============================================== +extern SmErrorT sm_service_dependency_dependents_require_disable( + SmServiceT* service, bool* disable_required ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Dependents Require Notification +// ==================================================== +extern SmErrorT sm_service_dependency_dependents_require_notification( + SmServiceT* service, bool* notification ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Initialize +// =============================== +extern SmErrorT sm_service_dependency_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency - Finalize +// ============================= +extern SmErrorT sm_service_dependency_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DEPENDENCY_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_dependency_table.c b/service-mgmt/sm-1.0.0/src/sm_service_dependency_table.c new file mode 100644 index 00000000..71237e3d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_dependency_table.c @@ -0,0 +1,262 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_dependency_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_services.h" +#include "sm_db_service_dependency.h" + +static SmListT* _service_dependency = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Dependency Table - Read +// =============================== +SmServiceDependencyT* sm_service_dependency_table_read( + SmServiceDependencyTypeT type, char service_name[], SmServiceStateT state, + SmServiceActionT action, char dependent[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDependencyT* service_dependency; + + SM_LIST_FOREACH( _service_dependency, entry, entry_data ) + { + service_dependency = (SmServiceDependencyT*) entry_data; + + if(( type == service_dependency->type )&& + ( 0 == strcmp( service_name, service_dependency->service_name ) )&& + ( state == service_dependency->state )&& + ( action == service_dependency->action )&& + ( 0 == strcmp( dependent, service_dependency->dependent ) )) + { + return( service_dependency ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - For Each +// =================================== +void sm_service_dependency_table_foreach( SmServiceDependencyTypeT type, + char service_name[], SmServiceStateT state, SmServiceActionT action, + void* user_data[], SmServiceDependencyTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDependencyT* service_dependency; + + SM_LIST_FOREACH( _service_dependency, entry, entry_data ) + { + service_dependency = (SmServiceDependencyT*) entry_data; + + if(( type == service_dependency->type )&& + ( 0 == strcmp( service_name, service_dependency->service_name ) )&& + ( state == service_dependency->state )&& + ( action == service_dependency->action )) + { + callback( user_data, service_dependency ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - For Each Dependent +// ============================================= +void sm_service_dependency_table_foreach_dependent( + SmServiceDependencyTypeT type, char dependent[], + SmServiceStateT dependent_state, void* user_data[], + SmServiceDependencyTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDependencyT* service_dependency; + + SM_LIST_FOREACH( _service_dependency, entry, entry_data ) + { + service_dependency = (SmServiceDependencyT*) entry_data; + + if(( type == service_dependency->type )&& + ( 0 == strcmp( dependent, service_dependency->dependent ) )&& + ( dependent_state == service_dependency->dependent_state )) + { + callback( user_data, service_dependency ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - Add +// ============================== +static SmErrorT sm_service_dependency_table_add( void* user_data[], + void* record ) +{ + SmDbServiceT db_service; + SmDbServiceT db_dependent_service; + SmServiceDependencyT* service_dependency; + SmDbServiceDependencyT* db_service_dependency; + SmErrorT error; + + db_service_dependency = (SmDbServiceDependencyT*) record; + + error = sm_db_services_read( _sm_db_handle, + db_service_dependency->service_name, + &db_service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + db_service_dependency->service_name, sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_db_services_read( _sm_db_handle, + db_service_dependency->dependent, + &db_dependent_service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read dependent service (%s), error=%s.", + db_service_dependency->service_name, sm_error_str( error ) ); + return( SM_FAILED ); + } + + if( !(db_service.provisioned) || (!db_dependent_service.provisioned) ) + { + return( SM_OKAY ); + } + + service_dependency = sm_service_dependency_table_read( + db_service_dependency->type, + db_service_dependency->service_name, + db_service_dependency->state, + db_service_dependency->action, + db_service_dependency->dependent ); + if( NULL == service_dependency ) + { + service_dependency + = (SmServiceDependencyT*) malloc( sizeof(SmServiceDependencyT) ); + if( NULL == service_dependency ) + { + DPRINTFE( "Failed to allocate service dependency table entry." ); + return( SM_FAILED ); + } + + memset( service_dependency, 0, sizeof(SmServiceDependencyT) ); + + service_dependency->type = db_service_dependency->type; + snprintf( service_dependency->service_name, + sizeof(service_dependency->service_name), + "%s", db_service_dependency->service_name ); + + service_dependency->state = db_service_dependency->state; + service_dependency->action = db_service_dependency->action; + snprintf( service_dependency->dependent, + sizeof(service_dependency->dependent), + "%s", db_service_dependency->dependent ); + service_dependency->dependent_state + = db_service_dependency->dependent_state; + + SM_LIST_PREPEND( _service_dependency, + (SmListEntryDataPtrT) service_dependency ); + + } else { + service_dependency->dependent_state + = db_service_dependency->dependent_state; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - Load +// =============================== +SmErrorT sm_service_dependency_table_load( void ) +{ + SmDbServiceDependencyT service_dependency; + SmErrorT error; + + error = sm_db_foreach( SM_DATABASE_NAME, SM_SERVICE_DEPENDENCY_TABLE_NAME, + NULL, &service_dependency, + sm_db_service_dependency_convert, + sm_service_dependency_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service dependencies in database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - Initialize +// ===================================== +SmErrorT sm_service_dependency_table_initialize( void ) +{ + SmErrorT error; + + _service_dependency = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_dependency_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service dependencies from database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - Finalize +// =================================== +SmErrorT sm_service_dependency_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_dependency ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_dependency_table.h b/service-mgmt/sm-1.0.0/src/sm_service_dependency_table.h new file mode 100644 index 00000000..e5a5189f --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_dependency_table.h @@ -0,0 +1,78 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DEPENDENCY_TABLE_H__ +#define __SM_SERVICE_DEPENDENCY_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + SmServiceDependencyTypeT type; + char service_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceStateT state; + SmServiceActionT action; + char dependent[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceStateT dependent_state; +} SmServiceDependencyT; + +typedef void (*SmServiceDependencyTableForEachCallbackT) + (void* user_data[], SmServiceDependencyT* service_dependency); + +// **************************************************************************** +// Service Dependency Table - Read +// =============================== +extern SmServiceDependencyT* sm_service_dependency_table_read( + SmServiceDependencyTypeT type, char service_name[], SmServiceStateT state, + SmServiceActionT action, char dependent[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - For Each +// =================================== +extern void sm_service_dependency_table_foreach( SmServiceDependencyTypeT type, + char service_name[], SmServiceStateT state, SmServiceActionT action, + void* user_data[], SmServiceDependencyTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - For Each Dependent +// ============================================= +extern void sm_service_dependency_table_foreach_dependent( + SmServiceDependencyTypeT type, char dependent[], + SmServiceStateT dependent_state, void* user_data[], + SmServiceDependencyTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - Load +// =============================== +extern SmErrorT sm_service_dependency_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - Initialize +// ===================================== +extern SmErrorT sm_service_dependency_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Dependency Table - Finalize +// =================================== +extern SmErrorT sm_service_dependency_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DEPENDENCY_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_disable.c b/service-mgmt/sm-1.0.0/src/sm_service_disable.c new file mode 100644 index 00000000..58882533 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_disable.c @@ -0,0 +1,471 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_disable.h" + +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_process_death.h" +#include "sm_service_dependency.h" +#include "sm_service_fsm.h" +#include "sm_service_action.h" + +// **************************************************************************** +// Service Disable - Result Handler +// ================================ +static SmErrorT service_disable_result_handler( SmServiceT* service, + SmServiceActionT action_running, SmServiceActionResultT action_result, + SmServiceStateT service_state, SmServiceStatusT service_status, + SmServiceConditionT service_condition, const char reason_text[] ) +{ + bool retries_exhausted = true; + int max_failure_retries; + int max_timeout_retries; + int max_total_retries; + SmErrorT error; + + if( SM_SERVICE_ACTION_RESULT_SUCCESS == action_result ) + { + DPRINTFD( "Action (%s) of service (%s) completed with success.", + sm_service_action_str( action_running ), service->name ); + goto REPORT; + } + + error = sm_service_action_max_retries( service->name, action_running, + &max_failure_retries, + &max_timeout_retries, + &max_total_retries ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get max retries for action (%s) of service (%s), " + "error=%s.", sm_service_action_str( action_running ), + service->name, sm_error_str( error ) ); + goto REPORT; + } + + if( SM_SERVICE_ACTION_RESULT_FAILED == action_result ) + { + retries_exhausted = + (( max_failure_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + + } else if( SM_SERVICE_ACTION_RESULT_TIMEOUT == action_result ) { + retries_exhausted = + (( max_timeout_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + } + + if( retries_exhausted ) + { + DPRINTFI( "Max retires met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + goto REPORT; + } else { + DPRINTFI( "Max retires not met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + + error = sm_service_disable( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disable service (%s), error=%s.", + service->name, sm_error_str( error ) ); + goto REPORT; + } + } + + return( SM_OKAY ); + +REPORT: + service->action_attempts = 0; + + error = sm_service_fsm_action_complete_handler( service->name, + action_running, action_result, service_state, + service_status, service_condition, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service (%s) fsm action complete, " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Timeout +// ========================= +static bool sm_service_disable_timeout( SmTimerIdT timer_id, int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( false ); + } + + if( SM_SERVICE_ACTION_DISABLE != service->action_running ) + { + // timer will be deregistered after exit + service->action_timer_id = SM_TIMER_ID_INVALID; + DPRINTFE( "Service (%s) not running action (%s).", service->name, + sm_service_action_str( service->action_running ) ); + return( false ); + } + + action_running = service->action_running; + + error = sm_service_action_result( SM_SERVICE_ACTION_PLUGIN_TIMEOUT, + service->name, service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) defaulting " + "to failed, exit_code=%i, error=%s.", service->name, + SM_SERVICE_ACTION_PLUGIN_TIMEOUT, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + + DPRINTFI( "Action (%s) timeout with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, SM_SERVICE_ACTION_PLUGIN_TIMEOUT ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_disable_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle disable result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Complete +// ========================== +static void sm_service_disable_complete( pid_t pid, int exit_code, + int64_t user_data ) +{ + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + if( SM_PROCESS_FAILED == exit_code ) + { + exit_code = SM_SERVICE_ACTION_PLUGIN_FAILURE; + } + + service = sm_service_table_read_by_action_pid( (int) pid ); + if( NULL == service ) + { + DPRINTFE( "Failed to query service based on pid (%i), error=%s.", + (int) pid, sm_error_str(SM_NOT_FOUND) ); + return; + } + + if( SM_SERVICE_ACTION_DISABLE != service->action_running ) + { + DPRINTFE( "Service (%s) not running disable action.", service->name ); + return; + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY == error ) + { + DPRINTFD( "Timer stopped for action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + } else { + DPRINTFE( "Failed to stop timer for action (%s) of " + "service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + } + + action_running = service->action_running; + + if( SM_SERVICE_ACTION_PLUGIN_FORCE_SUCCESS == exit_code ) + { + DPRINTFI( "Action (%s) for service (%s) force-passed.", + sm_service_action_str( action_running ), service->name ); + + action_result = SM_SERVICE_ACTION_RESULT_SUCCESS; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + + } else { + error = sm_service_action_result( exit_code, service->name, + service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) " + "defaulting to failed, exit_code=%i, error=%s.", + service->name, exit_code, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + } + + DPRINTFI( "Action (%s) completed with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, exit_code ); + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_disable_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle disable result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Disable +// =============== +SmErrorT sm_service_disable( SmServiceT* service ) +{ + char timer_name[80] = ""; + int process_id = -1; + int timeout = 0; + bool dependency_met; + SmTimerIdT timer_id = SM_TIMER_ID_INVALID; + SmErrorT error; + + if( service->disable_check_dependency && !service->disable_skip_dependent ) + { + // Are disable dependencies met? + error = sm_service_dependency_disable_met( service, &dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check service (%s) dependencies, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + if( !dependency_met ) + { + DPRINTFD( "Some dependencies for service (%s) were not met.", + service->name ); + return( SM_OKAY ); + } + + DPRINTFD( "All dependencies for service (%s) were met.", + service->name ); + } else { + DPRINTFD( "Dependency check for service (%s) skipped.", + service->name ); + } + + // Run action. + error = sm_service_action_run( service->name, + service->instance_name, + service->instance_params, + SM_SERVICE_ACTION_DISABLE, + &process_id, &timeout ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to run disable action for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + // Register for action script exit notification. + error = sm_process_death_register( process_id, true, + sm_service_disable_complete, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for disable action completion for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + abort(); + } + + // Create timer for action completion. + snprintf( timer_name, sizeof(timer_name), "%s %s action", + service->name, sm_service_action_str( SM_SERVICE_ACTION_DISABLE ) ); + + error = sm_timer_register( timer_name, timeout, sm_service_disable_timeout, + service->id, &timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create a timer for action (%s) for service (%s), " + "error=%s.", sm_service_action_str( SM_SERVICE_ACTION_DISABLE ), + service->name, sm_error_str( error ) ); + abort(); + } + + // Write to database that we are running an action. + service->action_running = SM_SERVICE_ACTION_DISABLE; + service->action_pid = process_id; + service->action_timer_id = timer_id; + service->action_attempts += 1; + + DPRINTFI( "Started disable action (%i) for service (%s), flag (%d).", process_id, + service->name, service->disable_skip_dependent ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Abort +// ======================= +SmErrorT sm_service_disable_abort( SmServiceT* service ) +{ + SmErrorT error; + + DPRINTFI( "Aborting action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Cancel timer for action (%s) of service (%s) failed, " + "error=%s.", service->name, + sm_service_action_str( service->action_running ), + sm_error_str( error ) ); + return( error ); + } + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + service->action_attempts = 0; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Exists +// ======================== +SmErrorT sm_service_disable_exists( SmServiceT* service, bool* exists ) +{ + SmErrorT error; + + error = sm_service_action_exist( service->name, SM_SERVICE_ACTION_DISABLE ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to determine if action (%s) exists for service (%s), " + "error=%s.", sm_service_action_str( SM_SERVICE_ACTION_DISABLE ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_OKAY == error ) + { + *exists = true; + } else { + *exists = false; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Initialize +// ============================ +SmErrorT sm_service_disable_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Finalize +// ========================== +SmErrorT sm_service_disable_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_disable.h b/service-mgmt/sm-1.0.0/src/sm_service_disable.h new file mode 100644 index 00000000..223f8b96 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_disable.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DISABLE_H__ +#define __SM_SERVICE_DISABLE_H__ + +#include + +#include "sm_types.h" +#include "sm_service_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Disable +// =============== +extern SmErrorT sm_service_disable( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Abort +// ======================= +extern SmErrorT sm_service_disable_abort( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Exists +// ======================== +extern SmErrorT sm_service_disable_exists( SmServiceT* service, bool* exists ); +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Initialize +// ============================ +extern SmErrorT sm_service_disable_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Disable - Finalize +// ========================== +extern SmErrorT sm_service_disable_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DISABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_disabled_state.c b/service-mgmt/sm-1.0.0/src/sm_service_disabled_state.c new file mode 100644 index 00000000..d8098724 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_disabled_state.c @@ -0,0 +1,338 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_disabled_state.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_service_fsm.h" +#include "sm_service_enable.h" +#include "sm_service_disable.h" +#include "sm_service_audit.h" +#include "sm_service_heartbeat_api.h" + +// **************************************************************************** +// Service Disabled State - Audit Timer +// ==================================== +static bool sm_service_disabled_state_audit_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_AUDIT, NULL, + "periodic audit" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform audit on service (%s), error=%s.", + service->name, sm_error_str( error ) ); + return( true ); + } + + DPRINTFD( "Audit on service (%s) requested.", service->name ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Entry +// ============================== +SmErrorT sm_service_disabled_state_entry( SmServiceT* service ) +{ + char timer_name[80] = ""; + int audit_interval; + SmTimerIdT audit_timer_id; + SmErrorT error; + + error = sm_service_fsm_process_failure_deregister( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for process failure for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + } + + if( service->audit_disabled_exists ) + { + error = sm_service_audit_disabled_interval( service, &audit_interval ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get service (%s) audit interval, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + snprintf( timer_name, sizeof(timer_name), "%s disabled audit", + service->name ); + + error = sm_timer_register( timer_name, audit_interval, + sm_service_disabled_state_audit_timer, + service->id, &audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create audit-disabled timer for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + service->audit_timer_id = audit_timer_id; + + } else { + DPRINTFI( "No audit for service (%s) exists.", service->name ); + } + + service->transition_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Exit +// ============================= +SmErrorT sm_service_disabled_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + if( SM_SERVICE_ACTION_DISABLE == service->action_running ) + { + error = sm_service_disable_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + if( SM_SERVICE_ACTION_AUDIT_DISABLED == service->action_running ) + { + error = sm_service_audit_disabled_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + if( SM_TIMER_ID_INVALID != service->audit_timer_id ) + { + error = sm_timer_deregister( service->audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel audit-disabled timer, error=%s.", + sm_error_str( error ) ); + } + + service->audit_timer_id = SM_TIMER_ID_INVALID; + } + + service->disable_check_dependency = true; + service->disable_skip_dependent = false; + service->transition_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Transition +// =================================== +SmErrorT sm_service_disabled_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + SmErrorT error; + if(( SM_SERVICE_STATE_UNKNOWN == from_state )|| + ( SM_SERVICE_STATE_DISABLING == from_state )) + { + service->disable_check_dependency = true; + } + + if(service->disable_skip_dependent) + { + service->disable_check_dependency = false; + } + + if ( !service->disable_check_dependency ) + { + error = sm_service_disable( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disable service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Event Handler +// ====================================== +SmErrorT sm_service_disabled_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + SmServiceStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_ENABLE_THROTTLE: + if(( SM_SERVICE_ACTION_DISABLE != service->action_running )&& + ( service->fail_count < service->max_failures )&& + ( service->enable_action_exists )) + { + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLING_THROTTLE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_ENABLING_THROTTLE ), + service->name, sm_error_str( error ) ); + return( error ); + } + } else if(( service->fail_count >= service->max_failures )&& + ( SM_SERVICE_STATUS_FAILED != service->status )) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_RECOVERY_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "failures (%i).", service->name, + service->max_failures ); + return( SM_OKAY ); + } + break; + + case SM_SERVICE_EVENT_DISABLE_SUCCESS: + DPRINTFI( "Service (%s) disable successfully completed.", + service->name ); + break; + + case SM_SERVICE_EVENT_DISABLE_FAILED: + case SM_SERVICE_EVENT_DISABLE_TIMEOUT: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( SM_SERVICE_STATE_DISABLING ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_AUDIT: + error = sm_service_heartbeat_api_stop_heartbeat( service->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop service (%s) heartbeat, error=%s.", + service->name, sm_error_str( error ) ); + } + + if(( SM_SERVICE_ACTION_DISABLE != service->action_running )&& + ( service->audit_disabled_exists )) + { + error = sm_service_audit_disabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_AUDIT_SUCCESS: + DPRINTFD( "Service (%s) audit success.", service->name ); + break; + + case SM_SERVICE_EVENT_AUDIT_FAILED: + DPRINTFD( "Service (%s) audit failed.", service->name ); + break; + + case SM_SERVICE_EVENT_AUDIT_TIMEOUT: + DPRINTFD( "Service (%s) audit timeout.", service->name ); + break; + + case SM_SERVICE_EVENT_AUDIT_MISMATCH: + state = *(SmServiceStateT*) + event_data[SM_SERVICE_EVENT_DATA_STATE]; + + DPRINTFI( "State mismatch for service (%s), expected=%s, " + "result=%s.", service->name, + sm_service_state_str(SM_SERVICE_STATE_DISABLED), + sm_service_state_str(state) ); + + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Initialize +// =================================== +SmErrorT sm_service_disabled_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Finalize +// ================================= +SmErrorT sm_service_disabled_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_disabled_state.h b/service-mgmt/sm-1.0.0/src/sm_service_disabled_state.h new file mode 100644 index 00000000..1f992daf --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_disabled_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DISABLED_STATE_H__ +#define __SM_SERVICE_DISABLED_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Disabled State - Entry +// ============================== +extern SmErrorT sm_service_disabled_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Exit +// ============================= +extern SmErrorT sm_service_disabled_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Transition +// =================================== +extern SmErrorT sm_service_disabled_state_transition( SmServiceT* service, + SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Event Handler +// ====================================== +extern SmErrorT sm_service_disabled_state_event_handler( + SmServiceT* service, SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Initialize +// =================================== +extern SmErrorT sm_service_disabled_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabled State - Finalize +// ================================= +extern SmErrorT sm_service_disabled_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DISABLED_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_disabling_state.c b/service-mgmt/sm-1.0.0/src/sm_service_disabling_state.c new file mode 100644 index 00000000..b9c9cab5 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_disabling_state.c @@ -0,0 +1,303 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_disabling_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_fsm.h" +#include "sm_service_disable.h" + +#define SM_SERVICE_DISABLING_TIMEOUT_IN_MS 300000 + +// **************************************************************************** +// Service Disabling State - Timeout Timer +// ======================================= +static bool sm_service_disabling_state_timeout_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_DISABLE_TIMEOUT, + NULL, "overall disabling timeout" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal overall disabling timeout to service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( true ); + } + + DPRINTFI( "Service (%s) disabling overall timeout.", service->name ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Entry +// =============================== +SmErrorT sm_service_disabling_state_entry( SmServiceT* service ) +{ + char timer_name[80] = ""; + SmTimerIdT action_state_timer_id; + SmErrorT error; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel disabling overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + snprintf( timer_name, sizeof(timer_name), "%s disabling overall timeout", + service->name ); + + error = sm_timer_register( timer_name, + SM_SERVICE_DISABLING_TIMEOUT_IN_MS, + sm_service_disabling_state_timeout_timer, + service->id, &action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create disabling overall timer for service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_state_timer_id = action_state_timer_id; + + error = sm_service_disable( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disable service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Exit +// ============================== +SmErrorT sm_service_disabling_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel disabling overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + if( SM_SERVICE_ACTION_DISABLE == service->action_running ) + { + error = sm_service_disable_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + service->action_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Transition +// ==================================== +SmErrorT sm_service_disabling_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Event Handler +// ======================================= +SmErrorT sm_service_disabling_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_ENABLE_THROTTLE: + if(( SM_SERVICE_ACTION_DISABLE != service->action_running )&& + !(( SM_SERVICE_STATUS_FAILED == service->status )&& + ( SM_SERVICE_CONDITION_FATAL_FAILURE == service->condition ))&& + ( service->enable_action_exists )) + { + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLING_THROTTLE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_ENABLING_THROTTLE ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_DISABLE: + if( service->transition_fail_count >= service->max_transition_failures ) + { + if( SM_SERVICE_CONDITION_FATAL_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_FATAL_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "transition failures (%i).", service->name, + service->max_transition_failures ); + } + } + else if( service->action_fail_count >= service->max_action_failures ) + { + if( SM_SERVICE_CONDITION_ACTION_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_ACTION_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "action failures (%i).", service->name, + service->max_action_failures ); + } + } else { + if( SM_SERVICE_ACTION_DISABLE != service->action_running ) + { + error = sm_service_disable( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disable service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + } + break; + + case SM_SERVICE_EVENT_PROCESS_FAILURE: + DPRINTFD( "Service (%s) has reported process failure " + "when it is in 'disabling' state. It is considered disable success.", + service->name ); + //allow the script to complete further cleanup when applicable. + break; + case SM_SERVICE_EVENT_DISABLE_SUCCESS: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLED ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str( SM_SERVICE_STATE_DISABLED ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_DISABLE_FAILED: + case SM_SERVICE_EVENT_DISABLE_TIMEOUT: + // Service engine will run the disable action again. + ++(service->action_fail_count); + ++(service->transition_fail_count); + + if( service->transition_fail_count >= service->max_transition_failures ) + { + if( SM_SERVICE_CONDITION_FATAL_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_FATAL_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "transition failures (%i).", service->name, + service->max_transition_failures ); + } + } + else if( service->action_fail_count >= service->max_action_failures ) + { + if( SM_SERVICE_CONDITION_ACTION_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_ACTION_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "action failures (%i).", service->name, + service->max_action_failures ); + } + } + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Initialize +// ==================================== +SmErrorT sm_service_disabling_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Finalize +// ================================== +SmErrorT sm_service_disabling_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_disabling_state.h b/service-mgmt/sm-1.0.0/src/sm_service_disabling_state.h new file mode 100644 index 00000000..b58a945c --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_disabling_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DISABLING_STATE_H__ +#define __SM_SERVICE_DISABLING_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Disabling State - Entry +// =============================== +extern SmErrorT sm_service_disabling_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Exit +// ============================== +extern SmErrorT sm_service_disabling_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Transition +// ==================================== +extern SmErrorT sm_service_disabling_state_transition( SmServiceT* service, + SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Event Handler +// ======================================= +extern SmErrorT sm_service_disabling_state_event_handler( + SmServiceT* service, SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Initialize +// ==================================== +extern SmErrorT sm_service_disabling_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Disabling State - Finalize +// ================================== +extern SmErrorT sm_service_disabling_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DISABLING_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_api.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_api.c new file mode 100644 index 00000000..917797c0 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_api.c @@ -0,0 +1,322 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_api.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" +#include "sm_service_domain_table.h" +#include "sm_service_domain_member_table.h" +#include "sm_service_domain_neighbor_table.h" +#include "sm_service_domain_assignment_table.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_fsm.h" +#include "sm_service_domain_neighbor_fsm.h" +#include "sm_service_domain_interface_fsm.h" +#include "sm_service_domain_scheduler.h" + +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Domain API - Interface Enabled +// ====================================== +SmErrorT sm_service_domain_api_interface_enabled( char service_domain_name[] ) +{ + SmServiceDomainEventT event = SM_SERVICE_DOMAIN_EVENT_INTERFACE_ENABLED; + SmErrorT error; + + error = sm_service_domain_fsm_event_handler( service_domain_name, event, + NULL, "interface enabled" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) failed to handle event (%s), error=%s.", + service_domain_name, sm_service_domain_event_str(event), + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Interface Disabled +// ====================================== +SmErrorT sm_service_domain_api_interface_disabled( char service_domain_name[] ) +{ + SmServiceDomainEventT event = SM_SERVICE_DOMAIN_EVENT_INTERFACE_DISABLED; + SmErrorT error; + + error = sm_service_domain_fsm_event_handler( service_domain_name, event, + NULL, "interface disabled" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) failed to handle event (%s), error=%s.", + service_domain_name, sm_service_domain_event_str(event), + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Send Pause +// =============================== +static void sm_service_domain_api_send_pause( void* user_data[], + SmServiceDomainT* domain ) +{ + int pause_interval = *(int*) user_data[0]; + SmErrorT error; + + error = sm_service_domain_utils_send_pause( domain->name, pause_interval ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) failed to send pause, error=%s.", + domain->name, sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Pause All +// ============================== +void sm_service_domain_api_pause_all( int pause_interval ) +{ + void* user_data[] = {&pause_interval}; + + sm_service_domain_table_foreach( user_data, + sm_service_domain_api_send_pause ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Interface State Callback +// ============================================= +static void sm_service_domain_api_interface_state_callback( + char service_domain[], char service_domain_interface[], + SmInterfaceStateT interface_state ) +{ + SmErrorT error; + + if( SM_INTERFACE_STATE_ENABLED == interface_state ) + { + error = sm_service_domain_api_interface_enabled( service_domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service domain (%s) that " + "interface (%s) is enabled, error=%s.", service_domain, + service_domain_interface, sm_error_str( error ) ); + return; + } + + } else if( SM_INTERFACE_STATE_DISABLED == interface_state ) { + + error = sm_service_domain_api_interface_disabled( service_domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service domain (%s) that interface " + "(%s) is disabled, error=%s.", service_domain, + service_domain_interface, sm_error_str( error ) ); + return; + } + + } else { + DPRINTFD( "Ignoring interface (%s) state (%s) from service " + "domain (%s).", service_domain_interface, + sm_interface_state_str( interface_state ), + service_domain ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Initialize +// =============================== +SmErrorT sm_service_domain_api_initialize( void ) +{ + SmErrorT error; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_member_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain member table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain neighbor table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_assignment_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain assignment table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_utils_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain utilities, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_fsm_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain fsm, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_fsm_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain neighbor fsm, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_scheduler_initialize( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain scheduler, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_interface_fsm_register_callback( + sm_service_domain_api_interface_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for interface state changes, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Finalize +// ============================= +SmErrorT sm_service_domain_api_finalize( void ) +{ + SmErrorT error; + + error = sm_service_domain_interface_fsm_deregister_callback( + sm_service_domain_api_interface_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for interface state changes, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_scheduler_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain scheduler, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_neighbor_fsm_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain neighbor fsm, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_fsm_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain fsm, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_utils_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain utilities, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_assignment_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain assignment table, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_member_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain member table, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_neighbor_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain neighbor table, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain table, " + "error=%s.", sm_error_str( error ) ); + } + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_api.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_api.h new file mode 100644 index 00000000..6cc278d4 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_api.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_API_H__ +#define __SM_SERVICE_DOMAIN_API_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain API - Interface Enabled +// ====================================== +extern SmErrorT sm_service_domain_api_interface_enabled( + char service_domain_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Interface Disabled +// ======================================= +extern SmErrorT sm_service_domain_api_interface_disabled( + char service_domain_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Pause All +// ============================== +extern void sm_service_domain_api_pause_all( int pause_interval ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Initialize +// =============================== +extern SmErrorT sm_service_domain_api_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain API - Finalize +// ============================= +extern SmErrorT sm_service_domain_api_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_API_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_assignment_table.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_assignment_table.c new file mode 100644 index 00000000..410761be --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_assignment_table.c @@ -0,0 +1,642 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_assignment_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_domain_assignments.h" + +static SmListT* _service_domain_assignments = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Domain Assignment Table - Read +// ====================================== +SmServiceDomainAssignmentT* sm_service_domain_assignment_table_read( + char name[], char node_name[], char service_group_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH( _service_domain_assignments, entry, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if(( 0 == strcmp( name, assignment->name ) )&& + ( 0 == strcmp( node_name, assignment->node_name ) )&& + ( 0 == strcmp( service_group_name, assignment->service_group_name ) )) + { + return( assignment ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Read By Identifier +// ==================================================== +SmServiceDomainAssignmentT* sm_service_domain_assignment_table_read_by_id( + int64_t id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH( _service_domain_assignments, entry, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if( id == assignment->id ) + { + return( assignment ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Count +// ======================================= +unsigned int sm_service_domain_assignment_table_count( + char service_domain_name[], void* user_data[], + SmServiceDomainAssignmentTableCountCallbackT callback ) +{ + unsigned int count = 0; + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH( _service_domain_assignments, entry, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if( 0 == strcmp( service_domain_name, assignment->name ) ) + { + if( callback( user_data, assignment ) ) + { + ++count; + } + } + } + + return( count ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Count Service Group +// ===================================================== +unsigned int sm_service_domain_assignment_table_count_service_group( + char service_domain_name[], char service_group_name[], void* user_data[], + SmServiceDomainAssignmentTableCountCallbackT callback ) +{ + unsigned int count = 0; + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH( _service_domain_assignments, entry, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if(( 0 == strcmp( service_domain_name, assignment->name ) ) && + ( 0 == strcmp( service_group_name, assignment->service_group_name ) )) + { + if( callback( user_data, assignment ) ) + { + ++count; + } + } + } + + return( count ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each +// ========================================== +void sm_service_domain_assignment_table_foreach( char service_domain_name[], + void* user_data[], SmServiceDomainAssignmentTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListT* next = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH_SAFE( _service_domain_assignments, entry, next, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if( 0 == strcmp( service_domain_name, assignment->name ) ) + { + callback( user_data, assignment ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each Service Group +// ======================================================== +void sm_service_domain_assignment_table_foreach_service_group( + char service_domain_name[], char service_group_name[], void* user_data[], + SmServiceDomainAssignmentTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListT* next = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH_SAFE( _service_domain_assignments, entry, next, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if(( 0 == strcmp( service_domain_name, assignment->name ) )&& + ( 0 == strcmp( service_group_name, assignment->service_group_name ) )) + { + callback( user_data, assignment ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each Node in Service Domain +// ================================================================= +void sm_service_domain_assignment_table_foreach_node_in_service_domain( + char service_domain_name[], char node_name[], void* user_data[], + SmServiceDomainAssignmentTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListT* next = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH_SAFE( _service_domain_assignments, entry, next, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if(( 0 == strcmp( service_domain_name, assignment->name ) )&& + ( 0 == strcmp( node_name, assignment->node_name ) )) + { + callback( user_data, assignment ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each Node +// =============================================== +void sm_service_domain_assignment_table_foreach_node( char node_name[], + void* user_data[], SmServiceDomainAssignmentTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListT* next = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH_SAFE( _service_domain_assignments, entry, next, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if( 0 == strcmp( node_name, assignment->node_name ) ) + { + callback( user_data, assignment ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each Schedule List +// ======================================================== +void sm_service_domain_assignment_table_foreach_schedule_list( + char service_domain_name[], SmServiceDomainSchedulingListT sched_list, + void* user_data[], SmServiceDomainAssignmentTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListT* next = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_FOREACH_SAFE( _service_domain_assignments, entry, next, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if(( 0 == strcmp( service_domain_name, assignment->name ) )&& + ( sched_list == assignment->sched_list )) + { + callback( user_data, assignment ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Sort +// ====================================== +void sm_service_domain_assignment_table_sort( + SmServiceDomainAssignmentTableCompareCallbackT callback ) +{ + SM_LIST_SORT( _service_domain_assignments, callback ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Sort Assignments +// =========================================== +static int sm_service_domain_assignment_table_sort_by_id( const void* lhs, + const void* rhs ) +{ + SmServiceDomainAssignmentT* assignment_lhs; + SmServiceDomainAssignmentT* assignment_rhs; + + assignment_lhs = (SmServiceDomainAssignmentT*) lhs; + assignment_rhs = (SmServiceDomainAssignmentT*) rhs; + + if( assignment_lhs->id < assignment_rhs->id ) + { + return( -1 ); // lhs before rhs + } + + if( assignment_lhs->id > assignment_rhs->id ) + { + return( 1 ); // lhs after rhs + } + + return( 0 ); // lhs equal to rhs +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Get Next Node +// =============================================== +SmServiceDomainAssignmentT* sm_service_domain_assignment_table_get_next_node( + char service_domain_name[], char node_name[], int64_t last_id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_SORT( _service_domain_assignments, + sm_service_domain_assignment_table_sort_by_id ); + + SM_LIST_FOREACH( _service_domain_assignments, entry, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if(( 0 == strcmp( service_domain_name, assignment->name ) )&& + ( 0 == strcmp( node_name, assignment->node_name ) )&& + ( last_id < assignment->id )) + { + return( assignment ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Get Last Node +// =============================================== +SmServiceDomainAssignmentT* sm_service_domain_assignment_table_get_last_node( + char service_domain_name[], char node_name[], int64_t last_id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainAssignmentT* assignment; + + SM_LIST_SORT( _service_domain_assignments, + sm_service_domain_assignment_table_sort_by_id ); + + SM_LIST_FOREACH( _service_domain_assignments, entry, entry_data ) + { + assignment = (SmServiceDomainAssignmentT*) entry_data; + + if(( 0 == strcmp( service_domain_name, assignment->name ) )&& + ( 0 == strcmp( node_name, assignment->node_name ) )&& + ( last_id == assignment->id )) + { + return( assignment ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Add +// ===================================== +static SmErrorT sm_service_domain_assignment_table_add( void* user_data[], + void* record ) +{ + SmServiceDomainAssignmentT* assignment; + SmDbServiceDomainAssignmentT* db_assignment; + struct timespec ts; + + db_assignment = (SmDbServiceDomainAssignmentT*) record; + + assignment = sm_service_domain_assignment_table_read( + db_assignment->name, + db_assignment->node_name, + db_assignment->service_group_name ); + if( NULL == assignment ) + { + assignment = (SmServiceDomainAssignmentT*) + malloc( sizeof(SmServiceDomainAssignmentT) ); + if( NULL == assignment ) + { + DPRINTFE( "Failed to allocate service domain assignment table " + "entry." ); + return( SM_FAILED ); + } + + memset( assignment, 0, sizeof(SmServiceDomainAssignmentT) ); + + clock_gettime( CLOCK_MONOTONIC_RAW, &ts ); + + assignment->id = db_assignment->id; + snprintf( assignment->uuid, sizeof(assignment->uuid), + "%s", db_assignment->uuid ); + snprintf( assignment->name, sizeof(assignment->name), + "%s", db_assignment->name ); + snprintf( assignment->node_name, sizeof(assignment->node_name), + "%s", db_assignment->node_name ); + snprintf( assignment->service_group_name, + sizeof(assignment->service_group_name), + "%s", db_assignment->service_group_name ); + assignment->desired_state = db_assignment->desired_state; + assignment->state = db_assignment->state; + assignment->status = db_assignment->status; + assignment->condition = db_assignment->condition; + assignment->health = 0; + assignment->last_state_change = (long) ts.tv_sec; + assignment->sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE; + assignment->sched_weight = 0; + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_NIL; + assignment->reason_text[0] = '\0'; + assignment->exchanged = false; + + SM_LIST_PREPEND( _service_domain_assignments, + (SmListEntryDataPtrT) assignment ); + } else { + assignment->id = db_assignment->id; + snprintf( assignment->uuid, sizeof(assignment->uuid), + "%s", db_assignment->uuid ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Insert +// ======================================== +SmErrorT sm_service_domain_assignment_table_insert( char name[], + char node_name[], char service_group_name[], + SmServiceGroupStateT desired_state, SmServiceGroupStateT state, + SmServiceGroupStatusT status, SmServiceGroupConditionT condition, + int64_t health, long last_state_change, const char reason_text[] ) +{ + SmServiceDomainAssignmentT* assignment; + SmDbServiceDomainAssignmentT db_assignment; + SmErrorT error; + + memset( &db_assignment, 0, sizeof(SmDbServiceDomainAssignmentT) ); + + snprintf( db_assignment.name, sizeof(db_assignment.name), "%s", name ); + snprintf( db_assignment.node_name, sizeof(db_assignment.node_name), "%s", + node_name ); + snprintf( db_assignment.service_group_name, + sizeof(db_assignment.service_group_name), "%s", + service_group_name ); + db_assignment.desired_state = desired_state; + db_assignment.state = state; + db_assignment.status = status; + db_assignment.condition = condition; + + error = sm_db_service_domain_assignments_insert( _sm_db_handle, + &db_assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to insert assignment (%s) for service domain " + "(%s) node (%s), error=%s.", service_group_name, name, + node_name, sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_assignments_read( _sm_db_handle, name, + node_name, service_group_name, &db_assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read assignment (%s) for service domain " + "(%s) node (%s), error=%s.", service_group_name, name, + node_name, sm_error_str( error ) ); + return( error ); + } + + assignment = (SmServiceDomainAssignmentT*) + malloc( sizeof(SmServiceDomainAssignmentT) ); + if( NULL == assignment ) + { + DPRINTFE( "Failed to allocate service domain assignment table entry." ); + return( SM_FAILED ); + } + + assignment->id = db_assignment.id; + snprintf( assignment->uuid, sizeof(assignment->uuid), + "%s", db_assignment.uuid ); + snprintf( assignment->name, sizeof(assignment->name), + "%s", db_assignment.name ); + snprintf( assignment->node_name, sizeof(assignment->node_name), + "%s", db_assignment.node_name ); + snprintf( assignment->service_group_name, + sizeof(assignment->service_group_name), + "%s", db_assignment.service_group_name ); + assignment->desired_state = db_assignment.desired_state; + assignment->state = db_assignment.state; + assignment->status = db_assignment.status; + assignment->condition = db_assignment.condition; + assignment->health = health; + assignment->last_state_change = last_state_change; + assignment->sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE; + assignment->sched_weight = 0; + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_NIL; + snprintf( assignment->reason_text, sizeof(assignment->reason_text), + "%s", reason_text ); + assignment->exchanged = false; + + SM_LIST_PREPEND( _service_domain_assignments, + (SmListEntryDataPtrT) assignment ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Delete +// ======================================== +SmErrorT sm_service_domain_assignment_table_delete( char name[], + char node_name[], char service_group_name[] ) +{ + SmServiceDomainAssignmentT* assignment; + SmErrorT error; + + assignment = sm_service_domain_assignment_table_read( name, node_name, + service_group_name ); + if( NULL != assignment ) + { + error = sm_db_service_domain_assignments_delete( _sm_db_handle, name, + node_name, service_group_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to delete assignment (%s) for service domain " + "(%s) node (%s), error=%s.", service_group_name, name, + node_name, sm_error_str( error ) ); + return( error ); + } + + SM_LIST_REMOVE( _service_domain_assignments, + (SmListEntryDataPtrT) assignment ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Load +// ====================================== +SmErrorT sm_service_domain_assignment_table_load( void ) +{ + SmDbServiceDomainAssignmentT assignment; + SmErrorT error; + + error = sm_db_foreach( SM_DATABASE_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, + NULL, &assignment, + sm_db_service_domain_assignments_convert, + sm_service_domain_assignment_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service domain assignments in " + "database, error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Persist +// ========================================= +SmErrorT sm_service_domain_assignment_table_persist( + SmServiceDomainAssignmentT* assignment ) +{ + SmDbServiceDomainAssignmentT db_assignment; + SmErrorT error; + + memset( &db_assignment, 0, sizeof(db_assignment) ); + + db_assignment.id = assignment->id; + snprintf( db_assignment.uuid, sizeof(db_assignment.uuid), + "%s", assignment->uuid ); + snprintf( db_assignment.name, sizeof(db_assignment.name), + "%s", assignment->name ); + snprintf( db_assignment.node_name, sizeof(db_assignment.node_name), + "%s", assignment->node_name ); + snprintf( db_assignment.service_group_name, + sizeof(db_assignment.service_group_name), + "%s", assignment->service_group_name ); + db_assignment.desired_state = assignment->desired_state; + db_assignment.state = assignment->state; + db_assignment.status = assignment->status; + db_assignment.condition = assignment->condition; + + error = sm_db_service_domain_assignments_update( _sm_db_handle, + &db_assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Initialize +// ============================================ +SmErrorT sm_service_domain_assignment_table_initialize( void ) +{ + SmErrorT error; + + _service_domain_assignments = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_assignment_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service domain assignments from database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Finalize +// ========================================== +SmErrorT sm_service_domain_assignment_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_domain_assignments ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_assignment_table.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_assignment_table.h new file mode 100644 index 00000000..273c2a39 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_assignment_table.h @@ -0,0 +1,188 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_ASSIGNMENT_TABLE_H__ +#define __SM_SERVICE_DOMAIN_ASSIGNMENT_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_uuid.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int64_t id; + SmUuidT uuid; + char name[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char node_name[SM_NODE_NAME_MAX_CHAR]; + char service_group_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceGroupStateT desired_state; + SmServiceGroupStateT state; + SmServiceGroupStatusT status; + SmServiceGroupConditionT condition; + int64_t health; + long last_state_change; + SmServiceDomainSchedulingStateT sched_state; + int sched_weight; + SmServiceDomainSchedulingListT sched_list; + char reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR]; + bool exchanged; +} SmServiceDomainAssignmentT; + +typedef int (*SmServiceDomainAssignmentTableCompareCallbackT) + (const void* assignment_lhs, const void* assignment_rhs); + +typedef bool (*SmServiceDomainAssignmentTableCountCallbackT) + (void* user_data[], SmServiceDomainAssignmentT* assignment); + +typedef void (*SmServiceDomainAssignmentTableForEachCallbackT) + (void* user_data[], SmServiceDomainAssignmentT* assignment); + +// **************************************************************************** +// Service Domain Assignment Table - Read +// ====================================== +extern SmServiceDomainAssignmentT* +sm_service_domain_assignment_table_read( char name[], char node_name[], + char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Read By Identifier +// ==================================================== +extern SmServiceDomainAssignmentT* +sm_service_domain_assignment_table_read_by_id( int64_t id ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Count +// ======================================= +extern unsigned int sm_service_domain_assignment_table_count( + char service_domain_name[], void* user_data[], + SmServiceDomainAssignmentTableCountCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Count Service Group +// ===================================================== +extern unsigned int sm_service_domain_assignment_table_count_service_group( + char service_domain_name[], char service_group_name[], void* user_data[], + SmServiceDomainAssignmentTableCountCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each +// ========================================== +extern void sm_service_domain_assignment_table_foreach( + char service_domain_name[], void* user_data[], + SmServiceDomainAssignmentTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each Service Group +// ======================================================== +extern void sm_service_domain_assignment_table_foreach_service_group( + char service_domain_name[], char service_group_name[], void* user_data[], + SmServiceDomainAssignmentTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each Node in Service Domain +// ================================================================= +extern void sm_service_domain_assignment_table_foreach_node_in_service_domain( + char service_domain_name[], char node_name[], void* user_data[], + SmServiceDomainAssignmentTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each Node +// =============================================== +extern void sm_service_domain_assignment_table_foreach_node( + char node_name[], void* user_data[], + SmServiceDomainAssignmentTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - For Each Schedule List +// ======================================================== +extern void sm_service_domain_assignment_table_foreach_schedule_list( + char service_domain_name[], SmServiceDomainSchedulingListT sched_list, + void* user_data[], SmServiceDomainAssignmentTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Sort +// ====================================== +extern void sm_service_domain_assignment_table_sort( + SmServiceDomainAssignmentTableCompareCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Get Next Node +// =============================================== +extern SmServiceDomainAssignmentT* +sm_service_domain_assignment_table_get_next_node( + char service_domain_name[], char node_name[], int64_t last_id ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Get Last Node +// =============================================== +extern SmServiceDomainAssignmentT* +sm_service_domain_assignment_table_get_last_node( + char service_domain_name[], char node_name[], int64_t last_id ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Insert +// ======================================== +extern SmErrorT sm_service_domain_assignment_table_insert( char name[], + char node_name[], char service_group_name[], + SmServiceGroupStateT desired_state, SmServiceGroupStateT state, + SmServiceGroupStatusT status, SmServiceGroupConditionT condition, + int64_t health, long last_state_change, const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Delete +// ======================================== +extern SmErrorT sm_service_domain_assignment_table_delete( char name[], + char node_name[], char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Load +// ====================================== +extern SmErrorT sm_service_domain_assignment_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Persist +// ========================================= +extern SmErrorT sm_service_domain_assignment_table_persist( + SmServiceDomainAssignmentT* assignment ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Initialize +// ============================================ +extern SmErrorT sm_service_domain_assignment_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Assignment Table - Finalize +// ========================================== +extern SmErrorT sm_service_domain_assignment_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_ASSIGNMENT_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_backup_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_backup_state.c new file mode 100644 index 00000000..e4471ae3 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_backup_state.c @@ -0,0 +1,218 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_backup_state.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_node_api.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_fsm.h" + +// **************************************************************************** +// Service Domain Backup State - Entry +// =================================== +SmErrorT sm_service_domain_backup_state_entry( SmServiceDomainT* domain ) +{ + domain->designation = SM_DESIGNATION_TYPE_BACKUP; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Exit +// ================================== +SmErrorT sm_service_domain_backup_state_exit( SmServiceDomainT* domain ) +{ + domain->designation = SM_DESIGNATION_TYPE_UNKNOWN; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Transition +// ======================================== +SmErrorT sm_service_domain_backup_state_transition( SmServiceDomainT* domain, + SmServiceDomainStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Event Handler +// =========================================== +SmErrorT sm_service_domain_backup_state_event_handler( SmServiceDomainT* domain, + SmServiceDomainEventT event, void* event_data[] ) +{ + bool enabled, elected; + char* leader_name = NULL; + char* neighbor_name = NULL; + char leader[SM_NODE_NAME_MAX_CHAR]; + char hostname[SM_NODE_NAME_MAX_CHAR]; + int generation = 0; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainStateT state = SM_SERVICE_DOMAIN_STATE_NIL; + SmErrorT error; + + error = sm_service_domain_utils_service_domain_enabled( domain->name, + &enabled ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if service domain (%s) is enabled, " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_DOMAIN_EVENT_HELLO_MSG: + neighbor_name + = (char*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_NODE_NAME]; + generation + = *(int*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_GENERATION]; + leader_name + = (char*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_LEADER]; + + if( 0 == strcmp( hostname, leader_name ) ) + { + state = SM_SERVICE_DOMAIN_STATE_WAITING; + + snprintf( reason_text, sizeof(reason_text), + "hello received from %s indicating %s as leader", + neighbor_name, leader_name ); + + } else if( 0 == strcmp( neighbor_name, leader_name ) ) { + if( generation < domain->generation ) + { + state = SM_SERVICE_DOMAIN_STATE_WAITING; + + snprintf( reason_text, sizeof(reason_text), + "hello received from %s indicating leader, " + "but from lesser generation", neighbor_name ); + } + } + + if( SM_SERVICE_DOMAIN_STATE_NIL != state ) + { + error = sm_service_domain_fsm_set_state( domain->name, + state, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) failed, " + "error=%s.", sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_NEIGHBOR_AGEOUT: + neighbor_name + = (char*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_NODE_NAME]; + + if( 0 == strcmp( neighbor_name, domain->leader ) ) + { + error = sm_service_domain_utils_hold_election( domain->name, + leader, &elected ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to hold election for service domain " + "(%s), error=%s.", domain->name, + sm_error_str( error ) ); + return( error ); + } + + if( 0 != strcmp( leader, domain->leader ) ) + { + state = SM_SERVICE_DOMAIN_STATE_WAITING; + + snprintf( reason_text, sizeof(reason_text), + "neighbor %s ageout of leader", neighbor_name ); + + error = sm_service_domain_fsm_set_state( domain->name, + state, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) " + "failed, error=%s.", + sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_ENABLED: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_DISABLED: + if( !enabled ) + { + state = SM_SERVICE_DOMAIN_STATE_INITIAL; + + snprintf( reason_text, sizeof(reason_text), + "primary interface disabled" ); + + error = sm_service_domain_fsm_set_state( domain->name, state, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) failed, " + "error=%s.", sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_WAIT_EXPIRED: + // Ignore. + break; + + default: + DPRINTFD( "Service Domain (%s) ignoring event (%s).", + domain->name, + sm_service_domain_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Initialize +// ======================================== +SmErrorT sm_service_domain_backup_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Finalize +// ====================================== +SmErrorT sm_service_domain_backup_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_backup_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_backup_state.h new file mode 100644 index 00000000..25e4ab8d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_backup_state.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_BACKUP_STATE_H__ +#define __SM_SERVICE_DOMAIN_BACKUP_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Backup State - Entry +// =================================== +extern SmErrorT sm_service_domain_backup_state_entry( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Exit +// ================================== +extern SmErrorT sm_service_domain_backup_state_exit( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Transition +// ======================================== +extern SmErrorT sm_service_domain_backup_state_transition( + SmServiceDomainT* domain, SmServiceDomainStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Event Handler +// =========================================== +extern SmErrorT sm_service_domain_backup_state_event_handler( + SmServiceDomainT* domain, SmServiceDomainEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Initialize +// ======================================== +extern SmErrorT sm_service_domain_backup_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Backup State - Finalize +// ====================================== +extern SmErrorT sm_service_domain_backup_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_BACKUP_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_filter.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_filter.c new file mode 100644 index 00000000..ee96ffbe --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_filter.c @@ -0,0 +1,1011 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_filter.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_nodes.h" +#include "sm_service_domain_member_table.h" +#include "sm_service_domain_neighbor_table.h" +#include "sm_service_domain_assignment_table.h" +#include "sm_node_api.h" +#include "sm_node_swact_monitor.h" +#include "sm_node_utils.h" + +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Domain Filter - Cleanup +// =============================== +static void sm_service_domain_filter_cleanup( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED; +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - By Node Ready +// ===================================== +static void sm_service_domain_filter_by_node_ready( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + SmServiceDomainFilterCountsT* counts; + SmDbNodeT node; + SmServiceDomainSchedulingListT list; + SmErrorT error; + + counts = (SmServiceDomainFilterCountsT*) user_data[0]; + + list = assignment->sched_list; + + error = sm_db_nodes_read( _sm_db_handle, assignment->node_name, &node ); + if( SM_OKAY == error ) + { + + if( SM_NODE_READY_STATE_ENABLED != node.ready_state ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE; + ++(counts->unavailable_members); + } + } else if( SM_NOT_FOUND == error ) { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE; + ++(counts->unavailable_members); + + } else { + DPRINTFE( "Failed to read node (%s) info, error = %s.", + assignment->node_name, sm_error_str(error) ); + return; + } + + if( list != assignment->sched_list ) + { + assignment->sched_list = list; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - By Node Administrative State +// ==================================================== +static void sm_service_domain_filter_by_node_admin_state( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + SmServiceDomainFilterCountsT* counts; + SmDbNodeT node; + SmServiceDomainSchedulingListT list; + SmErrorT error; + + counts = (SmServiceDomainFilterCountsT*) user_data[0]; + + list = assignment->sched_list; + + error = sm_db_nodes_read( _sm_db_handle, assignment->node_name, &node ); + if( SM_OKAY == error ) + { + if( SM_NODE_ADMIN_STATE_LOCKED == node.admin_state ) + { +#ifdef SM_CONFIG_OPTION_STANDBY_ALL_SERVICES_ON_A_LOCKED_NODE + switch( list ) + { + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE: + --(counts->active_members); + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY; + ++(counts->go_standby_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE: + --(counts->go_active_members); + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY; + ++(counts->go_standby_members); + break; + default: + //Ignore. + break; + } +#else + // Adjust counts. + switch( list ) + { + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE: + --(counts->active_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE: + --(counts->go_active_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY: + --(counts->go_standby_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY: + --(counts->standby_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING: + --(counts->disabling_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED: + --(counts->disabled_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED: + --(counts->failed_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL: + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE: + default: + //Ignore. + break; + } + + if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL != list )&& + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE != list )) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE; + ++(counts->unavailable_members); + } +#endif // SM_CONFIG_OPTION_STANDBY_ALL_SERVICES_ON_A_LOCKED_NODE + } + } else if( SM_NOT_FOUND != error ) { + DPRINTFE( "Failed to read node (%s) info, error = %s.", + assignment->node_name, sm_error_str(error) ); + return; + } + + if( list != assignment->sched_list ) + { + assignment->sched_list = list; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - By Neighbor +// =================================== +static void sm_service_domain_filter_by_neighbor( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + SmServiceDomainFilterCountsT* counts; + SmServiceDomainSchedulingListT list; + SmServiceDomainNeighborT* neighbor; + SmErrorT error; + + counts = (SmServiceDomainFilterCountsT*) user_data[0]; + + list = assignment->sched_list; + + neighbor = sm_service_domain_neighbor_table_read( assignment->node_name, + assignment->name ); + if( NULL != neighbor ) + { + if( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL != neighbor->state ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE; + ++(counts->unavailable_members); + + } else { + if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == list ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED; + // Don't increment here as the counts will be + // thrown off later, assignment filter will do + // the increment. + } + } + } else { + char hostname[SM_NODE_NAME_MAX_CHAR]; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return; + } + + if( 0 != strcmp( hostname, assignment->node_name ) ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE; + ++(counts->unavailable_members); + } + } + + if( list != assignment->sched_list ) + { + assignment->sched_list = list; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - By Assignment +// ===================================== +static void sm_service_domain_filter_by_assignment( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + SmServiceDomainFilterCountsT* counts; + SmServiceDomainSchedulingListT list; + + counts = (SmServiceDomainFilterCountsT*) user_data[0]; + + list = assignment->sched_list; + + ++(counts->total_members); + + // Previous filter might have already decided that this assignment + // needs to be put on the unavailable or disabled list (node checks). + if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list ) + { + DPRINTFD( "Member assignment (%s) for service domain (%s) node (%s) " + "is unavailable.", assignment->service_group_name, + assignment->name, assignment->node_name ); + return; + } + + // The scheduler decided that this assignment needs to be disabled. + if( SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE == assignment->sched_state ) + { + // Assignment is failed, move to the failed scheduling list. + if( SM_SERVICE_GROUP_STATUS_FAILED == assignment->status ) + { + // Fatal condition is looked at later when the health of all + // assignments is compared. + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED; + ++(counts->failed_members); + } else { + // Put it on the unavailable list, so that it can't be chosen. + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE; + ++(counts->unavailable_members); + } + goto UPDATE; + } + + // Request to swact from this assignment has been indicated. + if(( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT == assignment->sched_state )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE == assignment->sched_state )) + { + if(( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->state )|| + ( SM_SERVICE_GROUP_STATE_GO_ACTIVE == assignment->state )) + { + SmServiceDomainMemberT* member; + + member = sm_service_domain_member_table_read( assignment->name, + assignment->service_group_name ); + if( NULL == member ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY; + ++(counts->go_standby_members); + + DPRINTFE( "Failed to read service domain (%s) member (%s), " + "error=%s.", assignment->name, + assignment->service_group_name, + sm_error_str(SM_NOT_FOUND) ); + goto UPDATE; + } + + if( 0 < member->m_standby ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY; + ++(counts->go_standby_members); + } else { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED; + ++(counts->disabled_members); + } + } else if( SM_SERVICE_GROUP_STATE_STANDBY == assignment->state ) { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY; + ++(counts->standby_members); + + } else { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED; + ++(counts->disabled_members); + } + goto UPDATE; + } + + // Assignment is failed, move to the failed scheduling list. + if( SM_SERVICE_GROUP_STATUS_FAILED == assignment->status ) + { + // Fatal condition is looked at later when the health of all + // assignments is compared. + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmErrorT error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + hostname[0] = '\0'; + } + DPRINTFI("Uncontrolled swact start"); + if(0 == strcmp(hostname, assignment->node_name)) + { + SmNodeSwactMonitor::SwactStart(SM_NODE_STATE_STANDBY); + }else + { + SmNodeSwactMonitor::SwactStart(SM_NODE_STATE_ACTIVE); + } + + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED; + ++(counts->failed_members); + goto UPDATE; + } + + // Select scheduling list based on desired-state and operational state. + if( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->desired_state ) + { + if( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->state ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE; + ++(counts->active_members); + } else { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE; + ++(counts->go_active_members); + } + } + else if( SM_SERVICE_GROUP_STATE_STANDBY == assignment->desired_state ) + { + if( SM_SERVICE_GROUP_STATE_STANDBY == assignment->state ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY; + ++(counts->standby_members); + } else { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY; + ++(counts->go_standby_members); + } + } + else if( SM_SERVICE_GROUP_STATE_DISABLED == assignment->desired_state ) + { + if( SM_SERVICE_GROUP_STATE_DISABLED == assignment->state ) + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED; + ++(counts->disabled_members); + } else { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING; + ++(counts->disabling_members); + } + } + else + { + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED; + ++(counts->disabled_members); + } + +UPDATE: + if( list != assignment->sched_list ) + { + assignment->sched_list = list; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Count Healthier Assignments +// =================================================== +static void sm_service_domain_filter_count_healthier_assignments( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + int* count; + SmDbNodeT node; + SmServiceDomainAssignmentT* target_assignment; + + count = (int*) user_data[0]; + target_assignment = (SmServiceDomainAssignmentT*) user_data[1]; + SmErrorT error; + + error = sm_db_nodes_read( _sm_db_handle, assignment->node_name, &node ); + if( SM_OKAY == error ) + { + if( SM_NODE_ADMIN_STATE_LOCKED == node.admin_state ) + { + DPRINTFD( "Node (%s) is locked.", assignment->node_name ); + return; + } + } else if( SM_NOT_FOUND == error ) { + DPRINTFD( "Node (%s) not found.", assignment->node_name ); + return; + } else { + DPRINTFE( "Failed to read node (%s) info, error = %s.", + assignment->node_name, sm_error_str(error) ); + return; + } + + if(( 0 == strcmp( assignment->name, target_assignment->name ) )&& + ( 0 != strcmp( assignment->node_name, target_assignment->node_name ) )&& + ( 0 == strcmp( assignment->service_group_name, + target_assignment->service_group_name ) )&& + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED != assignment->sched_list )&& + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL != assignment->sched_list )&& + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE != assignment->sched_list )&& + ( assignment->health > target_assignment->health )) + { + ++(*count); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - By Assignment Health +// ============================================ +static void sm_service_domain_filter_by_assignment_health( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + int count = 0; + char* service_domain_name = (char*) user_data[1]; + SmServiceDomainFilterCountsT* counts; + SmServiceDomainMemberT* member; + void* user_data2[] = {&count, assignment }; + + counts = (SmServiceDomainFilterCountsT*) user_data[0]; + + if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED != assignment->sched_list ) + { + // Only looking at the failed list. + return; + } + + member = sm_service_domain_member_table_read( assignment->name, + assignment->service_group_name ); + if( NULL == member ) + { + DPRINTFE( "Failed to read service domain (%s) member (%s), error=%s.", + assignment->name, assignment->service_group_name, + sm_error_str(SM_NOT_FOUND) ); + return; + } + + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data2, sm_service_domain_filter_count_healthier_assignments ); + + if( member->n_active <= count ) + { + // Healthier assignment available. + switch( assignment->condition ) + { + case SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE: + // Already on the failed scheduling list. + break; + + case SM_SERVICE_GROUP_CONDITION_FATAL_FAILURE: + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL; + --(counts->failed_members); + ++(counts->fatal_members); + break; + + default: + assignment->sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE; + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE; + --(counts->failed_members); + ++(counts->unavailable_members); + break; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Service Group Aggregate Recover +// ======================================================= +static SmErrorT sm_service_domain_filter_service_group_aggregate_recover( + bool* recover, SmServiceDomainAssignmentT* assignment ) +{ + if(( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT == assignment->sched_state )&& + ( SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE == assignment->condition )) + { + if((( SM_SERVICE_GROUP_STATE_STANDBY == assignment->desired_state )&& + ( SM_SERVICE_GROUP_STATE_GO_STANDBY == assignment->state ))|| + (( SM_SERVICE_GROUP_STATE_DISABLED == assignment->desired_state )&& + ( SM_SERVICE_GROUP_STATE_DISABLING == assignment->state ))) + { + // Fail back to from-side back. + *recover = true; + DPRINTFE( "Failback service domain (%s) member (%s).", + assignment->name, assignment->service_group_name ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Service Group Aggregate Recover Apply +// ============================================================= +static SmErrorT sm_service_domain_filter_service_group_aggregate_recover_apply( + SmServiceDomainFilterCountsT* counts, + SmServiceDomainAssignmentT* assignment ) +{ + assignment->sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE; + + switch( assignment->sched_list ) + { + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE: + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE: + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE: + // Nothing to recover. + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY: + --(counts->standby_members); + ++(counts->go_active_members); + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE; + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY: + --(counts->go_standby_members); + ++(counts->go_active_members); + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE; + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED: + --(counts->disabled_members); + ++(counts->go_active_members); + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE; + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING: + --(counts->disabling_members); + ++(counts->go_active_members); + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE; + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED: + --(counts->failed_members); + ++(counts->go_active_members); + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE; + break; + default: + //Ignore. + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Get Service Group Aggregate List +// ======================================================== +static SmErrorT sm_service_domain_filter_get_service_group_aggregate_list( + SmServiceDomainSchedulingListT* list, + SmServiceDomainAssignmentT* assignment ) +{ + // Failed and Fatal scheduling list is not checked below. This is to + // allow partial service scenarios, otherwise we would pull down all + // co-located assignments. + + if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE == *list ) + { + if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list )) + { + *list = assignment->sched_list; + } + } else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE == *list ) + { + if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list )) + { + *list = assignment->sched_list; + } + } else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY == *list ) + { + if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list )) + { + *list = assignment->sched_list; + } + } else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY == *list ) + { + if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list )) + { + *list = assignment->sched_list; + } + } else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == *list ) + { + if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list )) + { + *list = assignment->sched_list; + } + } else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == *list ) + { + if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list ) + { + *list = assignment->sched_list; + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Apply Service Group Aggregate List +// ========================================================== +static SmErrorT sm_service_domain_filter_apply_service_group_aggregate_list( + SmServiceDomainFilterCountsT* counts, SmServiceDomainSchedulingListT* list, + SmServiceDomainAssignmentT* assignment ) +{ + if(( *list != assignment->sched_list )&& + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED != assignment->sched_list )&& + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL != assignment->sched_list )) + { + // Adjust counts. + switch( assignment->sched_list ) + { + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE: + --(counts->active_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE: + --(counts->go_active_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY: + --(counts->go_standby_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY: + --(counts->standby_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING: + --(counts->disabling_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED: + --(counts->disabled_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE: + --(counts->unavailable_members); + break; + default: + //Ignore. + break; + } + + switch( *list ) + { + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE: + ++(counts->active_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE: + ++(counts->go_active_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY: + ++(counts->go_standby_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY: + ++(counts->standby_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING: + ++(counts->disabling_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED: + ++(counts->disabled_members); + break; + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE: + ++(counts->unavailable_members); + break; + default: + //Ignore. + break; + } + + assignment->sched_list = *list; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Service Group Aggregate Member +// ====================================================== +void sm_service_domain_filter_service_group_aggregate_member( void* user_data[], + SmServiceDomainMemberT* member ) +{ + bool apply; + bool* recover; + SmDbNodeT* node; + char* service_domain_name; + SmServiceDomainFilterCountsT* counts; + SmServiceDomainSchedulingListT* list; + SmServiceDomainAssignmentT* assignment; + SmErrorT error; + + counts = (SmServiceDomainFilterCountsT*) user_data[0]; + service_domain_name = (char*) user_data[1]; + node = (SmDbNodeT*) user_data[2]; + list = (SmServiceDomainSchedulingListT*) user_data[3]; + apply = *(bool*) user_data[4]; + recover = (bool*) user_data[5]; + + assignment = sm_service_domain_assignment_table_read( service_domain_name, + node->name, member->service_group_name ); + if( NULL == assignment ) + { + // Possible that the node has been provisioned, but not configured yet. + // This is possible during initial commissioning of the second + // controller. + DPRINTFD( "Failed to query service domain (%s) assignment (%s) for " + "node (%s), error=%s.", member->name, + member->service_group_name, node->name, + sm_error_str(SM_NOT_FOUND) ); + return; + } + + if( apply ) + { + if( *recover ) + { + error = sm_service_domain_filter_service_group_aggregate_recover_apply( + counts, assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to apply service domain (%s) assignment (%s) " + "recovery for node (%s), error=%s.", member->name, + member->service_group_name, node->name, + sm_error_str( error ) ); + return; + } + } else { + error = sm_service_domain_filter_apply_service_group_aggregate_list( + counts, list, assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to apply service domain (%s) assignment (%s) " + "list for node (%s), error=%s.", member->name, + member->service_group_name, node->name, + sm_error_str( error ) ); + return; + } + } + } else { + // First determine if recovery is needed. + error = sm_service_domain_filter_service_group_aggregate_recover( + recover, assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if recovery of service domain (%s) " + "assignment (%s) is needed for node (%s), error=%s.", + member->name, member->service_group_name, node->name, + sm_error_str( error ) ); + return; + } + + if( false == *recover ) + { + // Recovery not needed, get the common list among the service + // group aggregate. + error = sm_service_domain_filter_get_service_group_aggregate_list( + list, assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get service domain (%s) assignment (%s) " + "list for node (%s), error=%s.", member->name, + member->service_group_name, node->name, + sm_error_str( error ) ); + return; + } + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Service Group Aggregates +// ================================================ +void sm_service_domain_filter_service_group_aggregates( void* user_data[], + SmServiceDomainMemberT* member ) +{ + bool apply = false; + bool recover = false; + char* service_domain_name = (char*) user_data[1]; + SmServiceDomainSchedulingListT list; + void* user_data2[] = { user_data[0], user_data[1], user_data[2], + &list, &apply, &recover }; + + if( '\0' == member->service_group_aggregate[0] ) + { + DPRINTFD( "Not aggregated with other service groups." ); + return; + } + + list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE; + + sm_service_domain_member_table_foreach_service_group_aggregate( + service_domain_name, member->service_group_aggregate, user_data2, + sm_service_domain_filter_service_group_aggregate_member ); + + apply = true; + + sm_service_domain_member_table_foreach_service_group_aggregate( + service_domain_name, member->service_group_aggregate, user_data2, + sm_service_domain_filter_service_group_aggregate_member ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - By Service Group Aggregate +// ================================================== +SmErrorT sm_service_domain_filter_by_service_group_aggregate( void* user_data[], + void* record ) +{ + char* service_domain_name = (char*) user_data[1]; + SmDbNodeT* node = (SmDbNodeT*) record; + void* user_data2[] = { user_data[0], user_data[1], node }; + + sm_service_domain_member_table_foreach( service_domain_name, user_data2, + sm_service_domain_filter_service_group_aggregates ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Preselect Apply +// ======================================= +SmErrorT sm_service_domain_filter_preselect_apply( char service_domain_name[], + SmServiceDomainFilterCountsT* counts ) +{ + long ms_expired; + SmTimeT time_prev, time_now; + void* user_data[] = {counts, service_domain_name}; + SmDbNodeT node; + SmErrorT error; + + memset( counts, 0, sizeof(SmServiceDomainFilterCountsT) ); + + // Filter - Cleanup + sm_time_get( &time_prev ); + + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data, sm_service_domain_filter_cleanup ); + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply filter - cleanup, " + "took %li ms.", ms_expired ); + + // Filter - By Node Ready. + sm_time_get( &time_prev ); + + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data, sm_service_domain_filter_by_node_ready ); + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply filter - node enabled, " + "took %li ms.", ms_expired ); + + // Filter - By Neighbor. + sm_time_get( &time_prev ); + + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data, sm_service_domain_filter_by_neighbor ); + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply filter - neighbor, " + "took %li ms.", ms_expired ); + + // Filter - By Assignments. + sm_time_get( &time_prev ); + + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data, sm_service_domain_filter_by_assignment ); + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply filter - assignments, " + "took %li ms.", ms_expired ); + + // Filter - By Assignment Health. + sm_time_get( &time_prev ); + + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data, sm_service_domain_filter_by_assignment_health ); + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply filter - assignment health, " + "took %li ms.", ms_expired ); + + // Filter - By Node Administrative State. + sm_time_get( &time_prev ); + + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data, sm_service_domain_filter_by_node_admin_state ); + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply filter - node admin state, " + "took %li ms.", ms_expired ); + + // Filter - By Service Group Aggregate. + sm_time_get( &time_prev ); + + error = sm_db_foreach( SM_DATABASE_NAME, SM_NODES_TABLE_NAME, + NULL, &node, &sm_db_nodes_convert, + sm_service_domain_filter_by_service_group_aggregate, + user_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over nodes, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply filter - service group " + "aggregate, took %li ms.", ms_expired ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Post Select Apply +// ========================================= +SmErrorT sm_service_domain_filter_post_select_apply( char service_domain_name[], + SmServiceDomainFilterCountsT* counts ) +{ + long ms_expired; + SmTimeT time_prev, time_now; + void* user_data[] = {counts, service_domain_name}; + SmDbNodeT node; + SmErrorT error; + + // Filter - By Service Group Aggregate. + sm_time_get( &time_prev ); + + error = sm_db_foreach( SM_DATABASE_NAME, SM_NODES_TABLE_NAME, + NULL, &node, &sm_db_nodes_convert, + sm_service_domain_filter_by_service_group_aggregate, + user_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over nodes, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - post select apply filter - service group " + "aggregate, took %li ms.", ms_expired ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Initialize +// ================================== +SmErrorT sm_service_domain_filter_initialize( SmDbHandleT* sm_db_handle ) +{ + _sm_db_handle = sm_db_handle; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Finalize +// ================================ +SmErrorT sm_service_domain_filter_finalize( void ) +{ + _sm_db_handle = NULL; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_filter.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_filter.h new file mode 100644 index 00000000..85eb8dd7 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_filter.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_FILTER_H__ +#define __SM_SERVICE_DOMAIN_FILTER_H__ + +#include "sm_types.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int active_members; + int go_active_members; + int go_standby_members; + int standby_members; + int disabling_members; + int disabled_members; + int failed_members; + int fatal_members; + int unavailable_members; + int total_members; +} SmServiceDomainFilterCountsT; + +// **************************************************************************** +// Service Domain Filter - Preselect Apply +// ======================================= +extern SmErrorT sm_service_domain_filter_preselect_apply( + char service_domain_name[], SmServiceDomainFilterCountsT* counts ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Post Select Apply +// ========================================= +extern SmErrorT sm_service_domain_filter_post_select_apply( + char service_domain_name[], SmServiceDomainFilterCountsT* counts ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Initialize +// ================================== +extern SmErrorT sm_service_domain_filter_initialize( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Filter - Finalize +// ================================ +extern SmErrorT sm_service_domain_filter_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_FILTER_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_fsm.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_fsm.c new file mode 100644 index 00000000..8919892f --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_fsm.c @@ -0,0 +1,754 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_fsm.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_msg.h" +#include "sm_service_domain_table.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_initial_state.h" +#include "sm_service_domain_waiting_state.h" +#include "sm_service_domain_other_state.h" +#include "sm_service_domain_backup_state.h" +#include "sm_service_domain_leader_state.h" +#include "sm_service_domain_neighbor_fsm.h" +#include "sm_service_domain_scheduler.h" +#include "sm_alarm.h" +#include "sm_log.h" +#include "sm_node_utils.h" + +static SmMsgCallbacksT _msg_callbacks = {0}; +static char _reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + +// **************************************************************************** +// Service Domain FSM - Enter State +// ================================ +static SmErrorT sm_service_domain_fsm_enter_state( SmServiceDomainT* domain ) +{ + SmErrorT error; + + switch( domain->state ) + { + case SM_SERVICE_DOMAIN_STATE_INITIAL: + error = sm_service_domain_initial_state_entry( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to enter state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_WAITING: + error = sm_service_domain_waiting_state_entry( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to enter state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_OTHER: + error = sm_service_domain_other_state_entry( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to enter state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_BACKUP: + error = sm_service_domain_backup_state_entry( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to enter state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_LEADER: + error = sm_service_domain_leader_state_entry( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to enter state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service domain (%s) state (%s).", + domain->name, + sm_service_domain_state_str( domain->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Exit State +// =============================== +static SmErrorT sm_service_domain_fsm_exit_state( SmServiceDomainT* domain ) +{ + SmErrorT error; + + switch( domain->state ) + { + case SM_SERVICE_DOMAIN_STATE_INITIAL: + error = sm_service_domain_initial_state_exit( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to exit state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_WAITING: + error = sm_service_domain_waiting_state_exit( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to exit state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_OTHER: + error = sm_service_domain_other_state_exit( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to exit state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_BACKUP: + error = sm_service_domain_backup_state_exit( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to exit state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_LEADER: + error = sm_service_domain_leader_state_exit( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to exit state (%s), " + "error=%s.", domain->name, + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service domain (%s) state (%s).", + domain->name, + sm_service_domain_state_str( domain->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Transition State +// ===================================== +static SmErrorT sm_service_domain_fsm_transition_state( + SmServiceDomainT* domain, SmServiceDomainStateT from_state ) +{ + SmErrorT error; + + switch( domain->state ) + { + case SM_SERVICE_DOMAIN_STATE_INITIAL: + error = sm_service_domain_initial_state_transition( + domain, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + domain->name, + sm_service_domain_state_str( from_state ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_WAITING: + error = sm_service_domain_waiting_state_transition( + domain, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + domain->name, + sm_service_domain_state_str( from_state ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_OTHER: + error = sm_service_domain_other_state_transition( + domain, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + domain->name, + sm_service_domain_state_str( from_state ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_BACKUP: + error = sm_service_domain_backup_state_transition( + domain, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + domain->name, + sm_service_domain_state_str( from_state ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_LEADER: + error = sm_service_domain_leader_state_transition( + domain, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + domain->name, + sm_service_domain_state_str( from_state ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service_domain (%s) state (%s).", + domain->name, + sm_service_domain_state_str( domain->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Set State +// ============================== +SmErrorT sm_service_domain_fsm_set_state( char service_domain_name[], + SmServiceDomainStateT state, const char reason_text[] ) +{ + SmServiceDomainStateT prev_state; + SmServiceDomainT* domain; + SmErrorT error, error2; + + domain = sm_service_domain_table_read( service_domain_name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service_domain (%s), error=%s.", + service_domain_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = domain->state; + + DPRINTFI("Set state %s->%s", sm_service_domain_state_str( domain->state ), + sm_service_domain_state_str( state )); + error = sm_service_domain_fsm_exit_state( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to exit state (%s) service_domain (%s), error=%s.", + sm_service_domain_state_str( domain->state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + + domain->state = state; + + error = sm_service_domain_fsm_transition_state( domain, prev_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to transition to state (%s) service domain (%s), " + "error=%s.", sm_service_domain_state_str( domain->state ), + domain->name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + error = sm_service_domain_fsm_enter_state( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enter state (%s) service domain (%s), error=%s.", + sm_service_domain_state_str( domain->state ), + domain->name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + if( '\0' != reason_text[0] ) + { + snprintf( _reason_text, sizeof(_reason_text), "%s", reason_text ); + } + + return( SM_OKAY ); + +STATE_CHANGE_ERROR: + error2 = sm_service_domain_fsm_exit_state( domain ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to exit state (%s) service domain (%s), error=%s.", + sm_service_domain_state_str( domain->state ), + domain->name, sm_error_str( error2 ) ); + abort(); + } + + domain->state = prev_state; + + error2 = sm_service_domain_fsm_transition_state( domain, state ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to transition to state (%s) service domain (%s), " + "error=%s.", sm_service_domain_state_str( domain->state ), + domain->name, sm_error_str( error2 ) ); + abort(); + } + + error2 = sm_service_domain_fsm_enter_state( domain ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to enter state (%s) service domain (%s), error=%s.", + sm_service_domain_state_str( domain->state ), + domain->name, sm_error_str( error2 ) ); + abort(); + } + + return( error ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Event Handler +// ================================== +SmErrorT sm_service_domain_fsm_event_handler( char service_domain_name[], + SmServiceDomainEventT event, void* event_data[], const char reason_text[] ) +{ + SmServiceDomainStateT prev_state; + SmServiceDomainT* domain; + SmErrorT error; + + snprintf( _reason_text, sizeof(_reason_text), "%s", reason_text ); + + domain = sm_service_domain_table_read( service_domain_name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + service_domain_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = domain->state; + + switch( domain->state ) + { + case SM_SERVICE_DOMAIN_STATE_INITIAL: + error = sm_service_domain_initial_state_event_handler( + domain, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to handle event (%s) " + "in state (%s), error=%s.", domain->name, + sm_service_domain_event_str( event ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_WAITING: + error = sm_service_domain_waiting_state_event_handler( + domain, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to handle event (%s) " + "in state (%s), error=%s.", domain->name, + sm_service_domain_event_str( event ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_OTHER: + error = sm_service_domain_other_state_event_handler( + domain, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to handle event (%s) " + "in state (%s), error=%s.", domain->name, + sm_service_domain_event_str( event ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_BACKUP: + error = sm_service_domain_backup_state_event_handler( + domain, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to handle event (%s) " + "in state (%s), error=%s.", domain->name, + sm_service_domain_event_str( event ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_STATE_LEADER: + error = sm_service_domain_leader_state_event_handler( + domain, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service Domain (%s) unable to handle event (%s) " + "in state (%s), error=%s.", domain->name, + sm_service_domain_event_str( event ), + sm_service_domain_state_str( domain->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown state (%s) for service domain (%s).", + sm_service_domain_state_str( domain->state ), + domain->name ); + break; + } + + if( prev_state != domain->state ) + { + DPRINTFI( "Service Domain (%s) received event (%s) was in the %s " + "state and is now in the %s state.", domain->name, + sm_service_domain_event_str( event ), + sm_service_domain_state_str( prev_state ), + sm_service_domain_state_str( domain->state ) ); + + error = sm_service_domain_table_persist( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service domain (%s) data, error=%s.", + service_domain_name, sm_error_str( error ) ); + return( error ); + } + + sm_log_service_domain_state_change( domain->name, + sm_service_domain_state_str( prev_state ), + sm_service_domain_state_str( domain->state ), + _reason_text ); + + if( SM_SERVICE_DOMAIN_STATE_LEADER == domain->state ) + { + sm_alarm_manage_domain_alarms( domain->name, true ); + sm_service_domain_scheduler_schedule_service_domain( domain ); + } else { + sm_alarm_manage_domain_alarms( domain->name, false ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Hello Message Callback +// =========================================== +static void sm_service_domain_fsm_hello_msg_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char service_domain[], char node_name[], char orchestration[], + char designation[], int generation, int priority, int hello_interval, + int dead_interval, int wait_interval, int exchange_interval, char leader[] ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainEventT event = SM_SERVICE_DOMAIN_EVENT_HELLO_MSG; + void* event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MAX] = {0}; + SmErrorT error; + + event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_NODE_NAME] = node_name; + event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_GENERATION] = &generation; + event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_PRIORITY] = &priority; + event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_LEADER] = leader; + + snprintf( reason_text, sizeof(reason_text), "hello received from %s", + node_name ); + + error = sm_service_domain_fsm_event_handler( service_domain, event, + event_data, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service domain (%s).", + sm_service_domain_event_str( event ), service_domain ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Neighbor State Callback +// ============================================ +static void sm_service_domain_fsm_neighbor_state_callback( + char service_domain_name[], char node_name[], + SmServiceDomainNeighborStateT state ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainEventT event; + SmErrorT error; + + if( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN == state ) + { + void* event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MAX] = {0}; + + DPRINTFI( "Neighbor (%s) down for service domain (%s).", node_name, + service_domain_name ); + + error = sm_service_domain_utils_service_domain_neighbor_cleanup( + service_domain_name, node_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup neighbor (%s) for service " + "domain (%s), error=%s.", node_name, + service_domain_name, sm_error_str(error) ); + return; + } + + event = SM_SERVICE_DOMAIN_EVENT_NEIGHBOR_AGEOUT; + + event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_NODE_NAME] = node_name; + + snprintf( reason_text, sizeof(reason_text), "%s neighbor ageout", + node_name ); + + error = sm_service_domain_fsm_event_handler( service_domain_name, + event, event_data, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) failed to handle event (%s), " + "error=%s.", service_domain_name, + sm_service_domain_event_str(event), + sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Failover - dump state +// ====================== +void sm_service_domain_dump_state(FILE* fp) +{ + char host_name[SM_NODE_NAME_MAX_CHAR]; + SmErrorT error = sm_node_utils_get_hostname( host_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + strncpy(host_name, "error:unknown", SM_NODE_NAME_MAX_CHAR); + } + + char service_domain_name[] = "controller"; + fprintf( fp, "Service Domain %s\n\n", service_domain_name ); + + fprintf( fp, " local host: %s\n", host_name ); + fprintf( fp, ".........................\n" ); + SmServiceDomainT* domain; + domain = sm_service_domain_table_read( service_domain_name ); + fprintf( fp, " state: %s ", sm_service_domain_state_str( domain->state )); + +// fprintf( fp, " neighbor: %s\n", host_name ); +// fprintf( fp, ".........................\n" ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Initialize +// =============================== +SmErrorT sm_service_domain_fsm_initialize( void ) +{ + SmErrorT error; + + error = sm_service_domain_initial_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain initial state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_waiting_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain waiting state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_other_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain other state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_backup_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain backup state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_leader_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain leader state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + _msg_callbacks.hello = sm_service_domain_fsm_hello_msg_callback; + + error = sm_msg_register_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register message callbacks, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_fsm_register_callback( + sm_service_domain_fsm_neighbor_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for neighbor state callbacks, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Finalize +// ============================= +SmErrorT sm_service_domain_fsm_finalize( void ) +{ + SmErrorT error; + + error = sm_service_domain_neighbor_fsm_deregister_callback( + sm_service_domain_fsm_neighbor_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for neighbor state callbacks, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_msg_deregister_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister message callbacks, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_initial_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain initial state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_waiting_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain waiting state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_other_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain other state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_backup_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain backup state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_leader_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain leader state module, " + "error=%s.", sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_fsm.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_fsm.h new file mode 100644 index 00000000..91a2c669 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_fsm.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_FSM_H__ +#define __SM_SERVICE_DOMAIN_FSM_H__ + +#include +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain FSM - Set State +// ============================== +extern SmErrorT sm_service_domain_fsm_set_state( char name[], + SmServiceDomainStateT state, const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Event Handler +// ================================== +extern SmErrorT sm_service_domain_fsm_event_handler( char name[], + SmServiceDomainEventT event, void* event_data[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - dump state +// ================================== +extern void sm_service_domain_dump_state(FILE* fp); +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Initialize +// =============================== +extern SmErrorT sm_service_domain_fsm_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain FSM - Finalize +// ============================= +extern SmErrorT sm_service_domain_fsm_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_FSM_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_initial_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_initial_state.c new file mode 100644 index 00000000..3e746d62 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_initial_state.c @@ -0,0 +1,225 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_initial_state.h" + +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_heartbeat.h" +#include "sm_msg.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_fsm.h" + +// **************************************************************************** +// Service Domain Initial State - Hello Timer +// ========================================== +static bool sm_service_domain_initial_state_hello_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceDomainT* domain; + SmErrorT error; + + domain = sm_service_domain_table_read_by_id( id ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_domain_utils_send_hello( domain->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send hello for service domain (%s), error=%s.", + domain->name, sm_error_str( error ) ); + return( true ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Entry +// ==================================== +SmErrorT sm_service_domain_initial_state_entry( SmServiceDomainT* domain ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != domain->hello_timer_id ) + { + error = sm_timer_deregister( domain->hello_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel hello timer for service domain (%s), " + "error=%s.", domain->name, sm_error_str( error ) ); + } + + domain->hello_timer_id = SM_TIMER_ID_INVALID; + } + + domain->designation = SM_DESIGNATION_TYPE_UNKNOWN; + + sm_msg_disable(); + + sm_heartbeat_disable(); + + error = sm_service_domain_utils_service_domain_disable_self( + domain->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disable own assignments for service domain " + "(%s), error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Exit +// =================================== +SmErrorT sm_service_domain_initial_state_exit( SmServiceDomainT* domain ) +{ + char timer_name[80] = ""; + SmTimerIdT hello_timer_id; + SmErrorT error; + + snprintf( timer_name, sizeof(timer_name), "%s hello", domain->name ); + + error = sm_timer_register( timer_name, domain->hello_interval, + sm_service_domain_initial_state_hello_timer, + domain->id, &hello_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create hello timer for service domain (%s), " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + domain->designation = SM_DESIGNATION_TYPE_UNKNOWN; + domain->hello_timer_id = hello_timer_id; + + error = sm_service_domain_utils_update_own_assignments( domain->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update own assignments for service domain " + "(%s), error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + sm_msg_enable(); + + sm_heartbeat_enable(); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Transition +// ========================================= +SmErrorT sm_service_domain_initial_state_transition( SmServiceDomainT* domain, + SmServiceDomainStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Event Handler +// ============================================ +SmErrorT sm_service_domain_initial_state_event_handler( + SmServiceDomainT* domain, SmServiceDomainEventT event, void* event_data[] ) +{ + bool enabled; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainStateT state; + SmErrorT error; + + error = sm_service_domain_utils_service_domain_enabled( domain->name, + &enabled ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if service domain (%s) is enabled, " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_DOMAIN_EVENT_HELLO_MSG: + case SM_SERVICE_DOMAIN_EVENT_NEIGHBOR_AGEOUT: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_ENABLED: + if( enabled ) + { + if( 0 == domain->priority ) + { + state = SM_SERVICE_DOMAIN_STATE_OTHER; + + snprintf( reason_text, sizeof(reason_text), + "interface enabled, priority is zero" ); + } else { + state = SM_SERVICE_DOMAIN_STATE_WAITING; + + snprintf( reason_text, sizeof(reason_text), + "interface enabled" ); + } + + error = sm_service_domain_fsm_set_state( domain->name, state, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) failed, " + "error=%s.", sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_DISABLED: + case SM_SERVICE_DOMAIN_EVENT_WAIT_EXPIRED: + // Ignore. + break; + + default: + DPRINTFD( "Service Domain (%s) ignoring event (%s).", + domain->name, sm_service_domain_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Initialize +// ========================================= +SmErrorT sm_service_domain_initial_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Finalize +// ======================================= +SmErrorT sm_service_domain_initial_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_initial_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_initial_state.h new file mode 100644 index 00000000..a880a1ed --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_initial_state.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_INITIAL_STATE_H__ +#define __SM_SERVICE_DOMAIN_INITIAL_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Initial State - Entry +// ==================================== +extern SmErrorT sm_service_domain_initial_state_entry( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Exit +// =================================== +extern SmErrorT sm_service_domain_initial_state_exit( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Transition +// ========================================= +extern SmErrorT sm_service_domain_initial_state_transition( + SmServiceDomainT* domain, SmServiceDomainStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Event Handler +// ============================================ +extern SmErrorT sm_service_domain_initial_state_event_handler( + SmServiceDomainT* domain, SmServiceDomainEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Initialize +// ========================================= +extern SmErrorT sm_service_domain_initial_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Initial State - Finalize +// ======================================= +extern SmErrorT sm_service_domain_initial_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_INITIAL_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_api.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_api.c new file mode 100644 index 00000000..4dc14048 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_api.c @@ -0,0 +1,412 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_interface_api.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_hw.h" +#include "sm_node_utils.h" +#include "sm_node_fsm.h" +#include "sm_service_domain_interface_table.h" +#include "sm_service_domain_interface_fsm.h" +#include "sm_log.h" + +static void sm_service_domain_interface_api_send_event( void* user_data[], + SmServiceDomainInterfaceT* interface ); + +// **************************************************************************** +// Service Domain Interface API - Get Hardware Interface +// ===================================================== +static void sm_service_domain_interface_api_get_hw_interface( + SmServiceDomainInterfaceT* interface ) +{ + char net_addr_str[SM_NETWORK_ADDRESS_MAX_CHAR]; + SmErrorT error; + + sm_network_address_str( &(interface->network_address), net_addr_str ); + + if( 0 == strcmp( SM_SERVICE_DOMAIN_MGMT_INTERFACE, + interface->service_domain_interface ) ) + { + error = sm_node_utils_get_mgmt_interface( interface->interface_name ); + if( SM_OKAY == error ) + { + DPRINTFI( "Network address (%s) maps to %s interface from config, " + "type=%s.", net_addr_str, interface->interface_name, + interface->service_domain_interface ); + goto PERSIST; + } + else if( SM_NOT_FOUND != error ) + { + DPRINTFE( "Failed to look up management interface, error=%s.", + sm_error_str(error) ); + return; + } + + } else if( 0 == strcmp( SM_SERVICE_DOMAIN_OAM_INTERFACE, + interface->service_domain_interface ) ) + { + error = sm_node_utils_get_oam_interface( interface->interface_name ); + if( SM_OKAY == error ) + { + DPRINTFI( "Network address (%s) maps to %s interface from config, " + "type=%s.", net_addr_str, interface->interface_name, + interface->service_domain_interface ); + goto PERSIST; + } + else if( SM_NOT_FOUND != error ) + { + DPRINTFE( "Failed to look up oam interface, error=%s.", + sm_error_str(error) ); + return; + } + + } else if( 0 == strcmp( SM_SERVICE_DOMAIN_INFRA_INTERFACE, + interface->service_domain_interface ) ) + { + error = sm_node_utils_get_infra_interface( interface->interface_name ); + if( SM_OKAY == error ) + { + DPRINTFI( "Network address (%s) maps to %s interface from config, " + "type=%s.", net_addr_str, interface->interface_name, + interface->service_domain_interface ); + goto PERSIST; + } + else if( SM_NOT_FOUND != error ) + { + DPRINTFE( "Failed to look up infrastructure interface, error=%s.", + sm_error_str(error) ); + return; + } + } + + error = sm_hw_get_if_by_network_address( &(interface->network_address), + interface->interface_name ); + if( SM_OKAY == error ) + { + DPRINTFI( "Network address (%s) maps to %s interface from kernel, " + "type=%s.", net_addr_str, interface->interface_name, + interface->service_domain_interface ); + goto PERSIST; + + } else { + if( SM_NOT_FOUND == error ) + { + DPRINTFE( "Failed to get interface by network address (%s), " + "error=%s.", net_addr_str, sm_error_str( error ) ); + } else { + DPRINTFE( "Failed to get interface by network address (%s), " + "error=%s.", net_addr_str, sm_error_str( error ) ); + } + return; + } + +PERSIST: + error = sm_service_domain_interface_table_persist( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update service domain (%s) interface (%s), " + "error=%s.", interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return; + } + + if( 0 != strcmp( SM_SERVICE_DOMAIN_OAM_INTERFACE, + interface->service_domain_interface ) ) + { + bool is_aio_sx = false; + error = sm_node_utils_is_aio_simplex(&is_aio_sx); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check for AIO simplex system, error=%s.", + sm_error_str(error) ); + } + + if ( is_aio_sx ) + { + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR]; + SmServiceDomainInterfaceEventT event; + void* user_data[] = { &event, reason_text }; + + event = SM_SERVICE_DOMAIN_INTERFACE_EVENT_NOT_IN_USE; + + snprintf( reason_text, sizeof(reason_text), "%s interface is not in use", + interface->service_domain_interface ); + + sm_service_domain_interface_api_send_event( user_data, interface ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Send Event +// ========================================= +static void sm_service_domain_interface_api_send_event( void* user_data[], + SmServiceDomainInterfaceT* interface ) +{ + const char* reason_text; + SmServiceDomainInterfaceEventT* event; + SmErrorT error; + + event = (SmServiceDomainInterfaceEventT*) user_data[0]; + reason_text = (char*) user_data[1]; + + if( '\0' == interface->interface_name[0] ) + { + if(( SM_NETWORK_TYPE_NIL == interface->network_address.type )|| + ( SM_NETWORK_TYPE_UNKNOWN == interface->network_address.type )) + { + DPRINTFD( "Network address not set for interface yet." ); + return; + } + + sm_service_domain_interface_api_get_hw_interface( interface ); + + } else { + error = sm_service_domain_interface_fsm_event_handler( + interface->service_domain, + interface->service_domain_interface, + *event, NULL, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service domain (%s) " + "interface (%s), error=%s.", + sm_service_domain_interface_event_str( *event ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Node Enabled +// =========================================== +SmErrorT sm_service_domain_interface_api_node_enabled( void ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainInterfaceEventT event; + void* user_data[] = { &event, reason_text }; + + event = SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_ENABLED; + + snprintf( reason_text, sizeof(reason_text), "node enabled" ); + + sm_service_domain_interface_table_foreach( user_data, + sm_service_domain_interface_api_send_event ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Node Disabled +// ============================================ +SmErrorT sm_service_domain_interface_api_node_disabled( void ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainInterfaceEventT event; + void* user_data[] = { &event, reason_text }; + + event = SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_DISABLED; + + snprintf( reason_text, sizeof(reason_text), "node disabled" ); + + sm_service_domain_interface_table_foreach( user_data, + sm_service_domain_interface_api_send_event ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Audit +// ==================================== +SmErrorT sm_service_domain_interface_api_audit( void ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainInterfaceEventT event; + void* user_data[] = { &event, reason_text }; + + event = SM_SERVICE_DOMAIN_INTERFACE_EVENT_AUDIT; + + snprintf( reason_text, sizeof(reason_text), "audit requested" ); + + sm_service_domain_interface_table_foreach( user_data, + sm_service_domain_interface_api_send_event ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Node State Callback +// ================================================== +static void sm_service_domain_interface_api_node_state_callback( + char node_name[], SmNodeReadyStateT ready_state ) +{ + SmErrorT error; + + char hostname[SM_NODE_NAME_MAX_CHAR]; + error = sm_node_utils_get_hostname( hostname ); + if (SM_OKAY != error) + { + DPRINTFE("Failed to find host name, %s", sm_error_str(error)); + return; + } + + if( 0 != strcmp(node_name, hostname) ) + { + DPRINTFD("Node ready state changed for %s, not local host, nothing to do", node_name); + return; + } + if( SM_NODE_READY_STATE_ENABLED == ready_state ) + { + error = sm_service_domain_interface_api_node_enabled( ); + if( SM_OKAY != error ) + { + DPRINTFE( "Notifying interfaces that node (%s) is " + "enabled, error=%s.", node_name, + sm_error_str( error ) ); + return; + } + + } else if( SM_NODE_READY_STATE_DISABLED == ready_state ) { + + error = sm_service_domain_interface_api_node_disabled( ); + if( SM_OKAY != error ) + { + DPRINTFE( "Notifying interfaces that node (%s) is " + "disabled failed, error=%s.", node_name, + sm_error_str( error ) ); + return; + } + + } else { + DPRINTFD( "Ignoring ready state (%s) from node (%s).", + sm_node_ready_state_str( ready_state ), node_name ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - set i/f not in use in aio-sx +// ========================================= +static void _sm_service_domain_interface_set_niu(void* unused_param[], + SmServiceDomainInterfaceT* interface ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR]; + SmServiceDomainInterfaceEventT event; + void* user_data[] = { &event, reason_text }; + + if( 0 == strcmp( SM_SERVICE_DOMAIN_OAM_INTERFACE, + interface->service_domain_interface ) ) + { + // don't change oam i/f + return; + } + + // aio sx i/f other than OAM are not in use + event = SM_SERVICE_DOMAIN_INTERFACE_EVENT_NOT_IN_USE; + + snprintf( reason_text, sizeof(reason_text), "interface %s not in use", + interface->service_domain_interface); + + sm_service_domain_interface_api_send_event( user_data, interface ); +} + +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Initialize +// ========================================= +SmErrorT sm_service_domain_interface_api_initialize( void ) +{ + SmErrorT error; + + error = sm_service_domain_interface_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain interface table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_interface_fsm_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain interface fsm, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_node_fsm_register_callback( + sm_service_domain_interface_api_node_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for node state changes, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + bool is_aio_sx = false; + error = sm_node_utils_is_aio_simplex(&is_aio_sx); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check for AIO simplex system, error=%s.", + sm_error_str(error) ); + return( error ); + } + + if ( is_aio_sx ) + { + sm_service_domain_interface_table_foreach( NULL, + _sm_service_domain_interface_set_niu ); + } + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Finalize +// ======================================= +SmErrorT sm_service_domain_interface_api_finalize( void ) +{ + SmErrorT error; + + error = sm_node_fsm_deregister_callback( + sm_service_domain_interface_api_node_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for node state changes, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_interface_fsm_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain interface fsm, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_interface_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain interface table, " + "error=%s.", sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_api.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_api.h new file mode 100644 index 00000000..c8bc489b --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_api.h @@ -0,0 +1,49 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_INTERFACE_API_H__ +#define __SM_SERVICE_DOMAIN_INTERFACE_API_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Interface API - Node Enabled +// =========================================== +extern SmErrorT sm_service_domain_interface_api_node_enabled( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Node Disabled +// ============================================ +extern SmErrorT sm_service_domain_interface_api_node_disabled( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Audit +// ==================================== +extern SmErrorT sm_service_domain_interface_api_audit( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Initialize +// ========================================= +extern SmErrorT sm_service_domain_interface_api_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface API - Finalize +// ======================================= +extern SmErrorT sm_service_domain_interface_api_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_INTERFACE_API_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_disabled_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_disabled_state.c new file mode 100644 index 00000000..79efe911 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_disabled_state.c @@ -0,0 +1,164 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_interface_disabled_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_hw.h" +#include "sm_log.h" +#include "sm_heartbeat.h" +#include "sm_service_domain_interface_fsm.h" + +// **************************************************************************** +// Service Domain Interface Disabled State - Entry +// =============================================== +SmErrorT sm_service_domain_interface_disabled_state_entry( + SmServiceDomainInterfaceT* interface ) +{ + SmErrorT error; + + error = sm_heartbeat_add_interface( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to add messaging interface for service domain (%s), " + "error=%s.", interface->service_domain, + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Exit +// ============================================== +SmErrorT sm_service_domain_interface_disabled_state_exit( + SmServiceDomainInterfaceT* interface ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Transition +// ==================================================== +SmErrorT sm_service_domain_interface_disabled_state_transition( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Event Handler +// ======================================================= +SmErrorT sm_service_domain_interface_disabled_state_event_handler( + SmServiceDomainInterfaceT* interface, + SmServiceDomainInterfaceEventT event, void* event_data[] ) +{ + bool enabled; + SmErrorT error; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + + error = sm_hw_get_if_state( interface->interface_name, &enabled ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit hardware state of interface (%s), " + "error=%s", interface->interface_name, + sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_ENABLED: + if( enabled ) + { + snprintf( reason_text, sizeof(reason_text), "node and %s " + "enabled", interface->interface_name ); + + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_ENABLED, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) " + "interface (%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_ENABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_ENABLED: + // Ignore. Need the node state before transitioning to enabled. + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_DISABLED: + // Already in this state. + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_AUDIT: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NOT_IN_USE: + snprintf( reason_text, sizeof(reason_text), "interface %s " + "not in use", interface->interface_name ); + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_NOT_IN_USE, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) " + "interface (%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_NOT_IN_USE ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Service domain (%s) interface (%s) ignoring event (%s).", + interface->service_domain, + interface->service_domain_interface, + sm_service_domain_interface_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Initialize +// ==================================================== +SmErrorT sm_service_domain_interface_disabled_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Finalize +// ================================================== +SmErrorT sm_service_domain_interface_disabled_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_disabled_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_disabled_state.h new file mode 100644 index 00000000..80ba61d3 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_disabled_state.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_INTERFACE_DISABLED_STATE_H__ +#define __SM_SERVICE_DOMAIN_INTERFACE_DISABLED_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_interface_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Interface Disabled State - Entry +// =============================================== +extern SmErrorT sm_service_domain_interface_disabled_state_entry( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Exit +// ============================================== +extern SmErrorT sm_service_domain_interface_disabled_state_exit( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Transition +// ==================================================== +extern SmErrorT sm_service_domain_interface_disabled_state_transition( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Event Handler +// ======================================================= +extern SmErrorT sm_service_domain_interface_disabled_state_event_handler( + SmServiceDomainInterfaceT* interface, + SmServiceDomainInterfaceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Initialize +// ==================================================== +extern SmErrorT sm_service_domain_interface_disabled_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Disabled State - Finalize +// ================================================== +extern SmErrorT sm_service_domain_interface_disabled_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_INTERFACE_DISABLED_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_enabled_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_enabled_state.c new file mode 100644 index 00000000..91b187a8 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_enabled_state.c @@ -0,0 +1,286 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_interface_enabled_state.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_msg.h" +#include "sm_hw.h" +#include "sm_log.h" +#include "sm_heartbeat.h" +#include "sm_service_domain_table.h" +#include "sm_service_domain_interface_fsm.h" + +// **************************************************************************** +// Service Domain Interface Enabled State - Entry +// ============================================== +SmErrorT sm_service_domain_interface_enabled_state_entry( + SmServiceDomainInterfaceT* interface ) +{ + SmServiceDomainT* service_domain; + SmErrorT error; + + service_domain = sm_service_domain_table_read( interface->service_domain ); + if( NULL == service_domain ) + { + DPRINTFE( "Service domain (%s) does not exist.", + interface->service_domain ); + return( SM_NOT_FOUND ); + } + + error = sm_msg_add_peer_interface( interface->interface_name, + &(interface->network_peer_address), + interface->network_peer_port, + interface->auth_type, + interface->auth_key ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to add peer messaging interface for service " + "domain (%s), error=%s.", interface->service_domain, + sm_error_str( error ) ); + return( error ); + } + + error = sm_msg_open_sockets( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open sockets on service domain (%s) " + "interface (%s), error=%s", interface->service_domain, + interface->service_domain_interface, sm_error_str( error ) ); + return( error ); + } + + error = sm_heartbeat_add_interface( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to add messaging interface for service domain (%s), " + "error=%s.", interface->service_domain, + sm_error_str( error ) ); + return( error ); + } + + error = sm_heartbeat_add_peer_interface( interface->id, + interface->interface_name, + &(interface->network_peer_address), + interface->network_heartbeat_port, + service_domain->dead_interval ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to add peer messaging interface for service " + "domain (%s), error=%s.", interface->service_domain, + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Exit +// ============================================= +SmErrorT sm_service_domain_interface_enabled_state_exit( + SmServiceDomainInterfaceT* interface ) +{ + SmErrorT error; + + error = sm_heartbeat_delete_peer_interface( interface->interface_name, + &(interface->network_peer_address), + interface->network_heartbeat_port ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to delete peer messaging interface for service " + "domain (%s), error=%s.", interface->service_domain, + sm_error_str( error ) ); + return( error ); + } + + error = sm_msg_delete_peer_interface( interface->interface_name, + &(interface->network_peer_address), + interface->network_peer_port ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to delete peer messaging interface for service " + "domain (%s), error=%s.", interface->service_domain, + sm_error_str( error ) ); + return( error ); + } + + error = sm_msg_close_sockets( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close sockets on service domain (%s) " + "interface (%s), error=%s", interface->service_domain, + interface->service_domain_interface, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Transition +// =================================================== +SmErrorT sm_service_domain_interface_enabled_state_transition( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Event Handler +// ====================================================== +SmErrorT sm_service_domain_interface_enabled_state_event_handler( + SmServiceDomainInterfaceT* interface, + SmServiceDomainInterfaceEventT event, void* event_data[] ) +{ + bool enabled; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + error = sm_hw_get_if_state( interface->interface_name, &enabled ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit hardware state of interface (%s), " + "error=%s", interface->interface_name, + sm_error_str( error ) ); + return( error ); + } + if( !enabled ) + { + DPRINTFI( "Interface %s is disabled", interface->interface_name ); + } + + switch( event ) + { + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_ENABLED: + // Already in this state. + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_DISABLED: + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_DISABLED, + "node disabled" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) interface (%s) " + "failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_DISABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_DISABLED: + if( !enabled ) + { + snprintf( reason_text, sizeof(reason_text), "%s disabled", + interface->interface_name ); + + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_DISABLED, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) interface " + "(%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_DISABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_ENABLED: + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_AUDIT: + if( !enabled ) + { + snprintf( reason_text, sizeof(reason_text), "%s disabled", + interface->interface_name ); + } + + if( !enabled ) + { + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_DISABLED, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) " + "interface (%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_DISABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NOT_IN_USE: + snprintf( reason_text, sizeof(reason_text), "interface %s " + "not in use", interface->interface_name ); + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_NOT_IN_USE, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) " + "interface (%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_ENABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Service domain (%s) interface (%s) ignoring event (%s).", + interface->service_domain, + interface->service_domain_interface, + sm_service_domain_interface_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Initialize +// =================================================== +SmErrorT sm_service_domain_interface_enabled_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Finalize +// ================================================= +SmErrorT sm_service_domain_interface_enabled_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_enabled_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_enabled_state.h new file mode 100644 index 00000000..1a09dc04 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_enabled_state.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_INTERFACE_ENABLED_STATE_H__ +#define __SM_SERVICE_DOMAIN_INTERFACE_ENABLED_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_interface_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Interface Enabled State - Entry +// ============================================== +extern SmErrorT sm_service_domain_interface_enabled_state_entry( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Exit +// ============================================= +extern SmErrorT sm_service_domain_interface_enabled_state_exit( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Transition +// =================================================== +extern SmErrorT sm_service_domain_interface_enabled_state_transition( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Event Handler +// ====================================================== +extern SmErrorT sm_service_domain_interface_enabled_state_event_handler( + SmServiceDomainInterfaceT* interface, + SmServiceDomainInterfaceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Initialize +// =================================================== +extern SmErrorT sm_service_domain_interface_enabled_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Enabled State - Finalize +// ================================================= +extern SmErrorT sm_service_domain_interface_enabled_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_INTERFACE_ENABLED_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_fsm.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_fsm.c new file mode 100644 index 00000000..732828f0 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_fsm.c @@ -0,0 +1,691 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_interface_fsm.h" + +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_service_domain_interface_table.h" +#include "sm_service_domain_interface_unknown_state.h" +#include "sm_service_domain_interface_enabled_state.h" +#include "sm_service_domain_interface_disabled_state.h" +#include "sm_service_domain_interface_not_in_use_state.h" +#include "sm_log.h" + +static char _reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; +static SmListT* _callbacks = NULL; + +// **************************************************************************** +// Service Domain Interface FSM - Register Callback +// ================================================ +SmErrorT sm_service_domain_interface_fsm_register_callback( + SmServiceDomainInterfaceFsmCallbackT callback ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Deregister Callback +// ================================================== +SmErrorT sm_service_domain_interface_fsm_deregister_callback( + SmServiceDomainInterfaceFsmCallbackT callback ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Notify +// ===================================== +static void sm_service_domain_interface_fsm_notify( + SmServiceDomainInterfaceT* interface ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainInterfaceFsmCallbackT callback; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callback = (SmServiceDomainInterfaceFsmCallbackT) entry_data; + + callback( interface->service_domain, + interface->service_domain_interface, + interface->interface_state ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Enter State +// ========================================== +static SmErrorT sm_service_domain_interface_fsm_enter_state( + SmServiceDomainInterfaceT* interface ) +{ + SmErrorT error; + + switch( interface->interface_state ) + { + case SM_INTERFACE_STATE_UNKNOWN: + error = sm_service_domain_interface_unknown_state_entry( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to enter " + "state (%s), error=%s.", interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_ENABLED: + error = sm_service_domain_interface_enabled_state_entry( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to enter " + "state (%s), error=%s.", interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_DISABLED: + error = sm_service_domain_interface_disabled_state_entry( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to enter " + "state (%s), error=%s.", interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service domain (%s) interface (%s) " + "state (%s).", interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Exit State +// ========================================= +static SmErrorT sm_service_domain_interface_fsm_exit_state( + SmServiceDomainInterfaceT* interface ) +{ + SmErrorT error; + + switch( interface->interface_state ) + { + case SM_INTERFACE_STATE_UNKNOWN: + error = sm_service_domain_interface_unknown_state_exit( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to exit " + "state (%s), error=%s.", interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_ENABLED: + error = sm_service_domain_interface_enabled_state_exit( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to exit " + "state (%s), error=%s.", interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_DISABLED: + error = sm_service_domain_interface_disabled_state_exit( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to exit " + "state (%s), error=%s.", interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service domain (%s) interface (%s) state (%s).", + interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Transition State +// =============================================== +static SmErrorT sm_service_domain_interface_fsm_transition_state( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ) +{ + SmErrorT error; + + switch( interface->interface_state ) + { + case SM_INTERFACE_STATE_UNKNOWN: + error = sm_service_domain_interface_unknown_state_transition( + interface, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to " + "transition from state (%s) to state (%s), error=%s.", + interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( from_state ), + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_ENABLED: + error = sm_service_domain_interface_enabled_state_transition( + interface, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to " + "transition from state (%s) to state (%s), error=%s.", + interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( from_state ), + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_DISABLED: + error = sm_service_domain_interface_disabled_state_transition( + interface, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to " + "transition from state (%s) to state (%s), error=%s.", + interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( from_state ), + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_NOT_IN_USE: + error = sm_service_domain_interface_niu_state_transition( + interface, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to " + "transition from state (%s) to state (%s), error=%s.", + interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( from_state ), + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + default: + DPRINTFE( "Unknown service domain (%s) interface (%s) state (%s).", + interface->service_domain, + interface->service_domain_interface, + sm_interface_state_str( interface->interface_state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Set State +// ======================================== +SmErrorT sm_service_domain_interface_fsm_set_state( + char service_domain[], char service_domain_interface[], + SmInterfaceStateT state, const char reason_text[] ) +{ + SmInterfaceStateT prev_state; + SmServiceDomainInterfaceT* interface; + SmErrorT error, error2; + + interface = sm_service_domain_interface_table_read( service_domain, + service_domain_interface ); + if( NULL == interface ) + { + DPRINTFE( "Failed to read service domain (%s) interface (%s), " + "error=%s.", service_domain, service_domain_interface, + sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = interface->interface_state; + + error = sm_service_domain_interface_fsm_exit_state( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to exit state (%s) service domain (%s) " + "interface (%s), error=%s.", + sm_interface_state_str( interface->interface_state ), + service_domain, service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + + interface->interface_state = state; + + error = sm_service_domain_interface_fsm_transition_state( interface, + prev_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to transition to state (%s) service domain (%s) " + "interface (%s), error=%s.", + sm_interface_state_str( interface->interface_state ), + service_domain, service_domain_interface, + sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + error = sm_service_domain_interface_fsm_enter_state( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enter state (%s) service domain (%s) " + "interface (%s), error=%s.", + sm_interface_state_str( interface->interface_state ), + service_domain, service_domain_interface, + sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + if( '\0' != _reason_text[0] ) + { + snprintf( _reason_text, sizeof(_reason_text), "%s", reason_text ); + } + + return( SM_OKAY ); + +STATE_CHANGE_ERROR: + error2 = sm_service_domain_interface_fsm_exit_state( interface ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to exit state (%s) service domain (%s) " + "interface (%s), error=%s.", + sm_interface_state_str( interface->interface_state ), + service_domain, service_domain_interface, + sm_error_str( error2 ) ); + abort(); + } + + interface->interface_state = prev_state; + + error2 = sm_service_domain_interface_fsm_transition_state( interface, + state ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to transition to state (%s) service domain (%s) " + "interface (%s), error=%s.", + sm_interface_state_str( interface->interface_state ), + service_domain, service_domain_interface, + sm_error_str( error2 ) ); + abort(); + } + + error2 = sm_service_domain_interface_fsm_enter_state( interface ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to enter state (%s) service domain (%s) " + "interface (%s), error=%s.", + sm_interface_state_str( interface->interface_state ), + service_domain, service_domain_interface, + sm_error_str( error2 ) ); + abort(); + } + + return( error ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Event Handler +// ============================================ +SmErrorT sm_service_domain_interface_fsm_event_handler( + char service_domain[], char service_domain_interface[], + SmServiceDomainInterfaceEventT event, void* event_data[], + const char reason_text[] ) +{ + SmInterfaceStateT prev_state; + SmServiceDomainInterfaceT* interface; + SmErrorT error; + + snprintf( _reason_text, sizeof(_reason_text), "%s", reason_text ); + + interface = sm_service_domain_interface_table_read( service_domain, + service_domain_interface ); + if( NULL == interface ) + { + DPRINTFE( "Failed to read service domain (%s) interface (%s), " + "error=%s.", service_domain, service_domain_interface, + sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = interface->interface_state; + + switch( interface->interface_state ) + { + case SM_INTERFACE_STATE_UNKNOWN: + error = sm_service_domain_interface_unknown_state_event_handler( + interface, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to handle " + "event (%s) in state (%s), error=%s.", service_domain, + service_domain_interface, + sm_service_domain_interface_event_str( event ), + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_ENABLED: + error = sm_service_domain_interface_enabled_state_event_handler( + interface, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to handle " + "event (%s) in state (%s), error=%s.", service_domain, + service_domain_interface, + sm_service_domain_interface_event_str( event ), + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_DISABLED: + error = sm_service_domain_interface_disabled_state_event_handler( + interface, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to handle " + "event (%s) in state (%s), error=%s.", service_domain, + service_domain_interface, + sm_service_domain_interface_event_str( event ), + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_INTERFACE_STATE_NOT_IN_USE: + error = sm_service_domain_interface_niu_state_event_handler( + interface, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) interface (%s) unable to handle " + "event (%s) in state (%s), error=%s.", service_domain, + service_domain_interface, + sm_service_domain_interface_event_str( event ), + sm_interface_state_str( interface->interface_state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown state (%s) for service domain (%s) " + "interface (%s).", + sm_interface_state_str( interface->interface_state ), + service_domain, service_domain_interface ); + break; + } + + if( prev_state != interface->interface_state ) + { + DPRINTFI( "Service domain (%s) interface (%s) received event (%s) was " + "in the %s state and is now in the %s.", service_domain, + service_domain_interface, + sm_service_domain_interface_event_str( event ), + sm_interface_state_str( prev_state ), + sm_interface_state_str( interface->interface_state ) ); + + error = sm_service_domain_interface_table_persist( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service domain (%s) interface (%s) " + "data, error=%s.", service_domain, + service_domain_interface, sm_error_str( error ) ); + return( error ); + } + + sm_log_interface_state_change( service_domain_interface, + sm_interface_state_str( prev_state ), + sm_interface_state_str( interface->interface_state ), + _reason_text ); + + sm_service_domain_interface_fsm_notify( interface ); + + } else if( SM_SERVICE_DOMAIN_INTERFACE_EVENT_AUDIT == event ) { + sm_service_domain_interface_fsm_notify( interface ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// service domain interface - dump ipv4 addr +// ================================================================== +static void _sm_service_domain_interface_dump_ipv4_addr(const struct in_addr& sin, FILE* fp) +{ + char str[INET_ADDRSTRLEN]; + + if(NULL == fp) return; + if( 0 == sin.s_addr ) + { + str[0] = '\0'; + }else + { + inet_ntop(AF_INET, &sin, str, sizeof(str)); + } + fprintf(fp, "%s\n", str); +} +// **************************************************************************** + +// **************************************************************************** +// service domain interface - dump interface ipv6 +// ================================================================== +static void _sm_service_domain_interface_dump_network_ipv4( + SmServiceDomainInterfaceT* interface, + FILE* fp ) +{ + if(NULL == fp) return; + + fprintf( fp, " IP Address: " ); + _sm_service_domain_interface_dump_ipv4_addr(interface->network_address.u.ipv4.sin, fp); + fprintf( fp, " Multicast: " ); + _sm_service_domain_interface_dump_ipv4_addr(interface->network_multicast.u.ipv4.sin, fp); + fprintf( fp, " Peer IP: " ); + _sm_service_domain_interface_dump_ipv4_addr(interface->network_peer_address.u.ipv4.sin, fp); +} +// **************************************************************************** + +// **************************************************************************** +// service domain interface - dump interface ipv6 +// ================================================================== +static void _sm_service_domain_interface_dump_network_ipv6( + SmServiceDomainInterfaceT* interface, + FILE* fp ) +{ + char str[INET_ADDRSTRLEN]; + if(NULL == fp) return; + + inet_ntop(AF_INET, &(interface->network_address.u.ipv6.sin6), str, sizeof(str)); + fprintf( fp, " IP Address: %s\n", str ); + inet_ntop(AF_INET, &(interface->network_multicast.u.ipv6.sin6), str, sizeof(str)); + fprintf( fp, " Multicast: %s\n", str ); + inet_ntop(AF_INET, &(interface->network_peer_address.u.ipv6.sin6), str, sizeof(str)); + fprintf( fp, " Peer IP: %s\n", str ); +} +// **************************************************************************** + +// **************************************************************************** +// service domain interface - dump interface state +// ================================================================== +static void _sm_service_domain_interface_dump_if_state(void* user_data[], + SmServiceDomainInterfaceT* interface) +{ + FILE* fp = (FILE*)user_data[0]; + if(NULL == fp) return; + + fprintf( fp, " Interface %s(%s): %s\n", + interface->service_domain_interface, + interface->interface_name, + sm_interface_state_str(interface->interface_state) ); + fprintf( fp, " Network Type: %s\n", sm_network_type_str(interface->network_type)); + if( interface->network_type == SM_NETWORK_TYPE_IPV4 || interface->network_type == SM_NETWORK_TYPE_IPV4_UDP ) + { + _sm_service_domain_interface_dump_network_ipv4( interface, fp ); + }else if ( interface->network_type == SM_NETWORK_TYPE_IPV6 + || interface->network_type == SM_NETWORK_TYPE_IPV6_UDP ) + { + _sm_service_domain_interface_dump_network_ipv6( interface, fp ); + } +} +// **************************************************************************** + +// **************************************************************************** +// service domain interface - dump interface state +// ================================================================== +void sm_service_domain_interface_dump_state(FILE* fp) +{ + fprintf( fp, "\nService Domain Interfaces\n"); + void* user_data[1] = {fp}; + sm_service_domain_interface_table_foreach( + user_data, + _sm_service_domain_interface_dump_if_state + ); + + + fprintf( fp, "\n" ); +} +// **************************************************************************** + + +// **************************************************************************** +// Service Domain Interface FSM - Initialize +// ========================================= +SmErrorT sm_service_domain_interface_fsm_initialize( void ) +{ + SmErrorT error; + + error = sm_service_domain_interface_unknown_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain interface unknown " + "state module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_interface_enabled_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain interface enabled " + "state module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_interface_disabled_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain interface disabled " + "state module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_interface_niu_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain interface not in use " + "state module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Finalize +// ======================================= +SmErrorT sm_service_domain_interface_fsm_finalize( void ) +{ + SmErrorT error; + + error = sm_service_domain_interface_unknown_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain interface unknown " + "state module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_interface_enabled_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain interface enabled " + "state module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_interface_disabled_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain interface disabled " + "state module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_interface_niu_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain interface not in use " + "state module, error=%s.", sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_fsm.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_fsm.h new file mode 100644 index 00000000..8e6761e7 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_fsm.h @@ -0,0 +1,65 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_INTERFACE_FSM_H__ +#define __SM_SERVICE_DOMAIN_INTERFACE_FSM_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmServiceDomainInterfaceFsmCallbackT) (char service_domain[], + char service_domain_interface[], SmInterfaceStateT interface_state); + +// **************************************************************************** +// Service Domain Interface FSM - Register Callback +// ================================================ +extern SmErrorT sm_service_domain_interface_fsm_register_callback( + SmServiceDomainInterfaceFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Deregister Callback +// ================================================== +extern SmErrorT sm_service_domain_interface_fsm_deregister_callback( + SmServiceDomainInterfaceFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Set State +// ======================================== +extern SmErrorT sm_service_domain_interface_fsm_set_state( + char service_domain[], char service_domain_interface[], + SmInterfaceStateT state, const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Event Handler +// ============================================ +extern SmErrorT sm_service_domain_interface_fsm_event_handler( + char service_domain[], char service_domain_interface[], + SmServiceDomainInterfaceEventT event, void* event_data[], + const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Initialize +// ========================================= +extern SmErrorT sm_service_domain_interface_fsm_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface FSM - Finalize +// ======================================= +extern SmErrorT sm_service_domain_interface_fsm_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_INTERFACE_FSM_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_not_in_use_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_not_in_use_state.c new file mode 100644 index 00000000..25c850ea --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_not_in_use_state.c @@ -0,0 +1,97 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_interface_not_in_use_state.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_msg.h" +#include "sm_log.h" +#include "sm_service_domain_interface_fsm.h" + +// **************************************************************************** +// Service Domain Interface Not In Use State - Entry +// ============================================== +SmErrorT sm_service_domain_interface_niu_state_entry( + SmServiceDomainInterfaceT* interface ) +{ + DPRINTFI("Interface (%s) is not in use.", interface->service_domain_interface); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Exit +// ============================================= +SmErrorT sm_service_domain_interface_unsued_state_exit( + SmServiceDomainInterfaceT* interface ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Transition +// =================================================== +SmErrorT sm_service_domain_interface_niu_state_transition( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Event Handler +// ====================================================== +SmErrorT sm_service_domain_interface_niu_state_event_handler( + SmServiceDomainInterfaceT* interface, + SmServiceDomainInterfaceEventT event, void* event_data[] ) +{ + switch( event ) + { + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_ENABLED: + // undefined behavior + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_DISABLED: + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_DISABLED: + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_ENABLED: + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_AUDIT: + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NOT_IN_USE: + // don't care, ignore these events + break; + + default: + DPRINTFD( "Service domain (%s) interface (%s) ignoring event (%s).", + interface->service_domain, + interface->service_domain_interface, + sm_service_domain_interface_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Initialize +// =================================================== +SmErrorT sm_service_domain_interface_niu_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Finalize +// ================================================= +SmErrorT sm_service_domain_interface_niu_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_not_in_use_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_not_in_use_state.h new file mode 100644 index 00000000..a4ad30b7 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_not_in_use_state.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_INTERFACE_NOT_IN_USE_STATE_H__ +#define __SM_SERVICE_DOMAIN_INTERFACE_NOT_IN_USE_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_interface_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Interface Not In Use State - Entry +// ============================================== +extern SmErrorT sm_service_domain_interface_niu_state_entry( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Exit +// ============================================= +extern SmErrorT sm_service_domain_interface_niu_state_exit( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Transition +// =================================================== +extern SmErrorT sm_service_domain_interface_niu_state_transition( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Event Handler +// ====================================================== +extern SmErrorT sm_service_domain_interface_niu_state_event_handler( + SmServiceDomainInterfaceT* interface, + SmServiceDomainInterfaceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Initialize +// =================================================== +extern SmErrorT sm_service_domain_interface_niu_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Not In Use State - Finalize +// ================================================= +extern SmErrorT sm_service_domain_interface_niu_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_INTERFACE_NOT_IN_USE_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_table.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_table.c new file mode 100644 index 00000000..e29035de --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_table.c @@ -0,0 +1,325 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_interface_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_domain_interfaces.h" + +static SmListT* _service_domain_interfaces = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Domain Interface Table - Read +// ===================================== +SmServiceDomainInterfaceT* sm_service_domain_interface_table_read( + char service_domain_name[], char service_domain_interface_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainInterfaceT* interface; + + SM_LIST_FOREACH( _service_domain_interfaces, entry, entry_data ) + { + interface = (SmServiceDomainInterfaceT*) entry_data; + + if(( 0 == strcmp( service_domain_name, interface->service_domain ) )&& + ( 0 == strcmp( service_domain_interface_name, + interface->service_domain_interface ) )) + { + return( interface ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Read By Identifier +// =================================================== +SmServiceDomainInterfaceT* sm_service_domain_interface_table_read_by_id( + int64_t id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainInterfaceT* interface; + + SM_LIST_FOREACH( _service_domain_interfaces, entry, entry_data ) + { + interface = (SmServiceDomainInterfaceT*) entry_data; + + if( id == interface->id ) + { + return( interface ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - For Each +// ========================================= +void sm_service_domain_interface_table_foreach( void* user_data[], + SmServiceDomainInterfaceTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + + SM_LIST_FOREACH( _service_domain_interfaces, entry, entry_data ) + { + callback( user_data, (SmServiceDomainInterfaceT*) entry_data ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - For Each Service Domain +// ======================================================== +void sm_service_domain_interface_table_foreach_service_domain( + char service_domain_name[], void* user_data[], + SmServiceDomainInterfaceTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainInterfaceT* interface; + + SM_LIST_FOREACH( _service_domain_interfaces, entry, entry_data ) + { + interface = (SmServiceDomainInterfaceT*) entry_data; + + if( 0 == strcmp( service_domain_name, interface->service_domain ) ) + { + callback( user_data, interface ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Add +// ==================================== +static SmErrorT sm_service_domain_interface_table_add( void* user_data[], + void* record ) +{ + SmServiceDomainInterfaceT* interface; + SmDbServiceDomainInterfaceT* db_interface; + + db_interface = (SmDbServiceDomainInterfaceT*) record; + + interface = sm_service_domain_interface_table_read( + db_interface->service_domain, + db_interface->service_domain_interface ); + if( NULL == interface ) + { + interface = (SmServiceDomainInterfaceT*) + malloc( sizeof(SmServiceDomainInterfaceT) ); + if( NULL == interface ) + { + DPRINTFE( "Failed to allocate service domain interface table " + "entry." ); + return( SM_FAILED ); + } + + memset( interface, 0, sizeof(SmServiceDomainInterfaceT) ); + + interface->id = db_interface->id; + snprintf( interface->service_domain, + sizeof(interface->service_domain), "%s", + db_interface->service_domain ); + snprintf( interface->service_domain_interface, + sizeof(interface->service_domain_interface), "%s", + db_interface->service_domain_interface ); + interface->path_type = db_interface->path_type; + interface->auth_type = db_interface->auth_type; + snprintf( interface->auth_key, sizeof(interface->auth_key), "%s", + db_interface->auth_key ); + snprintf( interface->interface_name, + sizeof(interface->interface_name), "%s", + db_interface->interface_name ); + interface->interface_state = db_interface->interface_state; + interface->network_type = db_interface->network_type; + interface->network_multicast = db_interface->network_multicast; + interface->network_address = db_interface->network_address; + interface->network_port = db_interface->network_port; + interface->network_heartbeat_port = db_interface->network_heartbeat_port; + interface->network_peer_address = db_interface->network_peer_address; + interface->network_peer_port = db_interface->network_peer_port; + interface->network_peer_heartbeat_port + = db_interface->network_peer_heartbeat_port; + interface->unicast_socket = -1; + interface->multicast_socket = -1; + interface->interface_connect_type = db_interface->interface_connect_type; + interface->interface_type = sm_get_interface_type(interface->service_domain_interface); + + SM_LIST_PREPEND( _service_domain_interfaces, + (SmListEntryDataPtrT) interface ); + + } else { + interface->id = db_interface->id; + interface->path_type = db_interface->path_type; + interface->auth_type = db_interface->auth_type; + snprintf( interface->auth_key, sizeof(interface->auth_key), "%s", + db_interface->auth_key ); + snprintf( interface->interface_name, + sizeof(interface->interface_name), "%s", + db_interface->interface_name ); + interface->interface_state = db_interface->interface_state; + interface->network_type = db_interface->network_type; + interface->network_multicast = db_interface->network_multicast; + interface->network_address = db_interface->network_address; + interface->network_port = db_interface->network_port; + interface->network_heartbeat_port = db_interface->network_heartbeat_port; + interface->network_peer_address = db_interface->network_peer_address; + interface->network_peer_port = db_interface->network_peer_port; + interface->network_peer_heartbeat_port + = db_interface->network_peer_heartbeat_port; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Load +// ===================================== +SmErrorT sm_service_domain_interface_table_load( void ) +{ + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbServiceDomainInterfaceT interface; + SmErrorT error; + + snprintf( db_query, sizeof(db_query), "%s = 'yes'", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PROVISIONED ); + + error = sm_db_foreach( SM_DATABASE_NAME, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME, + db_query, &interface, + sm_db_service_domain_interfaces_convert, + sm_service_domain_interface_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service domain interfaces in " + "database, error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Persist +// ======================================== +SmErrorT sm_service_domain_interface_table_persist( + SmServiceDomainInterfaceT* interface ) +{ + SmDbServiceDomainInterfaceT db_interface; + SmErrorT error; + + memset( &db_interface, 0, sizeof(db_interface) ); + + db_interface.id = interface->id; + snprintf( db_interface.service_domain, + sizeof(db_interface.service_domain), "%s", + interface->service_domain ); + snprintf( db_interface.service_domain_interface, + sizeof(db_interface.service_domain_interface), "%s", + interface->service_domain_interface ); + db_interface.path_type = interface->path_type; + db_interface.auth_type = interface->auth_type; + snprintf( db_interface.auth_key, sizeof(db_interface.auth_key), "%s", + interface->auth_key ); + snprintf( db_interface.interface_name, + sizeof(db_interface.interface_name), "%s", + interface->interface_name ); + db_interface.interface_state = interface->interface_state; + db_interface.network_type = interface->network_type; + db_interface.network_multicast = interface->network_multicast; + db_interface.network_address = interface->network_address; + db_interface.network_port = interface->network_port; + db_interface.network_heartbeat_port = interface->network_heartbeat_port; + db_interface.network_peer_address = interface->network_peer_address; + db_interface.network_peer_port = interface->network_peer_port; + db_interface.network_peer_heartbeat_port + = interface->network_peer_heartbeat_port; + + error = sm_db_service_domain_interfaces_update( _sm_db_handle, + &db_interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Initialize +// =========================================== +SmErrorT sm_service_domain_interface_table_initialize( void ) +{ + SmErrorT error; + + _service_domain_interfaces = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_interface_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service domain interfaces from database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Finalize +// ========================================= +SmErrorT sm_service_domain_interface_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_domain_interfaces ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_table.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_table.h new file mode 100644 index 00000000..957258f9 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_table.h @@ -0,0 +1,104 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_INTERFACE_TABLE_H__ +#define __SM_SERVICE_DOMAIN_INTERFACE_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int64_t id; + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char service_domain_interface[SM_SERVICE_DOMAIN_INTERFACE_NAME_MAX_CHAR]; + SmPathTypeT path_type; + SmAuthTypeT auth_type; + char auth_key[SM_AUTHENTICATION_KEY_MAX_CHAR]; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmInterfaceStateT interface_state; + SmNetworkTypeT network_type; + SmNetworkAddressT network_multicast; + SmNetworkAddressT network_address; + int network_port; + int network_heartbeat_port; + SmNetworkAddressT network_peer_address; + int network_peer_port; + int network_peer_heartbeat_port; + int unicast_socket; + int multicast_socket; + SmServiceDomainInterfaceConnectTypeT interface_connect_type; + SmInterfaceTypeT interface_type; +} SmServiceDomainInterfaceT; + +typedef void (*SmServiceDomainInterfaceTableForEachCallbackT) + (void* user_data[], SmServiceDomainInterfaceT* interface); + +// **************************************************************************** +// Service Domain Interface Table - Read +// ===================================== +extern SmServiceDomainInterfaceT* +sm_service_domain_interface_table_read( char service_domain_name[], + char service_domain_interface_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Read By Identifier +// =================================================== +extern SmServiceDomainInterfaceT* +sm_service_domain_interface_table_read_by_id( int64_t id ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - For Each +// ========================================= +extern void sm_service_domain_interface_table_foreach( void* user_data[], + SmServiceDomainInterfaceTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - For Each Service Domain +// ======================================================== +extern void sm_service_domain_interface_table_foreach_service_domain( + char service_domain_name[], void* user_data[], + SmServiceDomainInterfaceTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Load +// ===================================== +extern SmErrorT sm_service_domain_interface_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Persist +// ======================================== +extern SmErrorT sm_service_domain_interface_table_persist( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Initialize +// =========================================== +extern SmErrorT sm_service_domain_interface_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Table - Finalize +// ========================================= +extern SmErrorT sm_service_domain_interface_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_INTERFACE_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_unknown_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_unknown_state.c new file mode 100644 index 00000000..a63f3f3f --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_unknown_state.c @@ -0,0 +1,227 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_interface_unknown_state.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_hw.h" +#include "sm_log.h" +#include "sm_heartbeat.h" +#include "sm_service_domain_interface_fsm.h" + +// **************************************************************************** +// Service Domain Interface Unknown State - Entry +// ============================================== +SmErrorT sm_service_domain_interface_unknown_state_entry( + SmServiceDomainInterfaceT* interface ) +{ + SmErrorT error; + + error = sm_heartbeat_add_interface( interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to add messaging interface for service domain (%s), " + "error=%s.", interface->service_domain, + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Exit +// ============================================= +SmErrorT sm_service_domain_interface_unknown_state_exit( + SmServiceDomainInterfaceT* interface ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Transition +// =================================================== +SmErrorT sm_service_domain_interface_unknown_state_transition( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Event Handler +// ====================================================== +SmErrorT sm_service_domain_interface_unknown_state_event_handler( + SmServiceDomainInterfaceT* interface, SmServiceDomainInterfaceEventT event, + void* event_data[] ) +{ + bool enabled; + SmErrorT error; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = {0}; + + error = sm_hw_get_if_state( interface->interface_name, &enabled ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit hardware state of interface (%s), " + "error=%s", interface->interface_name, + sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_ENABLED: + if( enabled ) + { + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + + snprintf( reason_text, sizeof(reason_text), "node and %s " + "enabled", interface->interface_name ); + + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_ENABLED, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) interface " + "(%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_ENABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_ENABLED: + // Ignore. Need the node state before transitioning to enabled. + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_DISABLED: + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_DISABLED, + "node disabled" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) interface (%s) " + "failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_DISABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_DISABLED: + if( !enabled ) + { + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + + snprintf( reason_text, sizeof(reason_text), "%s disabled", + interface->interface_name ); + + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_DISABLED, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) interface " + "(%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_DISABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_AUDIT: + if( !enabled ) + { + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + + snprintf( reason_text, sizeof(reason_text), "%s disabled", + interface->interface_name ); + + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_DISABLED, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) " + "interface (%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_DISABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_INTERFACE_EVENT_NOT_IN_USE: + error = sm_service_domain_interface_fsm_set_state( + interface->service_domain, + interface->service_domain_interface, + SM_INTERFACE_STATE_NOT_IN_USE, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) " + "interface (%s) failed, error=%s.", + sm_interface_state_str( SM_INTERFACE_STATE_ENABLED ), + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Service domain (%s) interface (%s) ignoring event (%s).", + interface->service_domain, + interface->service_domain_interface, + sm_service_domain_interface_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Initialize +// =================================================== +SmErrorT sm_service_domain_interface_unknown_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Finalize +// ================================================= +SmErrorT sm_service_domain_interface_unknown_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_unknown_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_unknown_state.h new file mode 100644 index 00000000..8b7f051e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_interface_unknown_state.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_INTERFACE_UNKNOWN_STATE_H__ +#define __SM_SERVICE_DOMAIN_INTERFACE_UNKNOWN_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_interface_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Interface Unknown State - Entry +// ============================================== +extern SmErrorT sm_service_domain_interface_unknown_state_entry( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Exit +// ============================================= +extern SmErrorT sm_service_domain_interface_unknown_state_exit( + SmServiceDomainInterfaceT* interface ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Transition +// =================================================== +extern SmErrorT sm_service_domain_interface_unknown_state_transition( + SmServiceDomainInterfaceT* interface, SmInterfaceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Event Handler +// ====================================================== +extern SmErrorT sm_service_domain_interface_unknown_state_event_handler( + SmServiceDomainInterfaceT* interface, + SmServiceDomainInterfaceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Initialize +// =================================================== +extern SmErrorT sm_service_domain_interface_unknown_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Unknown State - Finalize +// ================================================= +extern SmErrorT sm_service_domain_interface_unknown_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_INTERFACE_UNKNOWN_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_leader_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_leader_state.c new file mode 100644 index 00000000..99e439f9 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_leader_state.c @@ -0,0 +1,218 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_leader_state.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_node_api.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_fsm.h" + +// **************************************************************************** +// Service Domain Leader State - Entry +// =================================== +SmErrorT sm_service_domain_leader_state_entry( SmServiceDomainT* domain ) +{ + domain->designation = SM_DESIGNATION_TYPE_LEADER; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Exit +// ================================== +SmErrorT sm_service_domain_leader_state_exit( SmServiceDomainT* domain ) +{ + domain->designation = SM_DESIGNATION_TYPE_UNKNOWN; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Transition +// ======================================== +SmErrorT sm_service_domain_leader_state_transition( SmServiceDomainT* domain, + SmServiceDomainStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Event Handler +// =========================================== +SmErrorT sm_service_domain_leader_state_event_handler( SmServiceDomainT* domain, + SmServiceDomainEventT event, void* event_data[] ) +{ + bool enabled; + char* neighbor_name = NULL; + char* leader_name = NULL; + char hostname[SM_NODE_NAME_MAX_CHAR]; + int generation = 0; + int priority = 0; + SmServiceDomainStateT state = SM_SERVICE_DOMAIN_STATE_NIL; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_utils_service_domain_enabled( domain->name, + &enabled ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if service domain (%s) is enabled, " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_DOMAIN_EVENT_HELLO_MSG: + neighbor_name + = (char*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_NODE_NAME]; + generation + = *(int*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_GENERATION]; + priority + = *(int*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_PRIORITY]; + leader_name + = (char*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_LEADER]; + + if(( '\0' != leader_name[0] )&& + ( 0 != strcmp( leader_name, domain->leader ) )) + { + DPRINTFI( "Service domain (%s) node name (%s) leader (%s) " + "does not match neighbor (%s) leader (%s).", + domain->name, hostname, domain->leader, + neighbor_name, leader_name ); + + state = SM_SERVICE_DOMAIN_STATE_WAITING; + + snprintf( reason_text, sizeof(reason_text), + "leader mismatch with %s neighbor", neighbor_name ); + + } else if( generation > domain->generation ) { + DPRINTFI( "Service domain (%s) node name (%s) generation (%i) " + "less than neighbor (%s) generation (%i).", + domain->name, hostname, domain->generation, + neighbor_name, generation ); + + state = SM_SERVICE_DOMAIN_STATE_WAITING; + + snprintf( reason_text, sizeof(reason_text), + "preempted by %s neighbor", neighbor_name ); + + } else if(( generation == domain->generation )&&( domain->preempt )) { + if( priority > domain->priority ) + { + DPRINTFI( "Service domain (%s) node name (%s) priority (%i) " + "less than neighbor (%s) priority (%i).", + domain->name, hostname, domain->priority, + neighbor_name, priority ); + + state = SM_SERVICE_DOMAIN_STATE_WAITING; + + snprintf( reason_text, sizeof(reason_text), + "preempted by %s neighbor", neighbor_name ); + + } else if( priority == domain->priority ) { + if( 0 < strcmp( neighbor_name, hostname ) ) + { + DPRINTFI( "Service domain (%s) node name (%s) priority " + "(%i) equal to neighbor (%s) priority (%i), " + "using names as tie breaker.", + domain->name, hostname, domain->priority, + neighbor_name, priority ); + + state = SM_SERVICE_DOMAIN_STATE_WAITING; + + snprintf( reason_text, sizeof(reason_text), + "preempted by %s neighbor", neighbor_name ); + } + } + } + + if( SM_SERVICE_DOMAIN_STATE_NIL != state ) + { + error = sm_service_domain_fsm_set_state( domain->name, state, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) failed, " + "error=%s.", sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_NEIGHBOR_AGEOUT: + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_ENABLED: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_DISABLED: + if( !enabled ) + { + state = SM_SERVICE_DOMAIN_STATE_INITIAL; + + snprintf( reason_text, sizeof(reason_text), + "primary interface disabled" ); + + error = sm_service_domain_fsm_set_state( domain->name, state, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) failed, " + "error=%s.", sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_WAIT_EXPIRED: + // Ignore. + break; + + default: + DPRINTFD( "Service Domain (%s) ignoring event (%s).", + domain->name, sm_service_domain_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Initialize +// ======================================== +SmErrorT sm_service_domain_leader_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Finalize +// ====================================== +SmErrorT sm_service_domain_leader_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_leader_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_leader_state.h new file mode 100644 index 00000000..0927372e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_leader_state.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_LEADER_STATE_H__ +#define __SM_SERVICE_DOMAIN_LEADER_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Leader State - Entry +// =================================== +extern SmErrorT sm_service_domain_leader_state_entry( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Exit +// ================================== +extern SmErrorT sm_service_domain_leader_state_exit( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Transition +// ======================================== +extern SmErrorT sm_service_domain_leader_state_transition( + SmServiceDomainT* domain, SmServiceDomainStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Event Handler +// =========================================== +extern SmErrorT sm_service_domain_leader_state_event_handler( + SmServiceDomainT* domain, SmServiceDomainEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Initialize +// ======================================== +extern SmErrorT sm_service_domain_leader_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Leader State - Finalize +// ====================================== +extern SmErrorT sm_service_domain_leader_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_LEADER_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_member_table.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_member_table.c new file mode 100644 index 00000000..63129a2c --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_member_table.c @@ -0,0 +1,308 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_member_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_domain_members.h" + +static SmListT* _service_domain_members = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Domain Member Table - Read +// ================================== +SmServiceDomainMemberT* sm_service_domain_member_table_read( char name[], + char service_group_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainMemberT* member; + + SM_LIST_FOREACH( _service_domain_members, entry, entry_data ) + { + member = (SmServiceDomainMemberT*) entry_data; + + if(( 0 == strcmp( name, member->name ) )&& + ( 0 == strcmp( service_group_name, member->service_group_name ) )) + { + return( member ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Read By Identifier +// ================================================ +SmServiceDomainMemberT* sm_service_domain_member_table_read_by_id( int64_t id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainMemberT* member; + + SM_LIST_FOREACH( _service_domain_members, entry, entry_data ) + { + member = (SmServiceDomainMemberT*) entry_data; + + if( id == member->id ) + { + return( member ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Read Service Group +// ================================================ +SmServiceDomainMemberT* sm_service_domain_member_table_read_service_group( + char service_group_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainMemberT* member; + + SM_LIST_FOREACH( _service_domain_members, entry, entry_data ) + { + member = (SmServiceDomainMemberT*) entry_data; + + if( 0 == strcmp( service_group_name, member->service_group_name ) ) + { + return( member ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Count +// =================================== +unsigned int sm_service_domain_member_table_count( char service_domain_name[] ) +{ + unsigned int count = 0; + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainMemberT* member; + + SM_LIST_FOREACH( _service_domain_members, entry, entry_data ) + { + member = (SmServiceDomainMemberT*) entry_data; + + if( 0 == strcmp( service_domain_name, member->name ) ) + { + ++count; + } + } + + return( count ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - For Each +// ====================================== +void sm_service_domain_member_table_foreach( char service_domain_name[], + void* user_data[], SmServiceDomainMemberTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainMemberT* member; + + SM_LIST_FOREACH( _service_domain_members, entry, entry_data ) + { + member = (SmServiceDomainMemberT*) entry_data; + + if( 0 == strcmp( service_domain_name, member->name ) ) + { + callback( user_data, member ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - For Each Service Group Aggregate +// ============================================================== +void sm_service_domain_member_table_foreach_service_group_aggregate( + char service_domain_name[], char service_group_aggregate[], + void* user_data[], SmServiceDomainMemberTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainMemberT* member; + + SM_LIST_FOREACH( _service_domain_members, entry, entry_data ) + { + member = (SmServiceDomainMemberT*) entry_data; + + if(( 0 == strcmp( service_domain_name, member->name ) )&& + ( 0 == strcmp( service_group_aggregate, + member->service_group_aggregate ) )) + { + callback( user_data, member ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Add +// ================================= +static SmErrorT sm_service_domain_member_table_add( void* user_data[], + void* record ) +{ + SmServiceDomainMemberT* member; + SmDbServiceDomainMemberT* db_member; + + db_member = (SmDbServiceDomainMemberT*) record; + + member = sm_service_domain_member_table_read( db_member->name, + db_member->service_group_name ); + if( NULL == member ) + { + member = (SmServiceDomainMemberT*) + malloc( sizeof(SmServiceDomainMemberT) ); + if( NULL == member ) + { + DPRINTFE( "Failed to allocate service domain member table entry." ); + return( SM_FAILED ); + } + + memset( member, 0, sizeof(SmServiceDomainMemberT) ); + + member->id = db_member->id; + snprintf( member->name, sizeof(member->name), + "%s", db_member->name ); + snprintf( member->service_group_name, + sizeof(member->service_group_name), + "%s", db_member->service_group_name ); + member->redundancy_model = db_member->redundancy_model; + member->n_active = db_member->n_active; + member->m_standby = db_member->m_standby; + snprintf( member->service_group_aggregate, + sizeof(member->service_group_aggregate), + "%s", db_member->service_group_aggregate ); + snprintf( member->active_only_if_active, + sizeof(member->active_only_if_active), + "%s", db_member->active_only_if_active ); + member->redundancy_log_text[0] = '\0'; + + SM_LIST_PREPEND( _service_domain_members, + (SmListEntryDataPtrT) member ); + } else { + member->id = db_member->id; + member->redundancy_model = db_member->redundancy_model; + member->n_active = db_member->n_active; + member->m_standby = db_member->m_standby; + snprintf( member->service_group_aggregate, + sizeof(member->service_group_aggregate), + "%s", db_member->service_group_aggregate ); + snprintf( member->active_only_if_active, + sizeof(member->active_only_if_active), + "%s", db_member->active_only_if_active ); + member->redundancy_log_text[0] = '\0'; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Load +// ================================== +SmErrorT sm_service_domain_member_table_load( void ) +{ + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbServiceDomainMemberT member; + SmErrorT error; + + snprintf( db_query, sizeof(db_query), "%s = 'yes'", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_PROVISIONED ); + + error = sm_db_foreach( SM_DATABASE_NAME, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME, + db_query, &member, + sm_db_service_domain_members_convert, + sm_service_domain_member_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service domain members in " + "database, error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Initialize +// ======================================== +SmErrorT sm_service_domain_member_table_initialize( void ) +{ + SmErrorT error; + + _service_domain_members = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_member_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service domain members from database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Finalize +// ====================================== +SmErrorT sm_service_domain_member_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_domain_members ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_member_table.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_member_table.h new file mode 100644 index 00000000..816ddfde --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_member_table.h @@ -0,0 +1,100 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_MEMBER_TABLE_H__ +#define __SM_SERVICE_DOMAIN_MEMBER_TABLE_H__ + +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int64_t id; + char name[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char service_group_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceDomainMemberRedundancyModelT redundancy_model; + int n_active; + int m_standby; + char service_group_aggregate[SM_SERVICE_GROUP_AGGREGATE_NAME_MAX_CHAR]; + char active_only_if_active[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + char redundancy_log_text[SM_LOG_REASON_TEXT_MAX_CHAR]; +} SmServiceDomainMemberT; + +typedef void (*SmServiceDomainMemberTableForEachCallbackT) + (void* user_data[], SmServiceDomainMemberT* member); + +// **************************************************************************** +// Service Domain Member Table - Read +// ================================== +extern SmServiceDomainMemberT* sm_service_domain_member_table_read( + char name[], char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Read By Identifier +// ================================================ +extern SmServiceDomainMemberT* sm_service_domain_member_table_read_by_id( + int64_t id ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Read Service Group +// ================================================ +extern SmServiceDomainMemberT* +sm_service_domain_member_table_read_service_group( char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Count +// =================================== +extern unsigned int sm_service_domain_member_table_count( + char service_domain_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - For Each +// ====================================== +extern void sm_service_domain_member_table_foreach( char service_domain_name[], + void* user_data[], SmServiceDomainMemberTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - For Each Service Group Aggregate +// ============================================================== +extern void sm_service_domain_member_table_foreach_service_group_aggregate( + char service_domain_name[], char service_group_aggregate[], + void* user_data[], SmServiceDomainMemberTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Load +// ================================== +extern SmErrorT sm_service_domain_member_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Initialize +// ======================================== +extern SmErrorT sm_service_domain_member_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Member Table - Finalize +// ====================================== +extern SmErrorT sm_service_domain_member_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_MEMBER_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_down_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_down_state.c new file mode 100644 index 00000000..40a225fa --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_down_state.c @@ -0,0 +1,128 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_neighbor_down_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_domain_neighbor_fsm.h" + +// **************************************************************************** +// Service Domain Neighbor Down State - Entry +// ========================================== +SmErrorT sm_service_domain_neighbor_down_state_entry( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + error = sm_service_domain_neighbor_fsm_stop_dead_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Exit +// ========================================= +SmErrorT sm_service_domain_neighbor_down_state_exit( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + error = sm_service_domain_neighbor_fsm_start_dead_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Transition +// =============================================== +SmErrorT sm_service_domain_neighbor_down_state_transition( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Event Handler +// ================================================== +SmErrorT sm_service_domain_neighbor_down_state_event_handler( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborEventT event, void* event_data[] ) +{ + SmServiceDomainNeighborStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_HELLO_MSG: + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START; + + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain neighbor (%s) set state (%s) " + "failed, error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_MSG: + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_TIMER: + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_MSG: + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_TIMEOUT: + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DOWN: + // Ignore. + break; + + default: + DPRINTFD( "Neighbor (%s) ignoring event (%s).", neighbor->name, + sm_service_domain_neighbor_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Initialize +// =============================================== +SmErrorT sm_service_domain_neighbor_down_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Finalize +// ============================================= +SmErrorT sm_service_domain_neighbor_down_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_down_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_down_state.h new file mode 100644 index 00000000..23be852f --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_down_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_NEIGHBOR_DOWN_STATE_H__ +#define __SM_SERVICE_DOMAIN_NEIGHBOR_DOWN_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_neighbor_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Neighbor Down State - Entry +// ========================================== +extern SmErrorT sm_service_domain_neighbor_down_state_entry( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Exit +// ========================================= +extern SmErrorT sm_service_domain_neighbor_down_state_exit( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Transition +// =============================================== +extern SmErrorT sm_service_domain_neighbor_down_state_transition( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Event Handler +// ================================================== +extern SmErrorT sm_service_domain_neighbor_down_state_event_handler( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Initialize +// =============================================== +extern SmErrorT sm_service_domain_neighbor_down_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Down State - Finalize +// ============================================= +extern SmErrorT sm_service_domain_neighbor_down_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_NEIGHBOR_DOWN_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_start_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_start_state.c new file mode 100644 index 00000000..b0d83433 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_start_state.c @@ -0,0 +1,344 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_neighbor_exchange_start_state.h" + +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_domain_neighbor_fsm.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_assignment_table.h" +#include "sm_failover.h" + +static const int MIN_EXCHANGE_START_INTERVAL_MS = 100; +// **************************************************************************** +// Service Domain Neighbor Exchange Start - Clear Assignments +// ========================================================== +static void sm_service_domain_neighbor_exchange_start_clear_assignments( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + assignment->exchanged = false; +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start - Timeout +// ================================================ +static bool sm_service_domain_neighbor_exchange_start_timeout( + SmTimerIdT timer_id, int64_t user_data ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + int64_t id = user_data; + SmServiceDomainNeighborT* neighbor; + SmServiceDomainNeighborEventT event; + SmErrorT error; + + neighbor = sm_service_domain_neighbor_table_read_by_id( id ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%"PRIi64"), error=%s.", id, + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + event = SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_TIMER; + + snprintf( reason_text, sizeof(reason_text), "exchange-start timeout for %s", + neighbor->service_domain ); + + error = sm_service_domain_neighbor_fsm_event_handler( neighbor->name, + neighbor->service_domain, event, NULL, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to handle " + "event (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_service_domain_neighbor_event_str( event ), + sm_error_str( error ) ); + return( true ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Entry +// ==================================================== +SmErrorT sm_service_domain_neighbor_exchange_start_state_entry( + SmServiceDomainNeighborT* neighbor ) +{ + char timer_name[80] = ""; + SmTimerIdT exchange_timer_id; + SmErrorT error; + + error = sm_service_domain_utils_update_own_assignments( + neighbor->service_domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update own assignments for service domain " + "(%s), error=%s.", neighbor->service_domain, + sm_error_str( error ) ); + return( error ); + } + + sm_service_domain_assignment_table_foreach_node_in_service_domain( + neighbor->service_domain, neighbor->name, NULL, + sm_service_domain_neighbor_exchange_start_clear_assignments ); + + snprintf( timer_name, sizeof(timer_name), "neighbor %s exchange start", + neighbor->name ); + + if( neighbor->exchange_master ) + { + error = sm_timer_register( timer_name, neighbor->exchange_interval, + sm_service_domain_neighbor_exchange_start_timeout, + neighbor->id, &exchange_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create exchange start timer for service " + "domain (%s) neighbor (%s), error=%s.", + neighbor->service_domain, neighbor->name, + sm_error_str( error ) ); + return( error ); + } + + ++neighbor->exchange_seq; + neighbor->exchange_timer_id = exchange_timer_id; + + error = sm_service_domain_utils_send_exchange_start( + neighbor->service_domain, neighbor, neighbor->exchange_seq ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange start for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + } else { + error = sm_timer_register( timer_name, neighbor->exchange_interval*4, + sm_service_domain_neighbor_exchange_start_timeout, + neighbor->id, &exchange_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create exchange start timer for service " + "domain (%s) neighbor (%s), error=%s.", + neighbor->service_domain, neighbor->name, + sm_error_str( error ) ); + return( error ); + } + + neighbor->exchange_seq = 0; + neighbor->exchange_timer_id = exchange_timer_id; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Exit +// =================================================== +SmErrorT sm_service_domain_neighbor_exchange_start_state_exit( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != neighbor->exchange_timer_id ) + { + error = sm_timer_deregister( neighbor->exchange_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel exchange start timer for service " + "domain (%s) neighbor (%s), error=%s.", + neighbor->service_domain, neighbor->name, + sm_error_str( error ) ); + } + + neighbor->exchange_timer_id = SM_TIMER_ID_INVALID; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Transition +// ========================================================= +SmErrorT sm_service_domain_neighbor_exchange_start_state_transition( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Event Handler +// ============================================================ +SmErrorT sm_service_domain_neighbor_exchange_start_state_event_handler( + SmServiceDomainNeighborT* neighbor, SmServiceDomainNeighborEventT event, + void* event_data[] ) +{ + int exchange_seq; + SmServiceDomainNeighborStateT state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_NIL; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_HELLO_MSG: + sm_failover_hello_msg_restore(); + error = sm_service_domain_neighbor_fsm_restart_dead_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to restart dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_MSG: + exchange_seq = *(int*) + event_data[SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MSG_EXCHANGE_SEQ]; + + if( neighbor->exchange_master ) + { + if( exchange_seq == neighbor->exchange_seq ) + { + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE; + + } else { + error = sm_service_domain_utils_send_exchange_start_throttle( + neighbor->service_domain, + neighbor, + neighbor->exchange_seq, + MIN_EXCHANGE_START_INTERVAL_MS); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange start for service " + "domain (%s) neighbor (%s), error=%s.", + neighbor->service_domain, neighbor->name, + sm_error_str( error ) ); + return( error ); + } + } + } else { + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE; + + error = sm_service_domain_utils_send_exchange_start( + neighbor->service_domain, + neighbor, exchange_seq ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange start for service " + "domain (%s) neighbor (%s), error=%s.", + neighbor->service_domain, neighbor->name, + sm_error_str( error ) ); + return( error ); + } + } + + if( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE == state ) + { + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain neighbor (%s) set state (%s) " + "failed, error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_TIMER: + if( neighbor->exchange_master ) + { + ++neighbor->exchange_seq; + + error = sm_service_domain_utils_send_exchange_start( + neighbor->service_domain, + neighbor, + neighbor->exchange_seq ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange start for service " + "domain (%s) neighbor (%s), error=%s.", + neighbor->service_domain, neighbor->name, + sm_error_str( error ) ); + return( error ); + } + } else { + error = sm_service_domain_utils_send_exchange_start( + neighbor->service_domain, + neighbor, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange start for service " + "domain (%s) neighbor (%s), error=%s.", + neighbor->service_domain, neighbor->name, + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_MSG: + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_TIMEOUT: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DOWN: + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN; + + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain neighbor (%s) set state (%s) " + "failed, error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Neighbor (%s) ignoring event (%s).", neighbor->name, + sm_service_domain_neighbor_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Initialize +// ========================================================= +SmErrorT sm_service_domain_neighbor_exchange_start_state_initialize( + void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Finalize +// ======================================================= +SmErrorT sm_service_domain_neighbor_exchange_start_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_start_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_start_state.h new file mode 100644 index 00000000..7a3931d9 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_start_state.h @@ -0,0 +1,63 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_NEIGHBOR_EXCHANGE_START_STATE_H__ +#define __SM_SERVICE_DOMAIN_NEIGHBOR_EXCHANGE_START_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_neighbor_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Entry +// ==================================================== +extern SmErrorT sm_service_domain_neighbor_exchange_start_state_entry( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Exit +// =================================================== +extern SmErrorT sm_service_domain_neighbor_exchange_start_state_exit( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Transition +// ========================================================= +extern SmErrorT sm_service_domain_neighbor_exchange_start_state_transition( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Event Handler +// ============================================================ +extern SmErrorT sm_service_domain_neighbor_exchange_start_state_event_handler( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Initialize +// ========================================================= +extern SmErrorT sm_service_domain_neighbor_exchange_start_state_initialize( + void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange Start State - Finalize +// ======================================================= +extern SmErrorT sm_service_domain_neighbor_exchange_start_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_NEIGHBOR_EXCHANGE_START_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_state.c new file mode 100644 index 00000000..f813a006 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_state.c @@ -0,0 +1,559 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_neighbor_exchange_state.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_msg.h" +#include "sm_node_api.h" +#include "sm_service_domain_neighbor_fsm.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_assignment_table.h" +#include "sm_failover.h" + +static SmMsgCallbacksT _msg_callbacks = {0}; + +// **************************************************************************** +// Service Domain Neighbor Exchange - Timeout +// ========================================== +static bool sm_service_domain_neighbor_exchange_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + int64_t id = user_data; + SmServiceDomainNeighborT* neighbor; + SmErrorT error; + + neighbor = sm_service_domain_neighbor_table_read_by_id( id ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%"PRIi64"), error=%s.", id, + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + if( neighbor->exchange_master ) + { + SmServiceDomainNeighborEventT event; + + event = SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_TIMEOUT; + + snprintf( reason_text, sizeof(reason_text), "exchange timeout for %s", + neighbor->service_domain ); + + error = sm_service_domain_neighbor_fsm_event_handler( neighbor->name, + neighbor->service_domain, event, NULL, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to handle " + "event (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_service_domain_neighbor_event_str( event ), + sm_error_str( error ) ); + } + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange - Start Timer +// ============================================== +static SmErrorT sm_service_domain_neighbor_exchange_start_timer( + SmServiceDomainNeighborT* neighbor ) +{ + char timer_name[80] = ""; + SmTimerIdT exchange_timer_id; + SmErrorT error; + + snprintf( timer_name, sizeof(timer_name), "neighbor %s exchange", + neighbor->name ); + + error = sm_timer_register( timer_name, neighbor->exchange_interval, + sm_service_domain_neighbor_exchange_timeout, + neighbor->id, &exchange_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create exchange timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + neighbor->exchange_timer_id = exchange_timer_id; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange - Stop Timer +// ============================================= +static SmErrorT sm_service_domain_neighbor_exchange_stop_timer( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != neighbor->exchange_timer_id ) + { + error = sm_timer_deregister( neighbor->exchange_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel exchange timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + } + + neighbor->exchange_timer_id = SM_TIMER_ID_INVALID; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange - Restart Timer +// ================================================ +static SmErrorT sm_service_domain_neighbor_exchange_restart_timer( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + error = sm_service_domain_neighbor_exchange_stop_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop exchange timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_exchange_start_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start exchange timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange - Send +// ======================================= +static SmErrorT sm_service_domain_neighbor_exchange_send( + SmServiceDomainNeighborT* neighbor, bool* exchange_complete ) +{ + bool more_members; + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainAssignmentT* assignment; + SmServiceDomainAssignmentT* next_assignment; + SmErrorT error; + + *exchange_complete = false; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + assignment = sm_service_domain_assignment_table_get_next_node( + neighbor->service_domain, hostname, + neighbor->exchange_last_sent_id ); + if( NULL == assignment ) + { + assignment = sm_service_domain_assignment_table_get_last_node( + neighbor->service_domain, hostname, + neighbor->exchange_last_sent_id ); + if( NULL == assignment ) + { + DPRINTFE( "Failed to find last sent assignment." ); + return( SM_NOT_FOUND ); + } + + next_assignment = NULL; + } else { + next_assignment = sm_service_domain_assignment_table_get_next_node( + neighbor->service_domain, hostname, + assignment->id ); + } + + more_members = (NULL != next_assignment); + + error = sm_service_domain_utils_send_exchange( neighbor->service_domain, + neighbor, neighbor->exchange_seq+1, assignment->id, + assignment->service_group_name, assignment->desired_state, + assignment->state, assignment->status, assignment->condition, + assignment->health, assignment->reason_text, + more_members, neighbor->exchange_last_recvd_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send service domain (%s) exchange message, " + "error=%s.", neighbor->service_domain, + sm_error_str(error) ); + return( error ); + } + + DPRINTFI( "Service domain (%s) sent service group (%s) to " + "node (%s), more_members=%s.", neighbor->service_domain, + assignment->service_group_name, neighbor->name, + more_members ? "yes" : "no" ); + + ++(neighbor->exchange_seq); + neighbor->exchange_last_sent_id = assignment->id; + + *exchange_complete = (!more_members); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange - Receive +// ========================================== +static void sm_service_domain_neighbor_exchange_receive( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char service_domain_name[], char node_name[], int exchange_seq, + int64_t member_id, char member_name[], SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t member_health, + char member_reason_text[], bool more_members, int64_t last_received_member_id ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainNeighborT* neighbor; + SmServiceDomainAssignmentT* assignment; + SmServiceDomainNeighborEventT event; + void* event_data[SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MAX] = {0}; + SmErrorT error; + + event_data[SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MSG_MORE_MEMBERS] + = &more_members; + + neighbor = sm_service_domain_neighbor_table_read( node_name, + service_domain_name ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%s), error=%s.", node_name, + sm_error_str(SM_NOT_FOUND) ); + return; + } + + if( last_received_member_id != neighbor->exchange_last_sent_id ) + { + DPRINTFE( "Member id mismatch from neighbor (%s) for service domain " + "(%s), received=%"PRIi64", expected=%"PRIi64".", + node_name, service_domain_name, last_received_member_id, + neighbor->exchange_last_sent_id ); + return; + } + + neighbor->exchange_last_recvd_id = member_id; + + DPRINTFI( "Service domain (%s) received service group (%s) from " + "node (%s), more_members=%s.", service_domain_name, member_name, + node_name, more_members ? "yes" : "no" ); + + if( '\0' != member_name[0] ) + { + error = sm_service_domain_utils_update_assignment( service_domain_name, + node_name, member_name, member_desired_state, + member_state, member_status, member_condition, member_health, + member_reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to update " + "assignment (%s), error=%s.", service_domain_name, + node_name, member_name, sm_error_str( error ) ); + return; + } + + assignment = sm_service_domain_assignment_table_read( + service_domain_name, node_name, member_name ); + if( NULL != assignment ) + { + assignment->exchanged = true; + } + } + + event = SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_MSG; + + // If we do transition because of this event, it is because the exchange + // is complete on both ends. + snprintf( reason_text, sizeof(reason_text), "exchange complete for %s", + service_domain_name ); + + error = sm_service_domain_neighbor_fsm_event_handler( node_name, + service_domain_name, + event, event_data, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to handle " + "event (%s), error=%s.", service_domain_name, node_name, + sm_service_domain_neighbor_event_str( event ), + sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Entry +// ============================================== +SmErrorT sm_service_domain_neighbor_exchange_state_entry( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + error = sm_service_domain_neighbor_exchange_start_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start exchange timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + neighbor->exchange_last_sent_id = 0; + neighbor->exchange_last_recvd_id = 0; + + if( neighbor->exchange_master ) + { + bool exchange_complete; + + error = sm_service_domain_neighbor_exchange_send( neighbor, + &exchange_complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange message to neighbor (%s) for " + "service domain (%s), error=%s.", neighbor->name, + neighbor->service_domain, sm_error_str( error ) ); + return( error ); + } + } + + error = sm_msg_register_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register message callbacks, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Exit +// ============================================= +SmErrorT sm_service_domain_neighbor_exchange_state_exit( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + error = sm_msg_deregister_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister message callbacks, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_exchange_stop_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop exchange timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + neighbor->exchange_last_sent_id = 0; + neighbor->exchange_last_recvd_id = 0; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Transition +// =================================================== +SmErrorT sm_service_domain_neighbor_exchange_state_transition( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Event Handler +// ====================================================== +SmErrorT sm_service_domain_neighbor_exchange_state_event_handler( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborEventT event, void* event_data[] ) +{ + bool exchange_complete; + bool neighbor_more_members; + bool neighbor_exchange_complete; + SmServiceDomainNeighborStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_HELLO_MSG: + sm_failover_hello_msg_restore(); + error = sm_service_domain_neighbor_fsm_restart_dead_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to restart dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_MSG: + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START; + + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to set " + "state (%s), error=%s.", neighbor->service_domain, + neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_TIMER: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_MSG: + + neighbor_more_members = *(bool*) + event_data[SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MSG_MORE_MEMBERS]; + + neighbor_exchange_complete = !neighbor_more_members; + + error = sm_service_domain_neighbor_exchange_restart_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start exchange timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_exchange_send( neighbor, + &exchange_complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange message to neighbor (%s) for " + "service domain (%s), error=%s.", neighbor->name, + neighbor->service_domain, sm_error_str( error ) ); + return( error ); + } + + if(( exchange_complete )&&( neighbor_exchange_complete )) + { + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL; + + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to set " + "state (%s), error=%s.", neighbor->service_domain, + neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_TIMEOUT: + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START; + + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to set " + "state (%s), error=%s.", neighbor->service_domain, + neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DOWN: + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN; + + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain neighbor (%s) set state (%s) " + "failed, error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Neighbor (%s) ignoring event (%s).", neighbor->name, + sm_service_domain_neighbor_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Initialize +// =================================================== +SmErrorT sm_service_domain_neighbor_exchange_state_initialize( void ) +{ + _msg_callbacks.exchange = sm_service_domain_neighbor_exchange_receive; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Finalize +// ================================================= +SmErrorT sm_service_domain_neighbor_exchange_state_finalize( void ) +{ + _msg_callbacks.exchange = NULL; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_state.h new file mode 100644 index 00000000..c1cc16f5 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_exchange_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_NEIGHBOR_EXCHANGE_STATE_H__ +#define __SM_SERVICE_DOMAIN_NEIGHBOR_EXCHANGE_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_neighbor_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Entry +// ============================================== +extern SmErrorT sm_service_domain_neighbor_exchange_state_entry( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Exit +// ============================================= +extern SmErrorT sm_service_domain_neighbor_exchange_state_exit( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Transition +// =================================================== +extern SmErrorT sm_service_domain_neighbor_exchange_state_transition( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Event Handler +// ====================================================== +extern SmErrorT sm_service_domain_neighbor_exchange_state_event_handler( + SmServiceDomainNeighborT* neighbor, SmServiceDomainNeighborEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Initialize +// =================================================== +extern SmErrorT sm_service_domain_neighbor_exchange_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Exchange State - Finalize +// ================================================= +extern SmErrorT sm_service_domain_neighbor_exchange_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_NEIGHBOR_EXCHANGE_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_fsm.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_fsm.c new file mode 100644 index 00000000..254541c3 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_fsm.c @@ -0,0 +1,1135 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_neighbor_fsm.h" + +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_time.h" +#include "sm_timer.h" +#include "sm_msg.h" +#include "sm_node_api.h" +#include "sm_heartbeat.h" +#include "sm_service_domain_table.h" +#include "sm_service_domain_neighbor_down_state.h" +#include "sm_service_domain_neighbor_exchange_start_state.h" +#include "sm_service_domain_neighbor_exchange_state.h" +#include "sm_service_domain_neighbor_full_state.h" +#include "sm_log.h" +#include "sm_failover.h" + +static SmMsgCallbacksT _msg_callbacks = {0}; +static SmListT* _callbacks = NULL; + +static SmServiceDomainNeighborStateT _dump_state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_NIL; +static SmTimeT _dump_state_last_changed = {0}; + +// **************************************************************************** +// Service Domain Neighbor FSM - Register Callback +// =============================================== +SmErrorT sm_service_domain_neighbor_fsm_register_callback( + SmServiceDomainNeighborFsmCallbackT callback ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Deregister Callback +// ================================================= +SmErrorT sm_service_domain_neighbor_fsm_deregister_callback( + SmServiceDomainNeighborFsmCallbackT callback ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Notify +// ==================================== +static void sm_service_domain_neighbor_fsm_notify( + SmServiceDomainNeighborT* neighbor ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainNeighborFsmCallbackT callback; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callback = (SmServiceDomainNeighborFsmCallbackT) entry_data; + + callback( neighbor->service_domain, neighbor->name, neighbor->state ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Pause Timeout +// =========================================== +static bool sm_service_domain_neighbor_fsm_pause_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceDomainNeighborT* neighbor; + + neighbor = sm_service_domain_neighbor_table_read_by_id( id ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%"PRIi64"), error=%s.", id, + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + neighbor->pause_timer_id = SM_TIMER_ID_INVALID; + + DPRINTFI( "Neighbor (%s) for service domain (%s) pause interval expired.", + neighbor->name, neighbor->service_domain ); + + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Start Pause Timer +// =============================================== +static SmErrorT sm_service_domain_neighbor_fsm_start_pause_timer( + int pause_interval, SmServiceDomainNeighborT* neighbor ) +{ + char timer_name[80] = ""; + SmTimerIdT pause_timer_id; + SmErrorT error; + + DPRINTFI( "Start pause timer for neighbor (%s), pause=%i ms.", + neighbor->name, pause_interval ); + + snprintf( timer_name, sizeof(timer_name), "%s neighbor %s pause", + neighbor->service_domain, neighbor->name ); + + error = sm_timer_register( timer_name, pause_interval, + sm_service_domain_neighbor_fsm_pause_timeout, + neighbor->id, &pause_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create pause timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + neighbor->pause_timer_id = pause_timer_id; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Stop Pause Timer +// ============================================== +static SmErrorT sm_service_domain_neighbor_fsm_stop_pause_timer( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != neighbor->pause_timer_id ) + { + DPRINTFI( "Stop pause timer for neighbor (%s).", neighbor->name ); + + error = sm_timer_deregister( neighbor->pause_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel pause timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + } + + neighbor->pause_timer_id = SM_TIMER_ID_INVALID; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Restart Pause Timer +// ================================================= +static SmErrorT sm_service_domain_neighbor_fsm_restart_pause_timer( + int pause_interval, SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + DPRINTFI( "Restart pause timer for neighbor (%s).", neighbor->name ); + + error = sm_service_domain_neighbor_fsm_stop_pause_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop pause timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_fsm_start_pause_timer( pause_interval, + neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start pause timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Dead Timeout +// ========================================== +static bool sm_service_domain_neighbor_fsm_dead_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceDomainNeighborT* neighbor; + + neighbor = sm_service_domain_neighbor_table_read_by_id( id ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%"PRIi64"), error=%s.", id, + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + if( !sm_timer_scheduling_on_time() ) + { + DPRINTFI( "Not scheduling on time, would have declared neighbor (%s) " + "for service domain (%s) dead.", neighbor->name, + neighbor->service_domain ); + return( true ); + } + + if( sm_heartbeat_peer_alive_in_period( neighbor->name, + neighbor->dead_interval/2 ) ) + { + DPRINTFI( "Heartbeat still indicates peer is alive, would have " + "declared neighbor (%s) for service domain (%s) dead.", + neighbor->name, neighbor->service_domain ); + return( true ); + } + + if( SM_TIMER_ID_INVALID != neighbor->pause_timer_id ) + { + DPRINTFI( "Pause timer still in effect, would have declared neighbor " + "(%s) for service domain (%s) dead.", neighbor->name, + neighbor->service_domain ); + return( true ); + } + + sm_failover_lost_hello_msg(); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Start Dead Timer +// ============================================== +SmErrorT sm_service_domain_neighbor_fsm_start_dead_timer( + SmServiceDomainNeighborT* neighbor ) +{ + char timer_name[80] = ""; + SmTimerIdT dead_timer_id; + SmErrorT error; + + DPRINTFD( "Start dead timer for neighbor (%s).", neighbor->name ); + + snprintf( timer_name, sizeof(timer_name), "%s neighbor %s dead", + neighbor->service_domain, neighbor->name ); + + error = sm_timer_register( timer_name, neighbor->dead_interval, + sm_service_domain_neighbor_fsm_dead_timeout, + neighbor->id, &dead_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + neighbor->dead_timer_id = dead_timer_id; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Stop Dead Timer +// ============================================= +SmErrorT sm_service_domain_neighbor_fsm_stop_dead_timer( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != neighbor->dead_timer_id ) + { + DPRINTFD( "Stop dead timer for neighbor (%s).", neighbor->name ); + + error = sm_timer_deregister( neighbor->dead_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + } + + neighbor->dead_timer_id = SM_TIMER_ID_INVALID; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Restart Dead Timer +// ================================================ +SmErrorT sm_service_domain_neighbor_fsm_restart_dead_timer( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + DPRINTFD( "Restart dead timer for neighbor (%s).", neighbor->name ); + + error = sm_service_domain_neighbor_fsm_stop_dead_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_fsm_start_dead_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Enter State +// ========================================= +static SmErrorT sm_service_domain_neighbor_fsm_enter_state( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + switch( neighbor->state ) + { + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN: + error = sm_service_domain_neighbor_down_state_entry( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to enter state (%s), error=%s.", + neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START: + error = sm_service_domain_neighbor_exchange_start_state_entry( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to enter state (%s), error=%s.", + neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE: + error = sm_service_domain_neighbor_exchange_state_entry( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to enter state (%s), error=%s.", + neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL: + error = sm_service_domain_neighbor_full_state_entry( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to enter state (%s), error=%s.", + neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown neighbor (%s) state (%s).", neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ) ); + break; + } + + _dump_state = neighbor->state; + clock_gettime( CLOCK_REALTIME, &_dump_state_last_changed ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Exit State +// ======================================== +static SmErrorT sm_service_domain_neighbor_fsm_exit_state( + SmServiceDomainNeighborT* neighbor ) +{ + SmErrorT error; + + switch( neighbor->state ) + { + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN: + error = sm_service_domain_neighbor_down_state_exit( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to exit state (%s), error=%s.", + neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START: + error = sm_service_domain_neighbor_exchange_start_state_exit( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to exit state (%s), error=%s.", + neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE: + error = sm_service_domain_neighbor_exchange_state_exit( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to exit state (%s), error=%s.", + neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL: + error = sm_service_domain_neighbor_full_state_exit( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to exit state (%s), error=%s.", + neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown neighbor (%s) state (%s).", neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Transition State +// ============================================== +static SmErrorT sm_service_domain_neighbor_fsm_transition_state( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ) +{ + SmErrorT error; + + switch( neighbor->state ) + { + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN: + error = sm_service_domain_neighbor_down_state_transition( + neighbor, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( from_state ), + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START: + error = sm_service_domain_neighbor_exchange_start_state_transition( + neighbor, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( from_state ), + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE: + error = sm_service_domain_neighbor_exchange_state_transition( + neighbor, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( from_state ), + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL: + error = sm_service_domain_neighbor_full_state_transition( + neighbor, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( from_state ), + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown neighbor (%s) state (%s).", neighbor->name, + sm_service_domain_neighbor_state_str( neighbor->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Set State +// ======================================= +SmErrorT sm_service_domain_neighbor_fsm_set_state( char neighbor_name[], + char service_domain[], SmServiceDomainNeighborStateT state ) +{ + SmServiceDomainNeighborStateT prev_state; + SmServiceDomainNeighborT* neighbor; + SmErrorT error, error2; + + neighbor = sm_service_domain_neighbor_table_read( neighbor_name, + service_domain ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%s), error=%s.", neighbor_name, + sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = neighbor->state; + + error = sm_service_domain_neighbor_fsm_exit_state( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to exit state (%s) neighbor (%s), error=%s.", + sm_service_domain_neighbor_state_str( neighbor->state ), + neighbor_name, sm_error_str( error ) ); + return( error ); + } + + neighbor->state = state; + + error = sm_service_domain_neighbor_fsm_transition_state( neighbor, + prev_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to transition to state (%s) neighbor (%s), " + "error=%s.", + sm_service_domain_neighbor_state_str( neighbor->state ), + neighbor_name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + error = sm_service_domain_neighbor_fsm_enter_state( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enter state (%s) neighbor (%s), error=%s.", + sm_service_domain_neighbor_state_str( neighbor->state ), + neighbor_name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + return( SM_OKAY ); + +STATE_CHANGE_ERROR: + error2 = sm_service_domain_neighbor_fsm_exit_state( neighbor ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to exit state (%s) neighbor (%s), error=%s.", + sm_service_domain_neighbor_state_str( neighbor->state ), + neighbor_name, sm_error_str( error2 ) ); + abort(); + } + + neighbor->state = prev_state; + + error2 = sm_service_domain_neighbor_fsm_transition_state( neighbor, + state ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to transition neighbor (%s) to state (%s), " + "error=%s.", neighbor_name, + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error2 ) ); + abort(); + } + + error2 = sm_service_domain_neighbor_fsm_enter_state( neighbor ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to enter state (%s) neighbor (%s), error=%s.", + sm_service_domain_neighbor_state_str( neighbor->state ), + neighbor_name, sm_error_str( error2 ) ); + abort(); + } + + return( error ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Event Handler +// =========================================== +SmErrorT sm_service_domain_neighbor_fsm_event_handler( char neighbor_name[], + char service_domain[], SmServiceDomainNeighborEventT event, + void* event_data[], const char reason_text[] ) +{ + SmServiceDomainNeighborStateT prev_state; + SmServiceDomainNeighborT* neighbor; + SmErrorT error; + + neighbor = sm_service_domain_neighbor_table_read( neighbor_name, + service_domain ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%s), error=%s.", + neighbor_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = neighbor->state; + + switch( neighbor->state ) + { + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN: + error = sm_service_domain_neighbor_down_state_event_handler( + neighbor, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to handle event (%s) " + "in state (%s), error=%s.", neighbor_name, + sm_service_domain_neighbor_event_str( event ), + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START: + error = sm_service_domain_neighbor_exchange_start_state_event_handler( + neighbor, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to handle event (%s) " + "in state (%s), error=%s.", neighbor_name, + sm_service_domain_neighbor_event_str( event ), + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE: + error = sm_service_domain_neighbor_exchange_state_event_handler( + neighbor, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to handle event (%s) " + "in state (%s), error=%s.", neighbor_name, + sm_service_domain_neighbor_event_str( event ), + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL: + error = sm_service_domain_neighbor_full_state_event_handler( + neighbor, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Neighbor (%s) unable to handle event (%s) " + "in state (%s), error=%s.", neighbor_name, + sm_service_domain_neighbor_event_str( event ), + sm_service_domain_neighbor_state_str( neighbor->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown state (%s) for neighbor (%s).", + sm_service_domain_neighbor_state_str( neighbor->state ), + neighbor_name ); + break; + } + + if( prev_state != neighbor->state ) + { + DPRINTFI( "Neighbor (%s) received event (%s) was in the %s state and " + "is now in the %s.", neighbor_name, + sm_service_domain_neighbor_event_str( event ), + sm_service_domain_neighbor_state_str( prev_state ), + sm_service_domain_neighbor_state_str( neighbor->state ) ); + + error = sm_service_domain_neighbor_table_persist( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update database for neighbor (%s), " + "error=%s.", neighbor_name, sm_error_str( error ) ); + return( error ); + } + + sm_log_neighbor_state_change( neighbor_name, + sm_service_domain_neighbor_state_str( prev_state ), + sm_service_domain_neighbor_state_str( neighbor->state ), + reason_text ); + + sm_service_domain_neighbor_fsm_notify( neighbor ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +SmNodeAvailStatusT sm_node_get_availability( char node_name[]) +{ + SmDbNodeT node; + SmErrorT error = sm_failover_get_node(node_name, node); + if( SM_OKAY == error ) + { + return node.avail_status; + } + return SM_NODE_AVAIL_STATUS_UNKNOWN; +} + +// **************************************************************************** +// Service Domain Neighbor FSM - Hello Message Callback +// ==================================================== +static void sm_service_domain_neighbor_fsm_hello_msg_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char service_domain_name[], char node_name[], + char orchestration[], char designation[], int generation, int priority, + int hello_interval, int dead_interval, int wait_interval, + int exchange_interval, char leader[] ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainT* domain; + SmServiceDomainNeighborT* neighbor; + SmServiceDomainNeighborEventT event; + SmErrorT error; + + domain = sm_service_domain_table_read( service_domain_name ); + if( NULL == domain ) + { + DPRINTFD( "Service domain (%s) does not exist, error=%s.", + service_domain_name, sm_error_str(SM_NOT_FOUND) ); + return; + } + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return; + } + + neighbor = sm_service_domain_neighbor_table_read( node_name, + service_domain_name ); + if( NULL == neighbor ) + { + error = sm_service_domain_neighbor_table_insert( node_name, + service_domain_name, orchestration, designation, + generation, priority, hello_interval, dead_interval, + wait_interval, exchange_interval ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to insert neighbor (%s) into database, " + "error=%s.", node_name, sm_error_str( error ) ); + return; + } + + neighbor = sm_service_domain_neighbor_table_read( node_name, + service_domain_name ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%s), error=%s.", + node_name, sm_error_str(SM_NOT_FOUND) ); + return; + } + + neighbor->exchange_master = false; + + if( generation > domain->generation ) + { + neighbor->exchange_master = true; + + } else if( generation == domain->generation ) { + if( priority < domain->priority ) + { + neighbor->exchange_master = true; + + } else if( priority == domain->priority ) { + SmNodeAvailStatusT host_avail_status = + sm_node_get_availability( hostname ); + SmNodeAvailStatusT neighbor_avail_status = + sm_node_get_availability( neighbor->name ); + + int weight_table[SM_NODE_AVAIL_STATUS_MAX] = {0}; + weight_table[SM_NODE_AVAIL_STATUS_AVAILABLE] = 10; + weight_table[SM_NODE_AVAIL_STATUS_DEGRADED] = 5; + weight_table[SM_NODE_AVAIL_STATUS_FAILED] = -1; + int host_weight = weight_table[host_avail_status]; + int neighbor_weight = weight_table[neighbor_avail_status]; + + if( host_weight > neighbor_weight ) + { + DPRINTFD("%s is more available than %s", hostname, neighbor->name); + neighbor->exchange_master = true; + } + else if( host_weight == neighbor_weight ) + { + if( 0 < strcmp( hostname, neighbor->name ) ) + { + neighbor->exchange_master = true; + } + } + else + { + DPRINTFD("%s is less available than %s", hostname, neighbor->name); + } + } + } + } else { + neighbor->exchange_master = false; + + if( generation > domain->generation ) + { + neighbor->exchange_master = true; + + } else if( generation == domain->generation ) { + if( priority < domain->priority ) + { + neighbor->exchange_master = true; + + } else if( priority == domain->priority ) { + SmNodeAvailStatusT host_avail_status = + sm_node_get_availability( hostname ); + SmNodeAvailStatusT neighbor_avail_status = + sm_node_get_availability( neighbor->name ); + + int weight_table[SM_NODE_AVAIL_STATUS_MAX] = {0}; + weight_table[SM_NODE_AVAIL_STATUS_AVAILABLE] = 10; + weight_table[SM_NODE_AVAIL_STATUS_DEGRADED] = 5; + weight_table[SM_NODE_AVAIL_STATUS_FAILED] = -1; + int host_weight = weight_table[host_avail_status]; + int neighbor_weight = weight_table[neighbor_avail_status]; + + if( host_weight > neighbor_weight ) + { + DPRINTFD("%s is more available than %s", hostname, neighbor->name); + neighbor->exchange_master = true; + } + else if( host_weight == neighbor_weight ) + { + if( 0 < strcmp( hostname, neighbor->name ) ) + { + neighbor->exchange_master = true; + } + } + else + { + DPRINTFD("%s is less available than %s", hostname, neighbor->name); + } + } + } + + snprintf( neighbor->designation, sizeof(neighbor->designation), + "%s", designation ); + + error = sm_service_domain_neighbor_table_persist( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update neighbor (%s) into database, " + "error=%s.", node_name, sm_error_str( error ) ); + return; + } + } + + error = sm_service_domain_neighbor_fsm_stop_pause_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel pause timer for neighbor (%s), " + "error=%s.", node_name, sm_error_str( error ) ); + return; + } + + event = SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_HELLO_MSG; + + snprintf( reason_text, sizeof(reason_text), "hello received for %s", + service_domain_name ); + + error = sm_service_domain_neighbor_fsm_event_handler( node_name, + service_domain_name, + event, NULL, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to handle " + "event (%s), error=%s.", service_domain_name, node_name, + sm_service_domain_neighbor_event_str( event ), + sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Pause Message Callback +// ==================================================== +static void sm_service_domain_neighbor_fsm_pause_msg_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char service_domain_name[], char node_name[], + int pause_interval ) +{ + SmServiceDomainNeighborT* neighbor; + SmErrorT error; + + neighbor = sm_service_domain_neighbor_table_read( node_name, + service_domain_name ); + if( NULL != neighbor ) + { + error = sm_service_domain_neighbor_fsm_restart_pause_timer( + pause_interval, neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable start " + "pause timer, error=%s.", service_domain_name, + node_name, sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Exchange Start Message Callback +// ============================================================= +static void sm_service_domain_neighbor_fsm_exchange_start_msg_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char service_domain_name[], char node_name[], + int exchange_seq ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainNeighborT* neighbor; + SmServiceDomainNeighborEventT event; + void* event_data[SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MAX] = {0}; + SmErrorT error; + + neighbor = sm_service_domain_neighbor_table_read( node_name, + service_domain_name ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to read neighbor (%s) for service domain (%s), " + "error=%s.", node_name, service_domain_name, + sm_error_str(SM_NOT_FOUND) ); + return; + } + + event = SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_MSG; + + event_data[SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MSG_EXCHANGE_SEQ] + = &exchange_seq; + + snprintf( reason_text, sizeof(reason_text), "exchange-start received for %s", + service_domain_name ); + + error = sm_service_domain_neighbor_fsm_event_handler( node_name, + service_domain_name, + event, event_data, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to handle " + "event (%s), error=%s.", service_domain_name, node_name, + sm_service_domain_neighbor_event_str( event ), + sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +void sm_domain_neighbor_fsm_dump(FILE* fp) +{ + SmRealTimeStrT realtime; + sm_time_format_realtime(&_dump_state_last_changed, realtime, sizeof(realtime)); + fprintf(fp, "Domain Neighbor FSM state: %s, last changed %s\n", + sm_service_domain_neighbor_state_str(_dump_state), + realtime + ); +} + +// **************************************************************************** +// Service Domain Neighbor FSM - Initialize +// ======================================== +SmErrorT sm_service_domain_neighbor_fsm_initialize( void ) +{ + SmErrorT error; + + error = sm_service_domain_neighbor_down_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize neighbor down state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_exchange_start_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize neighbor exchange start state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_exchange_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize neighbor exchange state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_full_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize neighbor full state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + _msg_callbacks.hello + = sm_service_domain_neighbor_fsm_hello_msg_callback; + _msg_callbacks.pause + = sm_service_domain_neighbor_fsm_pause_msg_callback; + _msg_callbacks.exchange_start + = sm_service_domain_neighbor_fsm_exchange_start_msg_callback; + + error = sm_msg_register_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register message callbacks, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Finalize +// ====================================== +SmErrorT sm_service_domain_neighbor_fsm_finalize( void ) +{ + SmErrorT error; + + error = sm_msg_deregister_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister message callbacks, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_neighbor_down_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize neighbor down state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_neighbor_exchange_start_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize neighbor exchange start state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_neighbor_exchange_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize neighbor exchange state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_domain_neighbor_full_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize neighbor full state module, " + "error=%s.", sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_fsm.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_fsm.h new file mode 100644 index 00000000..4b06e2eb --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_fsm.h @@ -0,0 +1,93 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_NEIGHBOR_FSM_H__ +#define __SM_SERVICE_DOMAIN_NEIGHBOR_FSM_H__ + +#include "sm_types.h" +#include "sm_timer.h" +#include "sm_service_domain_neighbor_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmServiceDomainNeighborFsmCallbackT) (char service_domain[], + char node_name[], SmServiceDomainNeighborStateT state); + +// **************************************************************************** +// Service Domain Neighbor FSM - Register Callback +// =============================================== +extern SmErrorT sm_service_domain_neighbor_fsm_register_callback( + SmServiceDomainNeighborFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Deregister Callback +// ================================================= +extern SmErrorT sm_service_domain_neighbor_fsm_deregister_callback( + SmServiceDomainNeighborFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Start Dead Timer +// ============================================== +extern SmErrorT sm_service_domain_neighbor_fsm_start_dead_timer( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Stop Dead Timer +// ============================================= +extern SmErrorT sm_service_domain_neighbor_fsm_stop_dead_timer( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Restart Dead Timer +// ================================================ +extern SmErrorT sm_service_domain_neighbor_fsm_restart_dead_timer( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Set State +// ======================================= +extern SmErrorT sm_service_domain_neighbor_fsm_set_state( char neighbor_name[], + char service_domain[], SmServiceDomainNeighborStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Event Handler +// =========================================== +extern SmErrorT sm_service_domain_neighbor_fsm_event_handler( + char neighbor_name[], char service_domain[], + SmServiceDomainNeighborEventT event, void* event_data[], + const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - dump +// =========================================== +void sm_domain_neighbor_fsm_dump(FILE* fp); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Initialize +// ======================================== +extern SmErrorT sm_service_domain_neighbor_fsm_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor FSM - Finalize +// ====================================== +extern SmErrorT sm_service_domain_neighbor_fsm_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_NEIGHBOR_FSM_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_full_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_full_state.c new file mode 100644 index 00000000..a915d366 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_full_state.c @@ -0,0 +1,166 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_neighbor_full_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_domain_neighbor_fsm.h" +#include "sm_service_domain_assignment_table.h" +#include "sm_failover.h" + +// **************************************************************************** +// Service Domain Neighbor Full State - Delete Assignments +// ======================================================= +static void sm_service_domain_neighbor_full_state_delete_assignments( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + SmErrorT error; + + if( !assignment->exchanged ) + { + error = sm_service_domain_assignment_table_delete( assignment->name, + assignment->node_name, assignment->service_group_name ); + if( SM_OKAY == error ) + { + DPRINTFI( "Deleted assignment (%s) from service domain (%s) " + "node (%s) as it was not exchanged.", + assignment->service_group_name, assignment->name, + assignment->node_name ); + } else { + DPRINTFE( "Failed to delete assignment (%s) for service domain " + "(%s) node (%s), error=%s.", + assignment->service_group_name, assignment->name, + assignment->node_name, sm_error_str( error ) ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Entry +// ========================================== +SmErrorT sm_service_domain_neighbor_full_state_entry( + SmServiceDomainNeighborT* neighbor ) +{ + sm_service_domain_assignment_table_foreach_node_in_service_domain( + neighbor->service_domain, neighbor->name, NULL, + sm_service_domain_neighbor_full_state_delete_assignments ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Exit +// ========================================= +SmErrorT sm_service_domain_neighbor_full_state_exit( + SmServiceDomainNeighborT* neighbor ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Transition +// =============================================== +SmErrorT sm_service_domain_neighbor_full_state_transition( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Event Handler +// ================================================== +SmErrorT sm_service_domain_neighbor_full_state_event_handler( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborEventT event, void* event_data[] ) +{ + SmServiceDomainNeighborStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_HELLO_MSG: + sm_failover_hello_msg_restore(); + error = sm_service_domain_neighbor_fsm_restart_dead_timer( neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to restart dead timer for service domain (%s) " + "neighbor (%s), error=%s.", neighbor->service_domain, + neighbor->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_MSG: + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_MSG: + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START; + + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to set " + "state (%s), error=%s.", neighbor->service_domain, + neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_TIMER: + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_TIMEOUT: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DOWN: + state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN; + + error = sm_service_domain_neighbor_fsm_set_state( neighbor->name, + neighbor->service_domain, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain neighbor (%s) set state (%s) " + "failed, error=%s.", neighbor->name, + sm_service_domain_neighbor_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Neighbor (%s) ignoring event (%s).", neighbor->name, + sm_service_domain_neighbor_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Initialize +// =============================================== +SmErrorT sm_service_domain_neighbor_full_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Finalize +// ============================================= +SmErrorT sm_service_domain_neighbor_full_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_full_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_full_state.h new file mode 100644 index 00000000..ef765aaf --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_full_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_NEIGHBOR_FULL_STATE_H__ +#define __SM_SERVICE_DOMAIN_NEIGHBOR_FULL_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_neighbor_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Neighbor Full State - Entry +// ========================================== +extern SmErrorT sm_service_domain_neighbor_full_state_entry( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Exit +// ========================================= +extern SmErrorT sm_service_domain_neighbor_full_state_exit( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Transition +// =============================================== +extern SmErrorT sm_service_domain_neighbor_full_state_transition( + SmServiceDomainNeighborT* neighbor, + SmServiceDomainNeighborStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Event Handler +// ================================================== +extern SmErrorT sm_service_domain_neighbor_full_state_event_handler( + SmServiceDomainNeighborT* neighbor, SmServiceDomainNeighborEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Initialize +// =============================================== +extern SmErrorT sm_service_domain_neighbor_full_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Full State - Finalize +// ============================================= +extern SmErrorT sm_service_domain_neighbor_full_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_NEIGHBOR_FULL_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_table.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_table.c new file mode 100644 index 00000000..27a1e418 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_table.c @@ -0,0 +1,373 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_neighbor_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_domain_neighbors.h" + +static SmListT* _service_domain_neighbors = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Domain Neighbor Table - Read +// ==================================== +SmServiceDomainNeighborT* sm_service_domain_neighbor_table_read( + char name[], char service_domain_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainNeighborT* neighbor; + + SM_LIST_FOREACH( _service_domain_neighbors, entry, entry_data ) + { + neighbor = (SmServiceDomainNeighborT*) entry_data; + + if(( 0 == strcmp( name, neighbor->name ) )&& + ( 0 == strcmp( service_domain_name, neighbor->service_domain ) )) + { + return( neighbor ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Read By Identifier +// ================================================== +SmServiceDomainNeighborT* sm_service_domain_neighbor_table_read_by_id( + int64_t id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainNeighborT* neighbor; + + SM_LIST_FOREACH( _service_domain_neighbors, entry, entry_data ) + { + neighbor = (SmServiceDomainNeighborT*) entry_data; + + if( id == neighbor->id ) + { + return( neighbor ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - For Each +// ======================================== +void sm_service_domain_neighbor_table_foreach( char service_domain_name[], + void* user_data[], SmServiceDomainNeighborTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainNeighborT* neighbor; + + SM_LIST_FOREACH( _service_domain_neighbors, entry, entry_data ) + { + neighbor = (SmServiceDomainNeighborT*) entry_data; + + if( service_domain_name == neighbor->service_domain ) + { + callback( user_data, neighbor ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Add +// =================================== +static SmErrorT sm_service_domain_neighbor_table_add( void* user_data[], + void* record ) +{ + SmServiceDomainNeighborT* neighbor; + SmDbServiceDomainNeighborT* db_neighbor; + + db_neighbor = (SmDbServiceDomainNeighborT*) record; + + neighbor = sm_service_domain_neighbor_table_read( db_neighbor->name, + db_neighbor->service_domain ); + if( NULL == neighbor ) + { + neighbor = (SmServiceDomainNeighborT*) + malloc( sizeof(SmServiceDomainNeighborT) ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to allocate service domain neighbor table " + "entry." ); + return( SM_FAILED ); + } + + memset( neighbor, 0, sizeof(SmServiceDomainNeighborT) ); + + neighbor->id = db_neighbor->id; + snprintf( neighbor->name, sizeof(neighbor->name), "%s", + db_neighbor->name ); + snprintf( neighbor->service_domain, sizeof(neighbor->service_domain), + "%s", db_neighbor->service_domain ); + snprintf( neighbor->orchestration, sizeof(neighbor->orchestration), + "%s", db_neighbor->orchestration ); + snprintf( neighbor->designation, sizeof(neighbor->designation), + "%s", db_neighbor->designation ); + neighbor->generation = db_neighbor->generation; + neighbor->priority = db_neighbor->priority; + neighbor->hello_interval = db_neighbor->hello_interval; + neighbor->dead_interval = db_neighbor->dead_interval; + neighbor->wait_interval = db_neighbor->wait_interval; + neighbor->exchange_interval = db_neighbor->exchange_interval; + neighbor->state = db_neighbor->state; + neighbor->exchange_master = false; + neighbor->exchange_seq = 0; + neighbor->exchange_last_sent_id = 0; + neighbor->exchange_last_recvd_id = 0; + neighbor->exchange_timer_id = SM_TIMER_ID_INVALID; + neighbor->dead_timer_id = SM_TIMER_ID_INVALID; + neighbor->pause_timer_id = SM_TIMER_ID_INVALID; + + SM_LIST_PREPEND( _service_domain_neighbors, + (SmListEntryDataPtrT) neighbor ); + + } else { + neighbor->id = db_neighbor->id; + snprintf( neighbor->service_domain, sizeof(neighbor->service_domain), + "%s", db_neighbor->service_domain ); + snprintf( neighbor->orchestration, sizeof(neighbor->orchestration), + "%s", db_neighbor->orchestration ); + snprintf( neighbor->designation, sizeof(neighbor->designation), + "%s", db_neighbor->designation ); + neighbor->generation = db_neighbor->generation; + neighbor->priority = db_neighbor->priority; + neighbor->hello_interval = db_neighbor->hello_interval; + neighbor->dead_interval = db_neighbor->dead_interval; + neighbor->wait_interval = db_neighbor->wait_interval; + neighbor->exchange_interval = db_neighbor->exchange_interval; + neighbor->state = db_neighbor->state; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Insert +// ====================================== +SmErrorT sm_service_domain_neighbor_table_insert( char name[], + char service_domain_name[], char orchestration[], char designation[], + int generation, int priority, int hello_interval, int dead_interval, + int wait_interval, int exchange_interval ) +{ + SmServiceDomainNeighborT* neighbor; + SmDbServiceDomainNeighborT db_neighbor; + SmErrorT error; + + memset( &db_neighbor, 0, sizeof(SmDbServiceDomainNeighborT) ); + + snprintf( db_neighbor.name, sizeof(db_neighbor.name), "%s", name ); + snprintf( db_neighbor.service_domain, sizeof(db_neighbor.service_domain), + "%s", service_domain_name ); + snprintf( db_neighbor.orchestration, sizeof(db_neighbor.orchestration), + "%s", orchestration ); + snprintf( db_neighbor.designation, sizeof(db_neighbor.designation), + "%s", designation ); + db_neighbor.generation = generation; + db_neighbor.priority = priority; + db_neighbor.hello_interval = hello_interval; + db_neighbor.dead_interval = dead_interval; + db_neighbor.wait_interval = wait_interval; + db_neighbor.exchange_interval = exchange_interval; + db_neighbor.state = SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN; + + error = sm_db_service_domain_neighbors_insert( _sm_db_handle, + &db_neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to insert neighbor (%s) for service domain " + "(%s), error=%s.", name, service_domain_name, + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_neighbors_read( _sm_db_handle, name, + service_domain_name, &db_neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read neighbor (%s) for service domain " + "(%s), error=%s.", name, service_domain_name, + sm_error_str( error ) ); + return( error ); + } + + neighbor = (SmServiceDomainNeighborT*) + malloc( sizeof(SmServiceDomainNeighborT) ); + if( NULL == neighbor ) + { + DPRINTFE( "Failed to allocate service domain neighbor table entry." ); + return( SM_FAILED ); + } + + neighbor->id = db_neighbor.id; + snprintf( neighbor->name, sizeof(neighbor->name), "%s", + db_neighbor.name ); + snprintf( neighbor->service_domain, sizeof(neighbor->service_domain), + "%s", db_neighbor.service_domain ); + snprintf( neighbor->orchestration, sizeof(neighbor->orchestration), + "%s", db_neighbor.orchestration ); + snprintf( neighbor->designation, sizeof(neighbor->designation), + "%s", db_neighbor.designation ); + neighbor->generation = db_neighbor.generation; + neighbor->priority = db_neighbor.priority; + neighbor->hello_interval = db_neighbor.hello_interval; + neighbor->dead_interval = db_neighbor.dead_interval; + neighbor->wait_interval = db_neighbor.wait_interval; + neighbor->exchange_interval = db_neighbor.exchange_interval; + neighbor->state = db_neighbor.state; + neighbor->exchange_master = false; + neighbor->exchange_seq = 0; + neighbor->exchange_last_sent_id = 0; + neighbor->exchange_last_recvd_id = 0; + neighbor->exchange_timer_id = SM_TIMER_ID_INVALID; + neighbor->dead_timer_id = SM_TIMER_ID_INVALID; + neighbor->pause_timer_id = SM_TIMER_ID_INVALID; + + SM_LIST_PREPEND( _service_domain_neighbors, + (SmListEntryDataPtrT) neighbor ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Load +// ==================================== +SmErrorT sm_service_domain_neighbor_table_load( void ) +{ + SmDbServiceDomainNeighborT neighbor; + SmErrorT error; + + error = sm_db_foreach( SM_DATABASE_NAME, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME, + NULL, &neighbor, + sm_db_service_domain_neighbors_convert, + sm_service_domain_neighbor_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service domain neighbors in " + "database, error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Persist +// ======================================= +SmErrorT sm_service_domain_neighbor_table_persist( + SmServiceDomainNeighborT* neighbor ) +{ + SmDbServiceDomainNeighborT db_neighbor; + SmErrorT error; + + memset( &db_neighbor, 0, sizeof(db_neighbor) ); + + db_neighbor.id = neighbor->id; + snprintf( db_neighbor.name, sizeof(db_neighbor.name), "%s", + neighbor->name ); + snprintf( db_neighbor.service_domain, sizeof(db_neighbor.service_domain), + "%s", neighbor->service_domain ); + snprintf( db_neighbor.orchestration, sizeof(db_neighbor.orchestration), + "%s", neighbor->orchestration ); + snprintf( db_neighbor.designation, sizeof(db_neighbor.designation), + "%s", neighbor->designation ); + db_neighbor.generation = neighbor->generation; + db_neighbor.priority = neighbor->priority; + db_neighbor.hello_interval = neighbor->hello_interval; + db_neighbor.dead_interval = neighbor->dead_interval; + db_neighbor.wait_interval = neighbor->wait_interval; + db_neighbor.exchange_interval = neighbor->exchange_interval; + db_neighbor.state = neighbor->state; + + error = sm_db_service_domain_neighbors_update( _sm_db_handle, + &db_neighbor ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Initialize +// ========================================== +SmErrorT sm_service_domain_neighbor_table_initialize( void ) +{ + SmErrorT error; + + _service_domain_neighbors = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_neighbor_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service domain neighbors from database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Finalize +// ======================================== +SmErrorT sm_service_domain_neighbor_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_domain_neighbors ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_table.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_table.h new file mode 100644 index 00000000..73ebcb34 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_neighbor_table.h @@ -0,0 +1,105 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_NEIGHBOR_TABLE_H__ +#define __SM_SERVICE_DOMAIN_NEIGHBOR_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int64_t id; + char name[SM_NODE_NAME_MAX_CHAR]; + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char orchestration[SM_ORCHESTRATION_MAX_CHAR]; + char designation[SM_DESIGNATION_MAX_CHAR]; + int generation; + int priority; + int hello_interval; + int dead_interval; + int wait_interval; + int exchange_interval; + SmServiceDomainNeighborStateT state; + bool exchange_master; + int exchange_seq; + int64_t exchange_last_sent_id; + int64_t exchange_last_recvd_id; + SmTimerIdT exchange_timer_id; + SmTimerIdT dead_timer_id; + SmTimerIdT pause_timer_id; + struct timespec last_exchange_start; +} SmServiceDomainNeighborT; + +typedef void (*SmServiceDomainNeighborTableForEachCallbackT) + (void* user_data[], SmServiceDomainNeighborT* neighbor); + +// **************************************************************************** +// Service Domain Neighbor Table - Read +// ==================================== +extern SmServiceDomainNeighborT* sm_service_domain_neighbor_table_read( + char name[], char service_domain_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Read By Identifier +// ================================================== +extern SmServiceDomainNeighborT* sm_service_domain_neighbor_table_read_by_id( + int64_t id ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - For Each +// ======================================== +extern void sm_service_domain_neighbor_table_foreach( char service_domain_name[], + void* user_data[], SmServiceDomainNeighborTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Load +// ==================================== +extern SmErrorT sm_service_domain_neighbor_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Insert +// ====================================== +extern SmErrorT sm_service_domain_neighbor_table_insert( char name[], + char service_domain_name[], char orchestration[], char designation[], + int generation, int priority, int hello_interval, int dead_interval, + int wait_interval, int exchange_interval ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Persist +// ======================================= +extern SmErrorT sm_service_domain_neighbor_table_persist( + SmServiceDomainNeighborT* neighbor ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Initialize +// ========================================== +extern SmErrorT sm_service_domain_neighbor_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Neighbor Table - Finalize +// ======================================== +extern SmErrorT sm_service_domain_neighbor_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_NEIGHBOR_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_other_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_other_state.c new file mode 100644 index 00000000..5d5c2193 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_other_state.c @@ -0,0 +1,127 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_other_state.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_fsm.h" + +// **************************************************************************** +// Service Domain Other State - Entry +// ================================== +SmErrorT sm_service_domain_other_state_entry( SmServiceDomainT* domain ) +{ + domain->designation = SM_DESIGNATION_TYPE_OTHER; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Exit +// ================================= +SmErrorT sm_service_domain_other_state_exit( SmServiceDomainT* domain ) +{ + domain->designation = SM_DESIGNATION_TYPE_UNKNOWN; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Transition +// ======================================= +SmErrorT sm_service_domain_other_state_transition( SmServiceDomainT* domain, + SmServiceDomainStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Event Handler +// ========================================== +SmErrorT sm_service_domain_other_state_event_handler( SmServiceDomainT* domain, + SmServiceDomainEventT event, void* event_data[] ) +{ + bool enabled; + SmServiceDomainStateT state; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + error = sm_service_domain_utils_service_domain_enabled( domain->name, + &enabled ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if service domain (%s) is enabled, " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_DOMAIN_EVENT_HELLO_MSG: + case SM_SERVICE_DOMAIN_EVENT_NEIGHBOR_AGEOUT: + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_ENABLED: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_DISABLED: + if( !enabled ) + { + state = SM_SERVICE_DOMAIN_STATE_INITIAL; + + snprintf( reason_text, sizeof(reason_text), + "primary interface disabled" ); + + error = sm_service_domain_fsm_set_state( domain->name, state, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) failed, " + "error=%s.", sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_WAIT_EXPIRED: + // Ignore. + break; + + default: + DPRINTFD( "Service Domain (%s) ignoring event (%s).", + domain->name, sm_service_domain_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Initialize +// ======================================= +SmErrorT sm_service_domain_other_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Finalize +// ===================================== +SmErrorT sm_service_domain_other_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_other_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_other_state.h new file mode 100644 index 00000000..281c87f1 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_other_state.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_OTHER_STATE_H__ +#define __SM_SERVICE_DOMAIN_OTHER_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Other State - Entry +// ================================== +extern SmErrorT sm_service_domain_other_state_entry( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Exit +// ================================= +extern SmErrorT sm_service_domain_other_state_exit( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Transition +// ======================================= +extern SmErrorT sm_service_domain_other_state_transition( + SmServiceDomainT* domain, SmServiceDomainStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Event Handler +// ========================================== +extern SmErrorT sm_service_domain_other_state_event_handler( + SmServiceDomainT* domain, SmServiceDomainEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Initialize +// ======================================= +extern SmErrorT sm_service_domain_other_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Other State - Finalize +// ===================================== +extern SmErrorT sm_service_domain_other_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_OTHER_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_scheduler.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_scheduler.c new file mode 100644 index 00000000..816e51dc --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_scheduler.c @@ -0,0 +1,1993 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_scheduler.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_timer.h" +#include "sm_msg.h" +#include "sm_db.h" +#include "sm_db_nodes.h" +#include "sm_db_service_domain_neighbors.h" +#include "sm_node_api.h" +#include "sm_service_domain_table.h" +#include "sm_service_domain_member_table.h" +#include "sm_service_domain_assignment_table.h" +#include "sm_service_domain_utils.h" +#include "sm_service_group_api.h" +#include "sm_service_domain_filter.h" +#include "sm_service_domain_weight.h" +#include "sm_alarm.h" +#include "sm_log.h" + +#define SM_SERVICE_DOMAIN_SCHEDULE_INTERVAL_IN_MS 3000 + +static SmDbHandleT* _sm_db_handle = NULL; +static SmTimerIdT _scheduler_timer_id = SM_TIMER_ID_INVALID; +static SmMsgCallbacksT _msg_callbacks = {0}; + +// **************************************************************************** +// Service Domain Scheduler - Set Scheduling State +// =============================================== +static void sm_service_domain_scheduler_set_assignment_sched_state( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + int* total_set; + SmServiceDomainSchedulingStateT only_sched_state; + SmServiceDomainSchedulingStateT sched_state; + + only_sched_state = *(SmServiceDomainSchedulingStateT*) user_data[0]; + sched_state = *(SmServiceDomainSchedulingStateT*) user_data[1]; + total_set = (int*) user_data[2]; + + if( SM_SERVICE_DOMAIN_SCHEDULING_STATE_NIL != only_sched_state ) + { + if(( only_sched_state == assignment->sched_state )&& + ( sched_state != assignment->sched_state )) + { + assignment->sched_state = sched_state; + ++(*total_set); + } + return; + } + + if(( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT == sched_state )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE == sched_state )) + { + SmServiceDomainMemberT* member; + + member = sm_service_domain_member_table_read( assignment->name, + assignment->service_group_name ); + if( NULL == member ) + { + DPRINTFE( "Failed to read member info for assignment (%s) for " + "service domain (%s) node (%s), error=%s.", + assignment->service_group_name, assignment->name, + assignment->node_name, sm_error_str(SM_NOT_FOUND) ); + return; + } + + if( SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_PLUS_M + != member->redundancy_model ) + { + DPRINTFD( "Cannot swact assignment (%s) for service domain (%s) " + "node (%s), standby state not supported.", + assignment->service_group_name, assignment->name, + assignment->node_name ); + return; + } + } + + if( sched_state != assignment->sched_state ) + { + assignment->sched_state = sched_state; + ++(*total_set); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Set Scheduling Node State +// ==================================================== +static SmErrorT sm_service_domain_scheduler_set_sched_node_state( + char* node_name, SmServiceDomainSchedulingStateT sched_state ) +{ + int total_set = 0; + SmServiceDomainSchedulingStateT only_sched_state; + void* user_data[] = {&only_sched_state, &sched_state, &total_set}; + + only_sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NIL; + + sm_service_domain_assignment_table_foreach_node( node_name, user_data, + sm_service_domain_scheduler_set_assignment_sched_state ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Set Scheduling State +// =============================================== +static SmErrorT sm_service_domain_scheduler_set_sched_state( + char* name, SmServiceDomainSchedulingStateT sched_state ) +{ + int total_set = 0; + SmServiceDomainSchedulingStateT only_sched_state; + void* user_data[] = {&only_sched_state, &sched_state, &total_set}; + + only_sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NIL; + + sm_service_domain_assignment_table_foreach( name, user_data, + sm_service_domain_scheduler_set_assignment_sched_state ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Count Swacting Assignments +// ===================================================== +bool sm_service_domain_scheduler_count_swacting_assignments( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + return((( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT == assignment->sched_state )|| + ( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE == assignment->sched_state ))&& + !((( SM_SERVICE_GROUP_STATE_STANDBY == assignment->desired_state )&& + (( SM_SERVICE_GROUP_STATE_STANDBY == assignment->state )|| + ( SM_SERVICE_GROUP_STATE_DISABLED == assignment->state )) )|| + (( SM_SERVICE_GROUP_STATE_DISABLED == assignment->desired_state )&& + ( SM_SERVICE_GROUP_STATE_DISABLED == assignment->state )) )); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Count Disabling Assignments +// ====================================================== +bool sm_service_domain_scheduler_count_disabling_assignments( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + return(( SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE == assignment->sched_state )&& + !(( SM_SERVICE_GROUP_STATE_DISABLED == assignment->desired_state )&& + ( SM_SERVICE_GROUP_STATE_DISABLED == assignment->state )) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Count Transitioning Assignments +// ========================================================== +bool sm_service_domain_scheduler_count_transitioning_assignments( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + return(( SM_SERVICE_GROUP_STATE_GO_STANDBY == assignment->state )|| + ( SM_SERVICE_GROUP_STATE_DISABLING == assignment->state )); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Count Active Assignments +// =================================================== +bool sm_service_domain_scheduler_count_active_assignments( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + return(( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->state )|| + ( SM_SERVICE_GROUP_STATE_GO_ACTIVE == assignment->state )); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Count Standby Assignments +// ==================================================== +bool sm_service_domain_scheduler_count_standby_assignments( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + return(( SM_SERVICE_GROUP_STATE_STANDBY == assignment->state )|| + ( SM_SERVICE_GROUP_STATE_GO_STANDBY == assignment->state )); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Count Active Only Assignments +// ======================================================== +bool sm_service_domain_scheduler_count_active_only_assignments( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + bool do_count = false; + + if(( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->state )&& + ( SM_SERVICE_GROUP_STATUS_FAILED != assignment->status )) + { + SmDbNodeT node; + SmErrorT error; + + error = sm_db_nodes_read( _sm_db_handle, assignment->node_name, + &node ); + if( SM_OKAY == error ) + { + if(( SM_NODE_ADMIN_STATE_UNLOCKED == node.admin_state )&& + ( SM_NODE_READY_STATE_ENABLED == node.ready_state )) + { + do_count = true; + DPRINTFD( "Count active assignment (%s) node (%s) for " + "domain (%s).", assignment->service_group_name, + assignment->node_name, assignment->name ); + } else { + DPRINTFD( "Skip counting active assignment (%s) node (%s) " + "for domain (%s), state=%s.", + assignment->service_group_name, + assignment->node_name, assignment->name, + sm_node_state_str( node.admin_state, + node.ready_state ) ); + } + } + } + + return( do_count ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Count Standby Only Assignments +// ========================================================= +bool sm_service_domain_scheduler_count_standby_only_assignments( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + bool do_count = false; + + if(( SM_SERVICE_GROUP_STATE_STANDBY == assignment->state )&& + ( SM_SERVICE_GROUP_STATUS_FAILED != assignment->status )) + { + SmDbNodeT node; + SmErrorT error; + + error = sm_db_nodes_read( _sm_db_handle, assignment->node_name, + &node ); + if( SM_OKAY == error ) + { + if(( SM_NODE_ADMIN_STATE_UNLOCKED == node.admin_state )&& + ( SM_NODE_READY_STATE_ENABLED == node.ready_state )) + { + do_count = true; + DPRINTFD( "Count standby assignment (%s) node (%s) for " + "domain (%s).", assignment->service_group_name, + assignment->node_name, assignment->name ); + } else { + DPRINTFD( "Skip counting standby assignment (%s) node (%s) " + "for domain (%s), state=%s.", + assignment->service_group_name, + assignment->node_name, assignment->name, + sm_node_state_str( node.admin_state, + node.ready_state ) ); + } + } + } + + return( do_count ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Update State +// ======================================= +static SmErrorT sm_service_domain_scheduler_update_state( + SmServiceDomainT* domain, bool* removing_activity ) +{ + int total_set = 0; + SmServiceDomainSchedulingStateT only_sched_state, sched_state; + void* user_data[] = {&only_sched_state, &sched_state, &total_set}; + int count; + + // Update Remove Activity Scheduler States + count = sm_service_domain_assignment_table_count( domain->name, + NULL, sm_service_domain_scheduler_count_swacting_assignments ); + if( 0 == count ) + { + *removing_activity = false; + + only_sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT; + sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE; + + sm_service_domain_assignment_table_foreach( domain->name, user_data, + sm_service_domain_scheduler_set_assignment_sched_state ); + + only_sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE; + sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE; + + sm_service_domain_assignment_table_foreach( domain->name, user_data, + sm_service_domain_scheduler_set_assignment_sched_state ); + + if( 0 < total_set ) + { + SCHED_LOG( domain->name, "Clear swact scheduling states." ); + } + } else { + *removing_activity = true; + } + + // Update Disable Scheduler States + total_set = 0; + count = sm_service_domain_assignment_table_count( domain->name, NULL, + sm_service_domain_scheduler_count_disabling_assignments ); + if( 0 == count ) + { + only_sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE; + sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE; + + sm_service_domain_assignment_table_foreach( domain->name, user_data, + sm_service_domain_scheduler_set_assignment_sched_state ); + + if( 0 < total_set ) + { + SCHED_LOG( domain->name, "Clear disable scheduling states." ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Sort Assignments +// =========================================== +static int sm_service_domain_scheduler_sort_assignments( const void* lhs, + const void* rhs ) +{ + SmServiceDomainAssignmentT* assignment_lhs; + SmServiceDomainAssignmentT* assignment_rhs; + + assignment_lhs = (SmServiceDomainAssignmentT*) lhs; + assignment_rhs = (SmServiceDomainAssignmentT*) rhs; + + // Descending Order based on weight. + if( assignment_lhs->sched_weight > assignment_rhs->sched_weight ) + { + return( -1 ); // lhs before rhs + } + + if( assignment_lhs->sched_weight == assignment_rhs->sched_weight ) + { + // Ascending Order based on last state change. + if( assignment_lhs->last_state_change < assignment_rhs->last_state_change ) + { + return( -1 ); // lhs before rhs + } + + // Ascending Order based on last state change. + if( assignment_lhs->last_state_change == assignment_rhs->last_state_change ) + { + return( 0 ); // lhs before rhs + } + + // Ascending Order based on last state change. + if( assignment_lhs->last_state_change > assignment_rhs->last_state_change ) + { + return( 1 ); // lhs after rhs + } + } + + if( assignment_lhs->sched_weight < assignment_rhs->sched_weight ) + { + return( 1 ); // lhs after rhs + } + + return( 0 ); // lhs before rhs +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Disable Active Member +// ================================================ +static void sm_service_domain_scheduler_disable_active_member( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE == assignment->sched_list ) || + ( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE == assignment->sched_list )) + { + assignment->sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Unselect Active Member +// ================================================= +static void sm_service_domain_scheduler_unselect_active_member( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + SmServiceDomainMemberT* member = (SmServiceDomainMemberT*) user_data[0]; + int* current_active = (int*) user_data[1]; + + if( 0 != strcmp( member->service_group_name, assignment->service_group_name ) ) + { + return; + } + + if( SM_SERVICE_DOMAIN_WEIGHT_UNSELECTABLE_ACTIVE == assignment->sched_weight ) + { + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY; + DPRINTFD( "Unselect assignment (%s-%s-%s), unselectable.", + assignment->name, assignment->node_name, + assignment->service_group_name ); + return; + } + + if( *current_active < member->n_active ) + { + ++(*current_active); + + DPRINTFD( "Selected assignment (%s-%s-%s).", assignment->name, + assignment->node_name, assignment->service_group_name ); + } else { + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY; + + DPRINTFD( "Unselected assignment (%s-%s-%s).", assignment->name, + assignment->node_name, assignment->service_group_name ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Select Active Member +// =============================================== +static void sm_service_domain_scheduler_select_active_member( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + SmServiceDomainMemberT* member = (SmServiceDomainMemberT*) user_data[0]; + int* current_active = (int*) user_data[1]; + + if( 0 != strcmp( member->service_group_name, assignment->service_group_name ) ) + { + return; + } + + if( SM_SERVICE_DOMAIN_WEIGHT_UNSELECTABLE_ACTIVE == assignment->sched_weight ) + { + DPRINTFD( "Skipping assignment (%s-%s-%s), unselectable.", + assignment->name, assignment->node_name, + assignment->service_group_name ); + return; + } + + if( *current_active < member->n_active ) + { + ++(*current_active ); + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE; + + DPRINTFD( "Selected assignment (%s-%s-%s).", assignment->name, + assignment->node_name, assignment->service_group_name ); + } else { + DPRINTFD( "Not selected assignment (%s-%s-%s).", assignment->name, + assignment->node_name, assignment->service_group_name ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Select Active Members +// ================================================ +static void sm_service_domain_scheduler_select_active_members( void* user_data[], + SmServiceDomainMemberT* member ) +{ + int count; + int current_active; + SmServiceDomainT* domain = (SmServiceDomainT*) user_data[0]; + void* user_data2[] = {member, ¤t_active}; + + sm_service_domain_assignment_table_sort( + sm_service_domain_scheduler_sort_assignments ); + + // Count members transitioning to standby or disabled. + count = sm_service_domain_assignment_table_count_service_group( + member->name, member->service_group_name, NULL, + sm_service_domain_scheduler_count_transitioning_assignments ); + if( 0 != count ) + { + SCHED_LOG( domain->name, "Members transitioning to standby " + "or disabled, count=%i.", count ); + return; + } + + // Count active and transitioning to active members. + count = sm_service_domain_assignment_table_count_service_group( + member->name, member->service_group_name, NULL, + sm_service_domain_scheduler_count_active_assignments ); + + if(( SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_DISABLE_ALL_ACTIVE + == domain->split_brain_recovery )&&( count > member->n_active )) + { + SCHED_LOG( domain->name, "Too many active service domain (%s) " + "members (%s), disable all and recover, count=%i.", + member->name, member->service_group_name, count ); + + sm_service_domain_assignment_table_foreach_service_group( + member->name, member->service_group_name, NULL, + sm_service_domain_scheduler_disable_active_member ); + } + else if( count > member->n_active ) + { + current_active = 0; + // Go-Active List + sm_service_domain_assignment_table_foreach_schedule_list( member->name, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE, user_data2, + sm_service_domain_scheduler_unselect_active_member ); + + // Active List + sm_service_domain_assignment_table_foreach_schedule_list( member->name, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE, user_data2, + sm_service_domain_scheduler_unselect_active_member ); + + } else if( count < member->n_active ) { + current_active = count; + + // Standby List. + sm_service_domain_assignment_table_foreach_schedule_list( member->name, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY, user_data2, + sm_service_domain_scheduler_select_active_member ); + + if( current_active < member->n_active ) + { + // Disabled List. + sm_service_domain_assignment_table_foreach_schedule_list( member->name, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED, user_data2, + sm_service_domain_scheduler_select_active_member ); + } + } else { + SCHED_LOG( domain->name, "Active service domain (%s) members " + "(%s) already selected.", member->name, + member->service_group_name ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Select Active +// ======================================== +static SmErrorT sm_service_domain_scheduler_select_active( + SmServiceDomainT* domain ) +{ + void* user_data[] = {domain}; + + sm_service_domain_member_table_foreach( domain->name, user_data, + sm_service_domain_scheduler_select_active_members ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Unselect Standby Member +// ================================================== +static void sm_service_domain_scheduler_unselect_standby_member( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + SmServiceDomainMemberT* member = (SmServiceDomainMemberT*) user_data[0]; + int* current_standby = (int*) user_data[1]; + + if( 0 != strcmp( member->service_group_name, assignment->service_group_name ) ) + { + return; + } + + if(( *current_standby < member->m_standby )&& + ( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT != assignment->sched_state )&& + ( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE != assignment->sched_state )) + { + ++(*current_standby); + + } else { + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Select Standby Member +// ================================================ +static void sm_service_domain_scheduler_select_standby_member( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + SmServiceDomainMemberT* member = (SmServiceDomainMemberT*) user_data[0]; + int* current_standby = (int*) user_data[1]; + + if( 0 != strcmp( member->service_group_name, assignment->service_group_name ) ) + { + return; + } + + if( *current_standby < member->m_standby ) + { + ++(*current_standby ); + assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Select Standby Members +// ================================================= +static void sm_service_domain_scheduler_select_standby_members( void* user_data[], + SmServiceDomainMemberT* member ) +{ + int count; + int current_standby; + SmServiceDomainT* domain = (SmServiceDomainT*) user_data[0]; + void* user_data2[] = {member, ¤t_standby}; + + sm_service_domain_assignment_table_sort( + sm_service_domain_scheduler_sort_assignments ); + + count = sm_service_domain_assignment_table_count_service_group( + member->name, member->service_group_name, NULL, + sm_service_domain_scheduler_count_standby_assignments ); + if( count > member->m_standby ) + { + current_standby = 0; + + // Standby List. + sm_service_domain_assignment_table_foreach_schedule_list( member->name, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY, user_data2, + sm_service_domain_scheduler_unselect_standby_member ); + + } else if( count < member->m_standby ) { + current_standby = count; + + // Disabled List. + sm_service_domain_assignment_table_foreach_schedule_list( member->name, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED, user_data2, + sm_service_domain_scheduler_select_standby_member ); + + } else { + SCHED_LOG( domain->name, "Standby service domain (%s) members " + "(%s) already selected.", member->name, + member->service_group_name ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Select Standby +// ========================================= +static SmErrorT sm_service_domain_scheduler_select_standby( + SmServiceDomainT* domain ) +{ + void* user_data[] = {domain}; + + sm_service_domain_member_table_foreach( domain->name, user_data, + sm_service_domain_scheduler_select_standby_members ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Apply Change +// ======================================= +static void sm_service_domain_scheduler_apply_change( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + bool recover = false; + bool escalate_recovery = false; + bool clear_fatal_condition = false; + struct timespec ts; + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceGroupStateT desired_state; + SmServiceGroupActionT action; + SmServiceGroupActionFlagsT action_flags = 0; + SmErrorT error; + + switch( assignment->sched_list ) + { + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE: + desired_state = SM_SERVICE_GROUP_STATE_ACTIVE; + action = SM_SERVICE_GROUP_ACTION_GO_ACTIVE; + + if(( desired_state == assignment->desired_state )&& + (( SM_SERVICE_GROUP_STATUS_WARN == assignment->status )|| + ( SM_SERVICE_GROUP_STATUS_DEGRADED == assignment->status ))) + { + recover = true; + clear_fatal_condition = true; + } + break; + + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE: + desired_state = SM_SERVICE_GROUP_STATE_ACTIVE; + action = SM_SERVICE_GROUP_ACTION_GO_ACTIVE; + + if(( SM_SERVICE_GROUP_STATUS_FAILED == assignment->status )&& + ( SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE + == assignment->condition )) + { + recover = true; + + } else if(( SM_SERVICE_GROUP_STATUS_WARN == assignment->status )|| + ( SM_SERVICE_GROUP_STATUS_DEGRADED == assignment->status )) + { + recover = true; + clear_fatal_condition = true; + } + break; + + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY: + desired_state = SM_SERVICE_GROUP_STATE_STANDBY; + action = SM_SERVICE_GROUP_ACTION_GO_STANDBY; + + if(( desired_state == assignment->desired_state )&& + (( SM_SERVICE_GROUP_STATUS_WARN == assignment->status )|| + ( SM_SERVICE_GROUP_STATUS_DEGRADED == assignment->status ))) + { + recover = true; + } + break; + + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY: + desired_state = SM_SERVICE_GROUP_STATE_STANDBY; + action = SM_SERVICE_GROUP_ACTION_GO_STANDBY; + break; + + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED: + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING: + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE: + desired_state = SM_SERVICE_GROUP_STATE_DISABLED; + action = SM_SERVICE_GROUP_ACTION_DISABLE; + break; + + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED: + // An assignment can be failed or failed with a fatal error and be + // on the failed list. The failed list indicates recovery without + // escalation should be attempted. + desired_state = SM_SERVICE_GROUP_STATE_NIL; + action = SM_SERVICE_GROUP_ACTION_RECOVER; + recover = true; + clear_fatal_condition = (SM_SERVICE_GROUP_CONDITION_FATAL_FAILURE + == assignment->condition); + break; + + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL: + // An assignment on this list indicates that recovery with + // escalation should be attempted as there is another healthier + // assignment. + desired_state = SM_SERVICE_GROUP_STATE_NIL; + action = SM_SERVICE_GROUP_ACTION_RECOVER; + recover = true; + escalate_recovery = true; + clear_fatal_condition = true; + break; + + default: + DPRINTFI( "Unknown list specified for member (%s) of service " + "domain (%s) node (%s).", + assignment->service_group_name, assignment->name, + assignment->node_name ); + return; + break; + } + + if(( SM_SERVICE_GROUP_STATE_NIL != desired_state )&& + ( desired_state != assignment->desired_state )) + { + clock_gettime( CLOCK_MONOTONIC_RAW, &ts ); + + SCHED_LOG( assignment->name, "Update desired state from (%s) to (%s) " + "for member (%s) of node (%s) current_state=%s, " + "last_state_change=%ld, recover=%s, escalate_recovery=%s, " + "clear_fatal_condition=%s.", + sm_service_group_state_str(assignment->desired_state), + sm_service_group_state_str(desired_state), + assignment->service_group_name, assignment->node_name, + sm_service_group_state_str(assignment->state), + (long) ts.tv_sec, recover ? "yes" : "no", + escalate_recovery ? "yes" : "no", + clear_fatal_condition ? "yes" : "no" ); + + assignment->desired_state = desired_state; + assignment->last_state_change = (long) ts.tv_sec; + + error = sm_service_domain_assignment_table_persist( assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update assignment (%s) for service " + "domain (%s) node (%s), error=%s.", + assignment->service_group_name, assignment->name, + assignment->node_name, sm_error_str( error ) ); + return; + } + } else { + SCHED_LOG( assignment->name, "No update of desired state (%s) " + "for member (%s) of node (%s) current_state=%s, " + "last_state_change=%ld, recover=%s, escalate_recovery=%s, " + "clear_fatal_condition=%s.", + sm_service_group_state_str(assignment->desired_state), + assignment->service_group_name, assignment->node_name, + sm_service_group_state_str(assignment->state), + assignment->last_state_change, recover ? "yes" : "no", + escalate_recovery ? "yes" : "no", + clear_fatal_condition ? "yes" : "no" ); + } + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return; + } + + if( 0 == strcmp( hostname, assignment->node_name ) ) + { + switch( action ) + { + case SM_SERVICE_GROUP_ACTION_DISABLE: + error = sm_service_group_api_disable( + assignment->service_group_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform disable action on member (%s) " + "for service domain (%s) on node (%s), error=%s.", + assignment->service_group_name, + assignment->name, assignment->node_name, + sm_error_str(error) ); + return; + } + break; + + case SM_SERVICE_GROUP_ACTION_GO_ACTIVE: + error = sm_service_group_api_go_active( + assignment->service_group_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform go-active action on member (%s) " + "for service domain (%s) on node (%s), error=%s.", + assignment->service_group_name, + assignment->name, assignment->node_name, + sm_error_str(error) ); + return; + } + break; + + case SM_SERVICE_GROUP_ACTION_GO_STANDBY: + error = sm_service_group_api_go_standby( + assignment->service_group_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform go-standby action on member (%s) " + "for service domain (%s) on node (%s), error=%s.", + assignment->service_group_name, + assignment->name, assignment->node_name, + sm_error_str(error) ); + return; + } + break; + + case SM_SERVICE_GROUP_ACTION_RECOVER: + error = sm_service_group_api_recover( + assignment->service_group_name, + escalate_recovery, clear_fatal_condition ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform recovery action on member (%s) " + "for service domain (%s) on node (%s), error=%s.", + assignment->service_group_name, + assignment->name, assignment->node_name, + sm_error_str(error) ); + return; + } + break; + + default: + DPRINTFE( "Unknown action (%s) specified for member " + "(%s) for service domain (%s) on node (%s).", + sm_service_group_action_str(action), + assignment->service_group_name, assignment->name, + assignment->node_name ); + break; + } + + if(( recover )&&( SM_SERVICE_GROUP_ACTION_RECOVER != action )) + { + error = sm_service_group_api_recover( + assignment->service_group_name, + escalate_recovery, clear_fatal_condition ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform recovery action on member (%s) " + "for service domain (%s) on node (%s), error=%s.", + assignment->service_group_name, + assignment->name, assignment->node_name, + sm_error_str(error) ); + return; + } + } + } else { + if( recover ) + { + SM_FLAG_SET( action_flags, SM_SERVICE_GROUP_ACTION_FLAG_RECOVER ); + } + + if( escalate_recovery ) + { + SM_FLAG_SET( action_flags, + SM_SERVICE_GROUP_ACTION_FLAG_ESCALATE_RECOVERY ); + } + + if( clear_fatal_condition ) + { + SM_FLAG_SET( action_flags, + SM_SERVICE_GROUP_ACTION_FLAG_CLEAR_FATAL_CONDITION ); + } + + error = sm_service_domain_utils_send_member_request( + assignment->name, assignment->node_name, + assignment->id, assignment->service_group_name, + action, action_flags ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send member update for service domain " + "(%s) node (%s) of member (%s).", assignment->name, + assignment->node_name, assignment->service_group_name ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Apply Changes +// ======================================== +static SmErrorT sm_service_domain_scheduler_apply_changes( + char service_domain_name[] ) +{ + sm_service_domain_assignment_table_foreach( service_domain_name, NULL, + sm_service_domain_scheduler_apply_change ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Dump Entry +// ===================================== +static void sm_service_domain_scheduler_dump_entry( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + bool* first_one = (bool*) user_data[0]; + + if( *first_one ) + { + SmServiceDomainSchedulingListT* sched_list; + + sched_list = (SmServiceDomainSchedulingListT*) user_data[1]; + + SCHED_LOG( assignment->name, "List (%s):", + sm_service_domain_scheduling_list_str( *sched_list) ); + *first_one = false; + } + + SCHED_LOG( assignment->name, " Node (%s) - Service Group (%s) - " + "desired_state=%s, state=%s, status=%s, condition=%s, " + "health=%"PRIX64", last_state_change=%li, sched_state=%s, " + "sched_weight=%i.", assignment->node_name, + assignment->service_group_name, + sm_service_group_state_str(assignment->desired_state), + sm_service_group_state_str(assignment->state), + sm_service_group_status_str(assignment->status), + sm_service_group_condition_str(assignment->condition), + assignment->health, assignment->last_state_change, + sm_service_domain_scheduling_state_str(assignment->sched_state), + assignment->sched_weight ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Dump +// =============================== +static void sm_service_domain_scheduler_dump( SmServiceDomainT* domain ) +{ + bool first_one; + SmServiceDomainSchedulingListT sched_list; + void* user_data[] = {&first_one, &sched_list}; + + sm_service_domain_assignment_table_sort( + sm_service_domain_scheduler_sort_assignments ); + + int list; + for( list=SM_SERVICE_DOMAIN_SCHEDULING_LIST_NIL; + SM_SERVICE_DOMAIN_SCHEDULING_LIST_MAX > list; ++list ) + { + first_one = true; + sched_list = (SmServiceDomainSchedulingListT) list; + + sm_service_domain_assignment_table_foreach_schedule_list( + domain->name, sched_list, user_data, + sm_service_domain_scheduler_dump_entry ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Schedule +// =================================== +static SmErrorT sm_service_domain_scheduler_schedule( SmServiceDomainT* domain ) +{ + long ms_expired; + SmTimeT time_prev, time_now; + bool removing_activity; + SmServiceDomainFilterCountsT filter_counts; + SmErrorT error; + + // Apply Preselect Filters. + sm_time_get( &time_prev ); + + error = sm_service_domain_filter_preselect_apply( domain->name, + &filter_counts ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) filter preselect apply failed, " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - preselect apply filters, took %li ms.", + ms_expired ); + + SCHED_LOG( domain->name, "Filter counts: active(%i) go-active(%i) " + "standby(%i) go-standby(%i) disabling(%i) disabled (%i) " + "failed (%i) fatal (%i) unavailable(%i) total(%i)", + filter_counts.active_members, filter_counts.go_active_members, + filter_counts.standby_members, filter_counts.go_standby_members, + filter_counts.disabling_members, filter_counts.disabled_members, + filter_counts.failed_members, filter_counts.fatal_members, + filter_counts.unavailable_members, filter_counts.total_members ); + + // Apply Weights. + sm_time_get( &time_prev ); + + error = sm_service_domain_weight_apply( domain->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) weight apply failed, error=%s.", + domain->name, sm_error_str( error ) ); + return( error ); + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply weights, took %li ms.", ms_expired ); + + // Update scheduling states. + sm_time_get( &time_prev ); + + error = sm_service_domain_scheduler_update_state( domain, + &removing_activity ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) scheduler state update failed, " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - update scheduling states, took %li ms.", + ms_expired ); + + // Select Active. + sm_time_get( &time_prev ); + + if( removing_activity ) + { + SCHED_LOG( domain->name, "Removing activity, active selection " + "delayed." ); + } else { + error = sm_service_domain_scheduler_select_active( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to select active, error=%s.", + sm_error_str( error ) ); + return( error ); + } + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - select active, took %li ms.", ms_expired ); + + // Select Standby. + sm_time_get( &time_prev ); + + error = sm_service_domain_scheduler_select_standby( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to select standby, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - select standby, took %li ms.", ms_expired ); + + // Apply Post Select Filters. + sm_time_get( &time_prev ); + + error = sm_service_domain_filter_post_select_apply( domain->name, + &filter_counts ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) filter post select apply failed, " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - post select apply filters, took %li ms.", + ms_expired ); + + SCHED_LOG( domain->name, "Filter counts: active(%i) go-active(%i) " + "standby(%i) go-standby(%i) disabling(%i) disabled (%i) " + "failed (%i) fatal (%i) unavailable(%i) total(%i)", + filter_counts.active_members, filter_counts.go_active_members, + filter_counts.standby_members, filter_counts.go_standby_members, + filter_counts.disabling_members, filter_counts.disabled_members, + filter_counts.failed_members, filter_counts.fatal_members, + filter_counts.unavailable_members, filter_counts.total_members ); + + sm_service_domain_scheduler_dump( domain ); + + // Apply Changes. + sm_time_get( &time_prev ); + + error = sm_service_domain_scheduler_apply_changes( domain->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) apply changes failed, error=%s.", + domain->name, sm_error_str( error ) ); + return( error ); + } + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + DPRINTFD( "Scheduler execute - apply changes, took %li ms.", ms_expired ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Assignment State Alarms +// ================================================== +static void sm_service_domain_scheduler_assignment_state_alarms( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + SmAlarmSeverityT severity; + SmAlarmSpecificProblemTextT problem_text = ""; + + switch( assignment->status ) + { + case SM_SERVICE_GROUP_STATUS_WARN: + severity = SM_ALARM_SEVERITY_MINOR; + snprintf( problem_text, sizeof(problem_text), + "service group %s warning", + assignment->service_group_name ); + break; + + case SM_SERVICE_GROUP_STATUS_DEGRADED: + severity = SM_ALARM_SEVERITY_MAJOR; + snprintf( problem_text, sizeof(problem_text), + "service group %s degraded", + assignment->service_group_name ); + break; + + case SM_SERVICE_GROUP_STATUS_FAILED: + severity = SM_ALARM_SEVERITY_CRITICAL; + snprintf( problem_text, sizeof(problem_text), + "service group %s failure", + assignment->service_group_name ); + break; + + case SM_SERVICE_GROUP_STATUS_NONE: + severity = SM_ALARM_SEVERITY_CLEARED; + break; + + default: + DPRINTFD( "Ignore service domain (%s) assignment (%s) " + "status (%s = %i) on node (%s).", assignment->name, + assignment->service_group_name, + sm_service_group_status_str(assignment->status), + assignment->status, assignment->node_name ); + return; + break; + } + + if( SM_ALARM_SEVERITY_CLEARED == severity ) + { + sm_alarm_clear( SM_ALARM_SERVICE_GROUP_STATE, assignment->node_name, + assignment->name, assignment->service_group_name ); + } else { + sm_alarm_raise_state_alarm( SM_ALARM_SERVICE_GROUP_STATE, + assignment->node_name, assignment->name, + assignment->service_group_name, severity, + SM_ALARM_PROBABLE_CAUSE_UNDERLYING_RESOURCE_UNAVAILABLE, + sm_service_group_state_str(assignment->state), + sm_service_group_status_str(assignment->status), + sm_service_group_condition_str(assignment->condition), + problem_text, assignment->reason_text, "", true ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Assignment Redundancy Alarm +// ====================================================== +static void sm_service_domain_scheduler_assignment_redundancy_alarm( + void* user_data[], SmServiceDomainMemberT* member ) +{ + SmAlarmSpecificProblemTextT problem_text = ""; + SmAlarmAdditionalTextT additional_text; + SmAlarmProposedRepairActionT proposed_repair_action; + char log_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + int count; + + snprintf( problem_text, sizeof(problem_text), "service group %s loss " + "of redundancy", member->service_group_name ); + + snprintf( log_text, sizeof(log_text), "service group %s redundancy " + "restored", member->service_group_name ); + + snprintf( proposed_repair_action, sizeof(proposed_repair_action), + "bring a controller node back in to service, otherwise " + "contact next level of support" ); + + count = sm_service_domain_assignment_table_count_service_group( + member->name, member->service_group_name, NULL, + sm_service_domain_scheduler_count_active_only_assignments ); + + if( count == member->n_active ) + { + if( SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_PLUS_M + == member->redundancy_model ) + { + count = sm_service_domain_assignment_table_count_service_group( + member->name, member->service_group_name, NULL, + sm_service_domain_scheduler_count_standby_only_assignments ); + if( count < member->m_standby ) + { + if( 0 == count ) + { + snprintf( additional_text, sizeof(additional_text), + "expected %i standby member%s but no standby " + "members available", member->m_standby, + (1 == member->m_standby) ? "" : "s" ); + } else { + snprintf( additional_text, sizeof(additional_text), + "expected %i standby member%s but only %i " + "standby member%s available", member->m_standby, + (1 == member->m_standby) ? "" : "s", count, + (1 == count) ? "" : "s" ); + } + + sm_alarm_raise_threshold_alarm( SM_ALARM_SERVICE_GROUP_REDUNDANCY, + "", member->name, member->service_group_name, + SM_ALARM_SEVERITY_MAJOR, + SM_ALARM_PROBABLE_CAUSE_UNDERLYING_RESOURCE_UNAVAILABLE, + member->m_standby, count, problem_text, additional_text, + proposed_repair_action, true ); + + snprintf( log_text, sizeof(log_text), "%s; %s", problem_text, + additional_text ); + + } else { + sm_alarm_clear( SM_ALARM_SERVICE_GROUP_REDUNDANCY, "", + member->name, member->service_group_name ); + } + } else { + sm_alarm_clear( SM_ALARM_SERVICE_GROUP_REDUNDANCY, "", + member->name, member->service_group_name ); + } + } else { + if( count < member->n_active ) + { + SmAlarmSeverityT alarm_severity; + + if( 0 == count ) + { + snprintf( problem_text, sizeof(problem_text), "service group " + "%s has no active members available", + member->service_group_name ); + + snprintf( additional_text, sizeof(additional_text), + "expected %i active member%s", member->n_active, + (1 == member->n_active) ? "" : "s" ); + + alarm_severity = SM_ALARM_SEVERITY_CRITICAL; + + } else { + snprintf( additional_text, sizeof(additional_text), + "expected %i active member%s but only %i " + "active member%s available", member->n_active, + (1 == member->n_active) ? "" : "s", count, + (1 == count) ? "" : "s" ); + + alarm_severity = SM_ALARM_SEVERITY_MAJOR; + } + + sm_alarm_raise_threshold_alarm( SM_ALARM_SERVICE_GROUP_REDUNDANCY, + "", member->name, member->service_group_name, + alarm_severity, + SM_ALARM_PROBABLE_CAUSE_UNDERLYING_RESOURCE_UNAVAILABLE, + member->n_active, count, problem_text, additional_text, + proposed_repair_action, true ); + + snprintf( log_text, sizeof(log_text), "%s; %s", problem_text, + additional_text ); + + } else { + sm_alarm_clear( SM_ALARM_SERVICE_GROUP_REDUNDANCY, "", + member->name, member->service_group_name ); + } + } + + if( 0 != strcmp( member->redundancy_log_text, log_text ) ) + { + snprintf( member->redundancy_log_text, + sizeof(member->redundancy_log_text), "%s", log_text ); + + sm_log_service_group_redundancy_change( member->service_group_name, + member->redundancy_log_text ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Assignment Cleanup Alarms +// ==================================================== +static void sm_service_domain_scheduler_assignment_cleanup_alarms( + void* user_data[], SmServiceDomainMemberT* member ) +{ + member->redundancy_log_text[0] = '\0'; +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Manage Alarms +// ======================================== +static SmErrorT sm_service_domain_scheduler_manage_alarms( + SmServiceDomainT* domain ) +{ + if( SM_SERVICE_DOMAIN_STATE_LEADER == domain->state ) + { + // Manage Service Domain Assignment State Alarms + sm_service_domain_assignment_table_foreach( domain->name, NULL, + sm_service_domain_scheduler_assignment_state_alarms ); + + // Manage Service Domain Assignment Redundancy Alarms + sm_service_domain_member_table_foreach( domain->name, NULL, + sm_service_domain_scheduler_assignment_redundancy_alarm ); + + } else { + sm_service_domain_member_table_foreach( domain->name, NULL, + sm_service_domain_scheduler_assignment_cleanup_alarms ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Schedule Service Domain +// ================================================== +void sm_service_domain_scheduler_schedule_service_domain( + SmServiceDomainT* domain ) +{ + bool syncing; + SmErrorT error; + + SCHED_LOG_START( domain->name, "--start------------------------------" ); + SCHED_LOG( domain->name, "%s.", + sm_service_domain_state_str(domain->state) ); + + if( SM_SERVICE_DOMAIN_STATE_LEADER == domain->state ) + { + error = sm_service_domain_utils_service_domain_neighbors_syncing( + domain->name, &syncing ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if service domain (%s) neighbors " + "are syncing, error=%s.", domain->name, + sm_error_str( error ) ); + goto DONE; + } + + if( syncing ) + { + DPRINTFI( "Service domain (%s) neighbors are syncing.", + domain->name ); + SCHED_LOG( domain->name, "neighbors are syncing."); + goto DONE; + } + + error = sm_service_domain_scheduler_schedule( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to schedule service domain (%s), error=%s.", + domain->name, sm_error_str( error ) ); + goto DONE; + } + + } else { + error = sm_service_domain_scheduler_set_sched_state( + domain->name, SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set scheduling state for (%s), error=%s.", + domain->name, sm_error_str( error ) ); + goto DONE; + } + } + + error = sm_service_domain_scheduler_manage_alarms( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to manage alarms service domain (%s), " + "error=%s.", domain->name, sm_error_str( error ) ); + goto DONE; + } + +DONE: + SCHED_LOG_DONE( domain->name, "--complete---------------------------" ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Schedule Service Domain Timeout +// ========================================================== +static void sm_service_domain_scheduler_schedule_service_domain_timeout( + void* user_data[], SmServiceDomainT* domain ) +{ + sm_service_domain_scheduler_schedule_service_domain( domain ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Timeout +// ================================== +static bool sm_service_domain_scheduler_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + long ms_expired; + SmTimeT time_prev, time_now; + + sm_time_get( &time_prev ); + + sm_service_domain_table_foreach( NULL, + sm_service_domain_scheduler_schedule_service_domain_timeout ); + + sm_time_get( &time_now ); + + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + + DPRINTFD( "Scheduler execute, took %li ms.", ms_expired ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Swact Node +// ===================================== +SmErrorT sm_service_domain_scheduler_swact_node( char node_name[], bool force, + SmUuidT request_uuid ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR] = ""; + char log_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainSchedulingStateT sched_state; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + } + + if( force ) + { + sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE; + snprintf( log_text, sizeof(log_text), "issued against host %s", + node_name ); + sm_log_node_state_change( hostname, "", "swact-force", log_text ); + + } else { + sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT; + snprintf( log_text, sizeof(log_text), "issued against host %s", + node_name ); + sm_log_node_state_change( hostname, "", "swact", log_text ); + } + + DPRINTFI("Swact from (%s) to (%s) start", node_name, hostname); + error = sm_service_domain_scheduler_set_sched_node_state( node_name, + sched_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set node scheduling state, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Node Swact Message Callback +// ====================================================== +static void sm_service_domain_scheduler_node_swact_msg_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char node_name[], bool force, SmUuidT request_uuid ) +{ + SmErrorT error; + + error = sm_service_domain_scheduler_swact_node( node_name, force, + request_uuid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set node scheduling state, error=%s.", + sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Member Request Message Callback +// ========================================================== +static void sm_service_domain_scheduler_member_request_msg_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char service_domain_name[], char node_name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupActionT member_action, + SmServiceGroupActionFlagsT member_action_flags ) +{ + bool insync; + bool recover, escalate_recovery, clear_fatal_condition; + SmServiceGroupStateT member_desired_state; + SmServiceDomainAssignmentT* assignment; + SmErrorT error; + + assignment = sm_service_domain_assignment_table_read( service_domain_name, + member_node_name, member_name ); + if( NULL == assignment ) + { + DPRINTFE( "Failed to read service domain (%s) assignment for node " + "(%s) of member (%s), error=%s.", service_domain_name, + node_name, member_name, sm_error_str(SM_NOT_FOUND) ); + return; + } + + error = sm_service_domain_utils_service_domain_neighbor_insync( + service_domain_name, node_name, + &insync ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if service domain (%s) neighbor (%s) " + "is insync for assignment (%s).", service_domain_name, + node_name, member_name ); + return; + } + + if( !insync ) + { + DPRINTFI( "Service domain (%s) neighbor (%s) is not insync for " + "assignment (%s).", service_domain_name, member_node_name, + member_name ); + goto SEND_UPDATE; + } + + recover = SM_FLAG_IS_SET( member_action_flags, + SM_SERVICE_GROUP_ACTION_FLAG_RECOVER ); + escalate_recovery = SM_FLAG_IS_SET( member_action_flags, + SM_SERVICE_GROUP_ACTION_FLAG_ESCALATE_RECOVERY ); + clear_fatal_condition = SM_FLAG_IS_SET( member_action_flags, + SM_SERVICE_GROUP_ACTION_FLAG_CLEAR_FATAL_CONDITION ); + + switch( member_action ) + { + case SM_SERVICE_GROUP_ACTION_DISABLE: + member_desired_state = SM_SERVICE_GROUP_STATE_DISABLED; + + error = sm_service_domain_utils_update_assignment( + service_domain_name, member_node_name, member_name, + member_desired_state, assignment->state, + assignment->status, assignment->condition, + assignment->health, assignment->reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to update " + "assignment (%s), error=%s.", service_domain_name, + member_node_name, member_name, + sm_error_str( error ) ); + return; + } + + error = sm_service_group_api_disable( member_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform action (%s) on member (%s) for " + "service domain (%s) on node (%s), error=%s.", + sm_service_group_action_str(member_action), + member_name, service_domain_name, member_node_name, + sm_error_str(error) ); + return; + } + break; + + case SM_SERVICE_GROUP_ACTION_GO_ACTIVE: + member_desired_state = SM_SERVICE_GROUP_STATE_ACTIVE; + + error = sm_service_domain_utils_update_assignment( + service_domain_name, member_node_name, member_name, + member_desired_state, assignment->state, + assignment->status, assignment->condition, + assignment->health, assignment->reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to update " + "assignment (%s), error=%s.", service_domain_name, + member_node_name, member_name, + sm_error_str( error ) ); + return; + } + + error = sm_service_group_api_go_active( member_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform action (%s) on member (%s) for " + "service domain (%s) on node (%s), error=%s.", + sm_service_group_action_str(member_action), + member_name, service_domain_name, member_node_name, + sm_error_str(error) ); + return; + } + break; + + case SM_SERVICE_GROUP_ACTION_GO_STANDBY: + member_desired_state = SM_SERVICE_GROUP_STATE_STANDBY; + + error = sm_service_domain_utils_update_assignment( + service_domain_name, member_node_name, member_name, + member_desired_state, assignment->state, + assignment->status, assignment->condition, + assignment->health, assignment->reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to update " + "assignment (%s), error=%s.", service_domain_name, + member_node_name, member_name, + sm_error_str( error ) ); + return; + } + + error = sm_service_group_api_go_standby( member_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform action (%s) on member (%s) for " + "service domain (%s) on node (%s), error=%s.", + sm_service_group_action_str(member_action), + member_name, service_domain_name, member_node_name, + sm_error_str(error) ); + return; + } + break; + + case SM_SERVICE_GROUP_ACTION_AUDIT: + // Will send the current member state below. + break; + + case SM_SERVICE_GROUP_ACTION_RECOVER: + error = sm_service_group_api_recover( member_name, escalate_recovery, + clear_fatal_condition ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform action (%s) on member (%s) for " + "service domain (%s) on node (%s), error=%s.", + sm_service_group_action_str(member_action), + member_name, service_domain_name, member_node_name, + sm_error_str(error) ); + return; + } + break; + + default: + DPRINTFE( "Service domain (%s) unknown action (%s) received for " + "member (%s).", service_domain_name, + sm_service_group_action_str(member_action), + member_name ); + return; + + break; + } + + if(( recover )&&( SM_SERVICE_GROUP_ACTION_RECOVER != member_action )) + { + error = sm_service_group_api_recover( member_name, escalate_recovery, + clear_fatal_condition ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform recovery action on member (%s) for " + "service domain (%s) on node (%s), error=%s.", + member_name, service_domain_name, member_node_name, + sm_error_str(error) ); + return; + } + } + +SEND_UPDATE: + error = sm_service_domain_utils_send_member_update( service_domain_name, + member_node_name, member_id, member_name, + assignment->desired_state, assignment->state, + assignment->status, assignment->condition, assignment->health, + assignment->reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send member update for service domain (%s) node " + "(%s) of member (%s).", service_domain_name, member_node_name, + member_name ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Member Update Message Callback +// ========================================================= +static void sm_service_domain_scheduler_member_update_msg_callback( + SmNetworkAddressT* network_address, int network_port, int version, + int revision, char service_domain_name[], char node_name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t health, + char reason_text[] ) +{ + bool insync; + SmErrorT error; + + if( '\0' == member_name[0] ) + { + DPRINTFD( "Empty member name received from neighbor (%s).", + member_node_name ); + return; + } + + error = sm_service_domain_utils_service_domain_neighbor_insync( + service_domain_name, node_name, + &insync ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if service domain (%s) neighbor (%s) " + "is insync for assignment (%s).", service_domain_name, + node_name, member_name ); + return; + } + + if( !insync ) + { + DPRINTFI( "Service domain (%s) neighbor (%s) is not insync for " + "assignment (%s).", service_domain_name, member_node_name, + member_name ); + return; + } + + error = sm_service_domain_utils_update_assignment( service_domain_name, + member_node_name, member_name, member_desired_state, + member_state, member_status, member_condition, health, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to update " + "assignment (%s), error=%s.", service_domain_name, + member_node_name, member_name, sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Service Group State Callback +// ======================================================= +void sm_service_domain_scheduler_service_group_state_callback( + char service_group_name[], SmServiceGroupStateT state, + SmServiceGroupStatusT status, SmServiceGroupConditionT condition, + int64_t health, const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainMemberT* member; + SmServiceDomainAssignmentT* assignment; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return; + } + + member = sm_service_domain_member_table_read_service_group( + service_group_name ); + if( NULL == member ) + { + DPRINTFD( "Failed to query service domain membership for service " + "group (%s), error=%s.", service_group_name, + sm_error_str( error ) ); + return; + } + + assignment = sm_service_domain_assignment_table_read( member->name, + hostname, service_group_name ); + if( NULL == assignment ) + { + DPRINTFE( "Failed to read service domain (%s) assignment for node " + "(%s) of member (%s).", member->name, hostname, + service_group_name ); + return; + } + + error = sm_service_domain_utils_update_assignment( + member->name, hostname, service_group_name, + assignment->desired_state, state, status, condition, + health, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) unable to update " + "assignment (%s), error=%s.", member->name, hostname, + service_group_name, sm_error_str( error ) ); + return; + } + + error = sm_service_domain_utils_send_member_update( assignment->name, + assignment->node_name, assignment->id, + assignment->service_group_name, assignment->desired_state, + assignment->state, assignment->status, assignment->condition, + assignment->health, assignment->reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send member update for service domain (%s) node " + "(%s) of member (%s), error=%s.", assignment->name, + assignment->node_name, assignment->service_group_name, + sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Initialize +// ===================================== +SmErrorT sm_service_domain_scheduler_initialize( SmDbHandleT* sm_db_handle ) +{ + SmErrorT error; + + _sm_db_handle = sm_db_handle; + + error = sm_timer_register( "service domain scheduler", + SM_SERVICE_DOMAIN_SCHEDULE_INTERVAL_IN_MS, + sm_service_domain_scheduler_timeout, + 0, &_scheduler_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create scheduler timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + _msg_callbacks.node_swact + = sm_service_domain_scheduler_node_swact_msg_callback; + _msg_callbacks.member_request + = sm_service_domain_scheduler_member_request_msg_callback ; + _msg_callbacks.member_update + = sm_service_domain_scheduler_member_update_msg_callback; + + error = sm_msg_register_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register message callbacks, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_api_register_callback( + sm_service_domain_scheduler_service_group_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for service group state callbacks, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_filter_initialize( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain filtering, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_weight_initialize( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to intialize service domain weighting, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Finalize +// =================================== +SmErrorT sm_service_domain_scheduler_finalize( void ) +{ + SmErrorT error; + + _sm_db_handle = NULL; + + error = sm_service_domain_filter_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain filtering, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_domain_weight_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service domain weighting, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_group_api_deregister_callback( + sm_service_domain_scheduler_service_group_state_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for service group state callbacks, " + "error=%s.", sm_error_str( error ) ); + } + + if( SM_TIMER_ID_INVALID != _scheduler_timer_id ) + { + error = sm_timer_deregister( _scheduler_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel scheduler timer, error=%s.", + sm_error_str( error ) ); + } + + _scheduler_timer_id = SM_TIMER_ID_INVALID; + } + + error = sm_msg_deregister_callbacks( &_msg_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister message callbacks, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_scheduler.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_scheduler.h new file mode 100644 index 00000000..17352f29 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_scheduler.h @@ -0,0 +1,51 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_SCHEDULER_H__ +#define __SM_SERVICE_DOMAIN_SCHEDULER_H__ + +#include + +#include "sm_types.h" +#include "sm_uuid.h" +#include "sm_db.h" +#include "sm_service_domain_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Scheduler - Swact Node +// ===================================== +extern SmErrorT sm_service_domain_scheduler_swact_node( char node_name[], + bool force, SmUuidT request_uuid ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Schedule Service Domain +// ================================================== +extern void sm_service_domain_scheduler_schedule_service_domain( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Initialize +// ===================================== +extern SmErrorT sm_service_domain_scheduler_initialize( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Scheduler - Finalize +// =================================== +extern SmErrorT sm_service_domain_scheduler_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_SCHEDULER_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_table.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_table.c new file mode 100644 index 00000000..3a6c5a80 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_table.c @@ -0,0 +1,266 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_domains.h" + +static SmListT* _service_domains = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Domain Table - Read +// =========================== +SmServiceDomainT* sm_service_domain_table_read( char name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainT* domain; + + SM_LIST_FOREACH( _service_domains, entry, entry_data ) + { + domain = (SmServiceDomainT*) entry_data; + + if( 0 == strcmp( name, domain->name ) ) + { + return( domain ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Read By Identifier +// ========================================= +SmServiceDomainT* sm_service_domain_table_read_by_id( int64_t id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceDomainT* domain; + + SM_LIST_FOREACH( _service_domains, entry, entry_data ) + { + domain = (SmServiceDomainT*) entry_data; + + if( id == domain->id ) + { + return( domain ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - For Each +// =============================== +void sm_service_domain_table_foreach( void* user_data[], + SmServiceDomainTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + + SM_LIST_FOREACH( _service_domains, entry, entry_data ) + { + callback( user_data, (SmServiceDomainT*) entry_data ); + } + +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Add +// ========================== +static SmErrorT sm_service_domain_table_add( void* user_data[], void* record ) +{ + SmServiceDomainT* domain; + SmDbServiceDomainT* db_domain; + + db_domain = (SmDbServiceDomainT*) record; + + domain = sm_service_domain_table_read( db_domain->name ); + if( NULL == domain ) + { + domain = (SmServiceDomainT*) malloc( sizeof(SmServiceDomainT) ); + if( NULL == domain ) + { + DPRINTFE( "Failed to allocate service domain table entry." ); + return( SM_FAILED ); + } + + memset( domain, 0, sizeof(SmServiceDomainT) ); + + domain->id = db_domain->id; + snprintf( domain->name, sizeof(domain->name), "%s", db_domain->name ); + domain->orchestration = db_domain->orchestration; + domain->designation = db_domain->designation; + domain->preempt = db_domain->preempt; + domain->generation = db_domain->generation; + domain->priority = db_domain->priority; + domain->hello_interval = db_domain->hello_interval; + domain->dead_interval = db_domain->dead_interval; + domain->wait_interval = db_domain->wait_interval; + domain->exchange_interval = db_domain->exchange_interval; + domain->state = db_domain->state; + domain->split_brain_recovery = db_domain->split_brain_recovery; + snprintf( domain->leader, sizeof(domain->leader), "%s", + db_domain->leader ); + domain->hello_timer_id = SM_TIMER_ID_INVALID; + domain->wait_timer_id = SM_TIMER_ID_INVALID; + + SM_LIST_PREPEND( _service_domains, (SmListEntryDataPtrT) domain ); + + } else { + domain->id = db_domain->id; + domain->orchestration = db_domain->orchestration; + domain->designation = db_domain->designation; + domain->preempt = db_domain->preempt; + domain->generation = db_domain->generation; + domain->priority = db_domain->priority; + domain->hello_interval = db_domain->hello_interval; + domain->dead_interval = db_domain->dead_interval; + domain->wait_interval = db_domain->wait_interval; + domain->exchange_interval = db_domain->exchange_interval; + domain->state = db_domain->state; + domain->split_brain_recovery = db_domain->split_brain_recovery; + snprintf( domain->leader, sizeof(domain->leader), "%s", + db_domain->leader ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Load +// =========================== +SmErrorT sm_service_domain_table_load( void ) +{ + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbServiceDomainT domain; + SmErrorT error; + + snprintf( db_query, sizeof(db_query), "%s = 'yes'", + SM_SERVICE_DOMAINS_TABLE_COLUMN_PROVISIONED ); + + error = sm_db_foreach( SM_DATABASE_NAME, + SM_SERVICE_DOMAINS_TABLE_NAME, db_query, + &domain, sm_db_service_domains_convert, + sm_service_domain_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service domains in " + "database, error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Persist +// ============================== +SmErrorT sm_service_domain_table_persist( SmServiceDomainT* domain ) +{ + SmDbServiceDomainT db_domain; + SmErrorT error; + + memset( &db_domain, 0, sizeof(db_domain) ); + + db_domain.id = domain->id; + snprintf( db_domain.name, sizeof(db_domain.name), "%s", domain->name ); + db_domain.orchestration = domain->orchestration; + db_domain.designation = domain->designation; + db_domain.preempt = domain->preempt; + db_domain.generation = domain->generation; + db_domain.priority = domain->priority; + db_domain.hello_interval = domain->hello_interval; + db_domain.dead_interval = domain->dead_interval; + db_domain.wait_interval = domain->wait_interval; + db_domain.exchange_interval = domain->exchange_interval; + db_domain.state = domain->state; + db_domain.split_brain_recovery = domain->split_brain_recovery; + snprintf( db_domain.leader, sizeof(db_domain.leader), "%s", + domain->leader ); + + error = sm_db_service_domains_update( _sm_db_handle, &db_domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Initialize +// ================================= +SmErrorT sm_service_domain_table_initialize( void ) +{ + SmErrorT error; + + _service_domains = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_domain_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service domains from database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Finalize +// =============================== +SmErrorT sm_service_domain_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_domains ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_table.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_table.h new file mode 100644 index 00000000..977789cd --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_table.h @@ -0,0 +1,89 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_TABLE_H__ +#define __SM_SERVICE_DOMAIN_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int64_t id; + char name[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + SmOrchestrationTypeT orchestration; + SmDesignationTypeT designation; + bool preempt; + int generation; + int priority; + int hello_interval; + int dead_interval; + int wait_interval; + int exchange_interval; + SmServiceDomainStateT state; + SmServiceDomainSplitBrainRecoveryT split_brain_recovery; + SmTimerIdT hello_timer_id; + SmTimerIdT wait_timer_id; + char leader[SM_NODE_NAME_MAX_CHAR]; +} SmServiceDomainT; + +typedef void (*SmServiceDomainTableForEachCallbackT) + (void* user_data[], SmServiceDomainT* domain); + +// **************************************************************************** +// Service Domain Table - Read +// =========================== +extern SmServiceDomainT* sm_service_domain_table_read( char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Read By Identifier +// ========================================= +extern SmServiceDomainT* sm_service_domain_table_read_by_id( int64_t id ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - For Each +// =============================== +extern void sm_service_domain_table_foreach( void* user_data[], + SmServiceDomainTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Load +// =========================== +extern SmErrorT sm_service_domain_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Persist +// ============================== +extern SmErrorT sm_service_domain_table_persist( SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Initialize +// ================================= +extern SmErrorT sm_service_domain_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Table - Finalize +// =============================== +extern SmErrorT sm_service_domain_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_utils.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_utils.c new file mode 100644 index 00000000..e4fbfeed --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_utils.c @@ -0,0 +1,1079 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_utils.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_msg.h" +#include "sm_node_api.h" +#include "sm_service_group_api.h" +#include "sm_service_group_table.h" +#include "sm_service_domain_table.h" +#include "sm_service_domain_member_table.h" +#include "sm_service_domain_neighbor_table.h" +#include "sm_service_domain_interface_table.h" +#include "sm_service_domain_assignment_table.h" + +#define NS_PER_SEC 1000000000 +#define NS_PER_MS 1000000 +// **************************************************************************** +// Service Domain Utilities - Core Service Group Enabled +// ===================================================== +static void sm_service_domain_utils_core_service_group_enabled( + void* user_data[], SmServiceGroupT* service_group ) +{ + bool* enabled = (bool*) user_data[0]; + + if(( service_group->core )&& + ( SM_SERVICE_GROUP_STATE_ACTIVE != service_group->state )) + { + *enabled = false; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Primary Inteface Enabled +// =================================================== +static void sm_service_domain_utils_primary_interface_enabled( + void* user_data[], SmServiceDomainInterfaceT* interface ) +{ + bool* enabled = (bool*) user_data[0]; + + if( SM_INTERFACE_STATE_NOT_IN_USE == interface->interface_state ) + { + return; + } + + if(( SM_PATH_TYPE_PRIMARY == interface->path_type ) && + ( SM_INTERFACE_STATE_ENABLED != interface->interface_state )) + { + if( SM_SERVICE_DOMAIN_INTERFACE_CONNECT_TYPE_TOR == interface->interface_connect_type ) + { + DPRINTFI( "Primary interface is DOWN. Node is disabled." ); + *enabled = false; + } + else + { + DPRINTFD( "Primary interface is DOWN, but it is direct connect interface." ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Service Domain Enabled +// ================================================= +SmErrorT sm_service_domain_utils_service_domain_enabled( char name[], + bool* enabled ) +{ + void* user_data[] = { enabled }; + + *enabled = true; + + sm_service_domain_interface_table_foreach_service_domain( name, user_data, + sm_service_domain_utils_primary_interface_enabled ); + + if( *enabled ) + { + sm_service_group_table_foreach( user_data, + sm_service_domain_utils_core_service_group_enabled ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Interface Send Hello +// =============================================== +static void sm_service_domain_utils_interface_send_hello( void* user_data[], + SmServiceDomainInterfaceT* interface ) +{ + char* hostname = (char*) user_data[0]; + SmServiceDomainT* domain = (SmServiceDomainT*) user_data[1]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_service_domain_hello( hostname, + domain->orchestration, domain->designation, + domain->generation, domain->priority, + domain->hello_interval, domain->dead_interval, + domain->wait_interval, domain->exchange_interval, + domain->leader, interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send hello for service domain (%s) on " + "interface (%s), error=%s.", domain->name, + interface->service_domain_interface, + sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Hello +// ===================================== +SmErrorT sm_service_domain_utils_send_hello( char name[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainT* domain = NULL; + void* user_data[] = { hostname, domain }; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + user_data[1] = domain; + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach_service_domain( name, user_data, + sm_service_domain_utils_interface_send_hello ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Interface Send Pause +// =============================================== +static void sm_service_domain_utils_interface_send_pause( void* user_data[], + SmServiceDomainInterfaceT* interface ) +{ + char* hostname = (char*) user_data[0]; + SmServiceDomainT* domain = (SmServiceDomainT*) user_data[1]; + int pause_interval = *(int*) user_data[2]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_service_domain_pause( hostname, pause_interval, + interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send pause for service domain (%s) on " + "interface (%s), error=%s.", domain->name, + interface->service_domain_interface, + sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Pause +// ===================================== +SmErrorT sm_service_domain_utils_send_pause( char name[], int pause_interval ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainT* domain = NULL; + void* user_data[] = { hostname, domain, &pause_interval }; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + user_data[1] = domain; + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach_service_domain( name, user_data, + sm_service_domain_utils_interface_send_pause ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Inteface Send Exchange Start +// ======================================================= +static void sm_service_domain_utils_interface_send_exchange_start( + void* user_data[], SmServiceDomainInterfaceT* interface ) +{ + char* hostname = (char*) user_data[0]; + SmServiceDomainT* domain = (SmServiceDomainT*) user_data[1]; + SmServiceDomainNeighborT* neighbor = (SmServiceDomainNeighborT*) user_data[2]; + int exchange_seq = *(int*) user_data[3]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_service_domain_exchange_start( hostname, + neighbor->name, exchange_seq, interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange start for service domain (%s) " + "on interface (%s), error=%s.", domain->name, + interface->service_domain_interface, + sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Exchange Start throttle +// ============================================== +SmErrorT sm_service_domain_utils_send_exchange_start_throttle( char name[], + SmServiceDomainNeighborT* neighbor, int exchange_seq, int min_interval_ms ) +{ + struct timespec now; + int sec, nsec; + clock_gettime( CLOCK_MONOTONIC_RAW, &now ); + sec = now.tv_sec - neighbor->last_exchange_start.tv_sec; + nsec = now.tv_nsec - neighbor->last_exchange_start.tv_nsec; + if (min_interval_ms >= (sec * NS_PER_SEC + nsec) / NS_PER_MS) + { + DPRINTFI("Donot send exchange start too often (%d ms)", min_interval_ms); + return SM_OKAY; + } + + return sm_service_domain_utils_send_exchange_start(name, neighbor, exchange_seq); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Exchange Start +// ============================================== +SmErrorT sm_service_domain_utils_send_exchange_start( char name[], + SmServiceDomainNeighborT* neighbor, int exchange_seq ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainT* domain = NULL; + void* user_data[] = { hostname, domain, neighbor, &exchange_seq }; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + user_data[1] = domain; + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach_service_domain( name, user_data, + sm_service_domain_utils_interface_send_exchange_start ); + + clock_gettime( CLOCK_MONOTONIC_RAW, &neighbor->last_exchange_start ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Inteface Send Exchange +// ================================================= +static void sm_service_domain_utils_interface_send_exchange( + void* user_data[], SmServiceDomainInterfaceT* interface ) +{ + char* hostname = (char*) user_data[0]; + SmServiceDomainT* domain = (SmServiceDomainT*) user_data[1]; + SmServiceDomainNeighborT* neighbor = (SmServiceDomainNeighborT*) user_data[2]; + int exchange_seq = *(int*) user_data[3]; + int64_t member_id = *(int64_t*) user_data[4]; + char* member_name = (char*) user_data[5]; + SmServiceGroupStateT member_desired_state = *(SmServiceGroupStateT*) user_data[6]; + SmServiceGroupStateT member_state = *(SmServiceGroupStateT*) user_data[7]; + SmServiceGroupStatusT member_status = *(SmServiceGroupStatusT*) user_data[8]; + SmServiceGroupConditionT member_condition = *(SmServiceGroupConditionT*) user_data[9]; + int64_t member_health = *(int64_t*) user_data[10]; + char * reason_text = (char*) user_data[11]; + bool more_members = *(bool*) user_data[12]; + int64_t last_received_member_id = *(int64_t*) user_data[13]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_service_domain_exchange( hostname, neighbor->name, + exchange_seq, member_id, member_name, member_desired_state, + member_state, member_status, member_condition, member_health, + reason_text, more_members, last_received_member_id, interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send exchange for service domain (%s) " + "on interface (%s), error=%s.", domain->name, + interface->service_domain_interface, + sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Exchange +// ======================================== +SmErrorT sm_service_domain_utils_send_exchange( char name[], + SmServiceDomainNeighborT* neighbor, int exchange_seq, int64_t member_id, + char member_name[], SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t member_health, + const char reason_text[], bool more_members, int64_t last_received_member_id ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainT* domain = NULL; + void* user_data[] = { hostname, domain, neighbor, &exchange_seq, + &member_id, member_name, &member_desired_state, + &member_state, &member_status, &member_condition, + &member_health, (void*) &(reason_text[0]), + &more_members, &last_received_member_id }; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + user_data[1] = domain; + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach_service_domain( name, user_data, + sm_service_domain_utils_interface_send_exchange ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Inteface Send Member Request +// ======================================================= +static void sm_service_domain_utils_interface_send_member_request( + void* user_data[], SmServiceDomainInterfaceT* interface ) +{ + char* hostname = (char*) user_data[0]; + SmServiceDomainT* domain = (SmServiceDomainT*) user_data[1]; + char* member_node_name = (char*) user_data[2]; + int64_t member_id = *(int64_t*) user_data[3]; + char* member_name = (char*) user_data[4]; + SmServiceGroupActionT member_action = *(SmServiceGroupActionT*) user_data[5]; + SmServiceGroupActionFlagsT member_action_flags = *(SmServiceGroupActionFlagsT*) + user_data[6]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_service_domain_member_request( hostname, + member_node_name, member_id, member_name, member_action, + member_action_flags, interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send member (%s) request for service domain " + "(%s) on interface (%s), error=%s.", member_name, + domain->name, interface->service_domain_interface, + sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Member Request +// ============================================== +SmErrorT sm_service_domain_utils_send_member_request( char name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupActionT member_action, + SmServiceGroupActionFlagsT member_action_flags ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainT* domain = NULL; + void* user_data[] = { hostname, domain, member_node_name, + &member_id, member_name, &member_action, + &member_action_flags }; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + user_data[1] = domain; + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach_service_domain( name, user_data, + sm_service_domain_utils_interface_send_member_request ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Inteface Send Member Update +// ====================================================== +static void sm_service_domain_utils_interface_send_member_update( + void* user_data[], SmServiceDomainInterfaceT* interface ) +{ + char* hostname = (char*) user_data[0]; + char* member_node_name = (char*) user_data[1]; + int64_t member_id = *(int64_t*) user_data[2]; + char* member_name = (char*) user_data[3]; + SmServiceGroupStateT member_desired_state = *(SmServiceGroupStateT*) user_data[4]; + SmServiceGroupStateT member_state = *(SmServiceGroupStateT*) user_data[5]; + SmServiceGroupStatusT member_status = *(SmServiceGroupStatusT*) user_data[6]; + SmServiceGroupConditionT member_condition = *(SmServiceGroupConditionT*) user_data[7]; + int64_t health = *(int64_t*) user_data[8]; + const char* reason_text = (char*) user_data[9]; + SmErrorT error; + + if(( SM_INTERFACE_STATE_ENABLED == interface->interface_state )&& + ( SM_PATH_TYPE_STATUS_ONLY != interface->path_type )) + { + error = sm_msg_send_service_domain_member_update( hostname, + member_node_name, member_id, member_name, + member_desired_state, member_state, member_status, + member_condition, health, reason_text, interface ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send member (%s) update for service domain " + "(%s) on interface (%s), error=%s.", member_name, + interface->service_domain, + interface->service_domain_interface, + sm_error_str( error ) ); + return; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Member Update +// ============================================= +SmErrorT sm_service_domain_utils_send_member_update( char name[], + char member_node_name[], int64_t member_id, + char member_name[], SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t health, + const char reason_text[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainT* domain; + void* user_data[] = { hostname, member_node_name, &member_id, member_name, + &member_desired_state, &member_state, &member_status, + &member_condition, &health, (void*) &(reason_text[0]) }; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + sm_msg_increment_seq_num(); + + sm_service_domain_interface_table_foreach_service_domain( name, user_data, + sm_service_domain_utils_interface_send_member_update ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Neighbor Elect +// ========================================= +static void sm_service_domain_utils_neighbor_elect( void* user_data[], + SmServiceDomainNeighborT* neighbor ) +{ + int* leader_generation = (int*) user_data[0]; + int* leader_priority = (int*) user_data[1]; + char* leader_name = (char*) user_data[2]; + + if( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN == neighbor->state ) + { + DPRINTFD( "Neighbor (%s) is in the down state, skip.", neighbor->name ); + return; + } + + if( *leader_generation < neighbor->generation ) + { + DPRINTFI( "New leader (%s), old=%s.", leader_name, neighbor->name ); + + *leader_generation = neighbor->generation; + *leader_priority = neighbor->priority; + snprintf( leader_name, SM_NODE_NAME_MAX_CHAR, "%s", neighbor->name ); + + } else if( *leader_generation == neighbor->generation ) { + + if( *leader_priority < neighbor->priority ) + { + DPRINTFI( "New leader (%s), old=%s.", leader_name, + neighbor->name ); + + *leader_generation = neighbor->generation; + *leader_priority = neighbor->priority; + snprintf( leader_name, SM_NODE_NAME_MAX_CHAR, "%s", + neighbor->name ); + + } else if( *leader_priority == neighbor->priority ) { + + if( 0 < strcmp( neighbor->name, leader_name ) ) + { + DPRINTFI( "New leader (%s), old=%s.", leader_name, + neighbor->name ); + + *leader_generation = neighbor->generation; + *leader_priority = neighbor->priority; + snprintf( leader_name, SM_NODE_NAME_MAX_CHAR, "%s", + neighbor->name ); + } + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Hold Election +// ======================================== +SmErrorT sm_service_domain_utils_hold_election( char name[], char leader[], + bool* elected ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + int leader_generation; + int leader_priority; + void* user_data[] = { &leader_generation, &leader_priority, leader }; + SmServiceDomainT* domain; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + // Elect self. + leader_generation = domain->generation; + leader_priority = domain->priority; + snprintf( leader, SM_NODE_NAME_MAX_CHAR, "%s", hostname ); + + sm_service_domain_neighbor_table_foreach( domain->name, user_data, + sm_service_domain_utils_neighbor_elect ); + + *elected = (0 == strcmp( leader, hostname ) ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Service Domain Neighbor InSync +// ========================================================= +SmErrorT sm_service_domain_utils_service_domain_neighbor_insync( + char name[], char node_name[], bool* insync ) +{ + SmServiceDomainNeighborT* neighbor; + + *insync = false; + + neighbor = sm_service_domain_neighbor_table_read( node_name, name ); + if( NULL == neighbor ) + { + DPRINTFE( "Service domain (%s) neighbor (%s) not found.", + name, node_name ); + return( SM_NOT_FOUND ); + } + + if( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL == neighbor->state ) + { + *insync = true; + } + else + { + DPRINTFI( "Service domain (%s) neighbor (%s) state is %s.", + name, node_name, sm_service_domain_neighbor_state_str(neighbor->state) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Neighbor State Full +// ============================================== +static void sm_service_domain_utils_neighbor_state_full( void* user_data[], + SmServiceDomainNeighborT* neighbor ) +{ + bool* insync = (bool*) user_data[0]; + + if( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL != neighbor->state ) + { + *insync = false; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Service Domain Neighbors InSync +// ========================================================== +SmErrorT sm_service_domain_utils_service_domain_neighbors_insync( + char name[], bool* insync ) +{ + void* user_data[] = { insync }; + SmServiceDomainT* domain; + + *insync = true; + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + sm_service_domain_neighbor_table_foreach( domain->name, user_data, + sm_service_domain_utils_neighbor_state_full ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Neighbor State Syncing +// ================================================= +static void sm_service_domain_utils_neighbor_state_syncing( void* user_data[], + SmServiceDomainNeighborT* neighbor ) +{ + bool* syncing = (bool*) user_data[0]; + + if(( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START == neighbor->state )|| + ( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE == neighbor->state )) + { + *syncing = true; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Service Domain Neighbors Syncing +// =========================================================== +SmErrorT sm_service_domain_utils_service_domain_neighbors_syncing( + char name[], bool* syncing ) +{ + void* user_data[] = { syncing }; + SmServiceDomainT* domain; + + *syncing = false; + + domain = sm_service_domain_table_read( name ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain (%s), error=%s.", + name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + sm_service_domain_neighbor_table_foreach( domain->name, user_data, + sm_service_domain_utils_neighbor_state_syncing ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Update Assignment +// ============================================ +SmErrorT sm_service_domain_utils_update_assignment( char name[], + char node_name[], char service_group_name[], + SmServiceGroupStateT desired_state, SmServiceGroupStateT state, + SmServiceGroupStatusT status, SmServiceGroupConditionT condition, + int64_t health, const char reason_text[] ) +{ + struct timespec ts; + SmServiceDomainAssignmentT* assignment; + SmErrorT error; + + clock_gettime( CLOCK_MONOTONIC_RAW, &ts ); + + assignment = sm_service_domain_assignment_table_read( name, node_name, + service_group_name ); + if( NULL != assignment ) + { + if(( assignment->desired_state != desired_state )|| + ( assignment->state != state )||( assignment->status != status )) + { + assignment->last_state_change = (long) ts.tv_sec; + } + + assignment->desired_state = desired_state; + assignment->state = state; + assignment->status = status; + assignment->condition = condition; + assignment->health = health; + + if( 0 != strcmp( assignment->reason_text, reason_text ) ) + { + snprintf( assignment->reason_text, sizeof(assignment->reason_text), + "%s", reason_text ); + } + + error = sm_service_domain_assignment_table_persist( assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update assignment (%s) for service domain " + "(%s) node (%s), error=%s.", service_group_name, name, + node_name, sm_error_str( error ) ); + return( error ); + } + } else { + error = sm_service_domain_assignment_table_insert( name, node_name, + service_group_name, desired_state, state, status, condition, + health, (long) ts.tv_sec, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to insert assignment (%s) for service domain " + "(%s) node (%s), error=%s.", service_group_name, name, + node_name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Update Own Assignment +// ================================================ +static void sm_service_domain_utils_update_own_assignment( void* user_data[], + SmServiceDomainMemberT* member ) +{ + char* service_domain_name = (char*) user_data[0]; + char* node_name = (char*) user_data[1]; + SmServiceGroupT* service_group; + SmErrorT error; + + service_group = sm_service_group_table_read( member->service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + member->service_group_name, sm_error_str(SM_NOT_FOUND) ); + return; + } + + error = sm_service_domain_utils_update_assignment( service_domain_name, + node_name, service_group->name, service_group->desired_state, + service_group->state, service_group->status, + service_group->condition, service_group->health, + service_group->reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update own assignments for service domain " + "(%s) node (%s) service group (%s), error=%s.", + service_domain_name, node_name, service_group->name, + sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Update Own Assignments +// ================================================= +SmErrorT sm_service_domain_utils_update_own_assignments( char name[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + void* user_data[] = { name, hostname }; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + sm_service_domain_member_table_foreach( name, user_data, + sm_service_domain_utils_update_own_assignment ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Disable Assignment +// ============================================= +static void sm_service_domain_utils_disable_assignment( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + SmErrorT error; + + error = sm_service_group_api_disable( assignment->service_group_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform disable action on member (%s) " + "for service domain (%s) on node (%s), error=%s.", + assignment->service_group_name, assignment->name, + assignment->node_name, sm_error_str(error) ); + return; + } + + assignment->desired_state = SM_SERVICE_GROUP_STATE_DISABLED; + assignment->state = SM_SERVICE_GROUP_STATE_DISABLED; + assignment->status = SM_SERVICE_GROUP_STATUS_NONE; + assignment->health = 0; + + error = sm_service_domain_assignment_table_persist( assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update assignment (%s) for service domain " + "(%s) node (%s), error=%s.", + assignment->service_group_name, assignment->name, + assignment->node_name, sm_error_str( error ) ); + return; + } + + DPRINTFI( "Assignment (%s) for service domain (%s) node (%s) disabled.", + assignment->service_group_name, assignment->name, + assignment->node_name ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Disable Self +// ======================================= +SmErrorT sm_service_domain_utils_service_domain_disable_self( char name[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + sm_service_domain_assignment_table_foreach_node_in_service_domain( name, + hostname, NULL, sm_service_domain_utils_disable_assignment ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Neighbor active assignement +// ====================================================== +static void sm_service_domain_utils_active_assignment( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + + SmErrorT error; + + error = sm_service_group_api_go_active( assignment->service_group_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform disable action on member (%s) " + "for service domain (%s) on node (%s), error=%s.", + assignment->service_group_name, assignment->name, + assignment->node_name, sm_error_str(error) ); + return; + } + + assignment->desired_state = SM_SERVICE_GROUP_STATE_ACTIVE; + assignment->state = SM_SERVICE_GROUP_STATE_GO_ACTIVE; + assignment->status = SM_SERVICE_GROUP_STATUS_NONE; + assignment->health = 0; + + error = sm_service_domain_assignment_table_persist( assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update assignment (%s) for service domain " + "(%s) node (%s), error=%s.", + assignment->service_group_name, assignment->name, + assignment->node_name, sm_error_str( error ) ); + return; + } + + DPRINTFI( "Assignment (%s) for service domain (%s) node (%s) active.", + assignment->service_group_name, assignment->name, + assignment->node_name ); + +} + +// **************************************************************************** +// Service Domain Utilities - Neighbor active self +// ====================================================== +SmErrorT sm_service_domain_utils_service_domain_active_self( char name[] ) +{ + + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmErrorT error; + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + sm_service_domain_assignment_table_foreach_node_in_service_domain( name, + hostname, NULL, sm_service_domain_utils_active_assignment ); + + return( SM_OKAY ); + +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Neighbor Cleanup Assignment +// ====================================================== +static void sm_service_domain_utils_neighbor_cleanup_assignment( + void* user_data[], SmServiceDomainAssignmentT* assignment ) +{ + SmErrorT error; + + assignment->desired_state = SM_SERVICE_GROUP_STATE_DISABLED; + assignment->state = SM_SERVICE_GROUP_STATE_DISABLED; + assignment->status = SM_SERVICE_GROUP_STATUS_NONE; + assignment->health = 0; + + error = sm_service_domain_assignment_table_persist( assignment ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update assignment (%s) for service domain " + "(%s) node (%s), error=%s.", + assignment->service_group_name, assignment->name, + assignment->node_name, sm_error_str( error ) ); + return; + } + + DPRINTFI( "Assignment (%s) for service domain (%s) node (%s) disabled.", + assignment->service_group_name, assignment->name, + assignment->node_name ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Neighbor Cleanup +// =========================================== +SmErrorT sm_service_domain_utils_service_domain_neighbor_cleanup( + char name[], char node_name[] ) +{ + sm_service_domain_assignment_table_foreach_node_in_service_domain( name, + node_name, NULL, sm_service_domain_utils_neighbor_cleanup_assignment ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Initialize +// ===================================== +SmErrorT sm_service_domain_utils_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Finalize +// =================================== +SmErrorT sm_service_domain_utils_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_utils.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_utils.h new file mode 100644 index 00000000..250db35d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_utils.h @@ -0,0 +1,162 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_UTILS_H__ +#define __SM_SERVICE_DOMAIN_UTILS_H__ + +#include + +#include "sm_types.h" +#include "sm_service_domain_neighbor_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Utilities - Service Domain Enabled +// ================================================= +extern SmErrorT sm_service_domain_utils_service_domain_enabled( char name[], + bool* enabled ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Hello +// ===================================== +extern SmErrorT sm_service_domain_utils_send_hello( char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Pause +// ===================================== +extern SmErrorT sm_service_domain_utils_send_pause( char name[], + int pause_interval ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Exchange Start throttled +// ============================================== +extern SmErrorT sm_service_domain_utils_send_exchange_start_throttle( char name[], + SmServiceDomainNeighborT* neighbor, int exchange_seq, int min_interval_ms ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Exchange Start +// ============================================== +extern SmErrorT sm_service_domain_utils_send_exchange_start( char name[], + SmServiceDomainNeighborT* neighbor, int exchange_seq ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Exchange +// ======================================== +extern SmErrorT sm_service_domain_utils_send_exchange( char name[], + SmServiceDomainNeighborT* neighbor, int exchange_seq, int64_t member_id, + char member_name[], SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t member_health, + const char reason_text[], bool more_members, + int64_t last_received_member_id ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Member Request +// ============================================== +extern SmErrorT sm_service_domain_utils_send_member_request( char name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupActionT member_action, + SmServiceGroupActionFlagsT member_action_flags ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Send Member Update +// ============================================= +extern SmErrorT sm_service_domain_utils_send_member_update( char name[], + char member_node_name[], int64_t member_id, char member_name[], + SmServiceGroupStateT member_desired_state, + SmServiceGroupStateT member_state, SmServiceGroupStatusT member_status, + SmServiceGroupConditionT member_condition, int64_t health, + const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Hold Election +// ======================================== +extern SmErrorT sm_service_domain_utils_hold_election( char name[], + char leader[], bool* elected ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Service Domain Neighbor InSync +// ========================================================= +extern SmErrorT sm_service_domain_utils_service_domain_neighbor_insync( + char name[], char node_name[], bool* insync ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Service Domain Neighbors InSync +// ========================================================== +extern SmErrorT sm_service_domain_utils_service_domain_neighbors_insync( + char name[], bool* insync ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Service Domain Neighbors Syncing +// =========================================================== +extern SmErrorT sm_service_domain_utils_service_domain_neighbors_syncing( + char name[], bool* syncing ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Update Assignment +// ============================================ +extern SmErrorT sm_service_domain_utils_update_assignment( char name[], + char node_name[], char service_group_name[], + SmServiceGroupStateT desired_state, SmServiceGroupStateT state, + SmServiceGroupStatusT status, SmServiceGroupConditionT condition, + int64_t health, const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Update Own Assignments +// ================================================= +extern SmErrorT sm_service_domain_utils_update_own_assignments( char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Disable Self +// ======================================= +extern SmErrorT sm_service_domain_utils_service_domain_disable_self( char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - active Self +// ======================================= +extern SmErrorT sm_service_domain_utils_service_domain_active_self( char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Neighbor Cleanup +// =========================================== +extern SmErrorT sm_service_domain_utils_service_domain_neighbor_cleanup( + char name[], char node_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Utilities - Initialize +// ===================================== +extern SmErrorT sm_service_domain_utils_initialize( void ); + +// **************************************************************************** +// Service Domain Utilities - Finalize +// =================================== +extern SmErrorT sm_service_domain_utils_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_UTILS_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_waiting_state.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_waiting_state.c new file mode 100644 index 00000000..c2ccc59a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_waiting_state.c @@ -0,0 +1,316 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_waiting_state.h" + +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_node_api.h" +#include "sm_service_domain_utils.h" +#include "sm_service_domain_fsm.h" + +#define SM_SKEW_WAIT_TIME( priority ) ((( 256 - priority ) * 100) / 256) + +// **************************************************************************** +// Service Domain Waiting State - Wait Timer +// ========================================= +static bool sm_service_domain_waiting_state_wait_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int wait_interval; + int64_t id = user_data; + SmServiceDomainT* domain; + SmServiceDomainEventT event = SM_SERVICE_DOMAIN_EVENT_WAIT_EXPIRED; + SmErrorT error; + + domain = sm_service_domain_table_read_by_id( id ); + if( NULL == domain ) + { + DPRINTFE( "Failed to read service domain, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + wait_interval = domain->wait_interval + SM_SKEW_WAIT_TIME( domain->priority ); + + if( sm_timer_scheduling_on_time_in_period( wait_interval ) ) + { + error = sm_service_domain_fsm_event_handler( domain->name, event, + NULL, "wait expired" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service domain (%s) failed to handle event (%s), " + "error=%s.", domain->name, + sm_service_domain_event_str(event), + sm_error_str( error ) ); + return( true ); + } + } else { + DPRINTFI( "Not scheduling on time in the last %i ms, waiting " + "another %i ms for service domain (%s).", wait_interval, + wait_interval, domain->name ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Entry +// ==================================== +SmErrorT sm_service_domain_waiting_state_entry( SmServiceDomainT* domain ) +{ + char timer_name[80] = ""; + int wait_interval; + SmTimerIdT wait_timer_id; + SmErrorT error; + + wait_interval = domain->wait_interval + SM_SKEW_WAIT_TIME( domain->priority ); + + DPRINTFI( "Service domain (%s) wait interval set to %i ms.", domain->name, + wait_interval ); + + snprintf( timer_name, sizeof(timer_name), "%s wait", domain->name ); + + error = sm_timer_register( timer_name, wait_interval, + sm_service_domain_waiting_state_wait_timer, + domain->id, &wait_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create wait timer for service domain (%s), " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + domain->designation = SM_DESIGNATION_TYPE_UNKNOWN; + domain->leader[0] = '\0'; + domain->wait_timer_id = wait_timer_id; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Exit +// =================================== +SmErrorT sm_service_domain_waiting_state_exit( SmServiceDomainT* domain ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != domain->wait_timer_id ) + { + error = sm_timer_deregister( domain->wait_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel wait timer for service domain (%s), " + "error=%s.", domain->name, sm_error_str( error ) ); + } + + domain->wait_timer_id = SM_TIMER_ID_INVALID; + } + + domain->designation = SM_DESIGNATION_TYPE_UNKNOWN; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Transition +// ========================================= +SmErrorT sm_service_domain_waiting_state_transition( + SmServiceDomainT* domain, SmServiceDomainStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Event Handler +// ============================================ +SmErrorT sm_service_domain_waiting_state_event_handler( + SmServiceDomainT* domain, SmServiceDomainEventT event, + void* event_data[] ) +{ + bool enabled, elected, hold_election; + char* leader_name = NULL; + char leader[SM_NODE_NAME_MAX_CHAR]; + char hostname[SM_NODE_NAME_MAX_CHAR]; + SmServiceDomainStateT state; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceDomainNeighborT* neighbor; + SmErrorT error; + + error = sm_service_domain_utils_service_domain_enabled( domain->name, + &enabled ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if service domain (%s) is enabled, " + "error=%s.", domain->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_node_api_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_DOMAIN_EVENT_HELLO_MSG: + leader_name + = (char*) event_data[SM_SERVICE_DOMAIN_EVENT_DATA_MSG_LEADER]; + + if( '\0' != leader_name[0] ) + { + snprintf( domain->leader, SM_NODE_NAME_MAX_CHAR, "%s", + leader_name ); + + error = sm_service_domain_table_persist( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service domain (%s) data, " + "error=%s.", domain->name, + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_NEIGHBOR_AGEOUT: + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_ENABLED: + // Ignore. + break; + + case SM_SERVICE_DOMAIN_EVENT_INTERFACE_DISABLED: + if( !enabled ) + { + state = SM_SERVICE_DOMAIN_STATE_INITIAL; + + snprintf( reason_text, sizeof(reason_text), + "primary interface disabled" ); + + error = sm_service_domain_fsm_set_state( domain->name, state, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) failed, " + "error=%s.", sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_DOMAIN_EVENT_WAIT_EXPIRED: + elected = false; + hold_election = false; + + if(( '\0' == domain->leader[0] )||( domain->preempt )) + { + hold_election = true; + + } else { + neighbor = sm_service_domain_neighbor_table_read( + domain->leader, domain->name ); + if( NULL != neighbor ) + { + if( domain->generation > neighbor->generation ) + { + hold_election = true; + } + } else { + DPRINTFE( "Service domain (%s) neighbor (%s) not found.", + domain->name, domain->leader ); + } + } + + if( hold_election ) + { + error = sm_service_domain_utils_hold_election( domain->name, + leader, &elected ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to hold election for service domain " + "(%s), error=%s.", domain->name, + sm_error_str( error ) ); + abort(); + } + + snprintf( domain->leader, SM_NODE_NAME_MAX_CHAR, "%s", leader ); + + error = sm_service_domain_table_persist( domain ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update service domain (%s), " + "error=%s.", domain->name, + sm_error_str( error ) ); + return( error ); + } + } else { + elected = (0 == strcmp( hostname, domain->leader )); + } + + if( elected ) + { + state = SM_SERVICE_DOMAIN_STATE_LEADER; + + snprintf( reason_text, sizeof(reason_text), + "wait expired, elected leader" ); + } else { + state = SM_SERVICE_DOMAIN_STATE_BACKUP; + + snprintf( reason_text, sizeof(reason_text), + "wait expired, elected backup" ); + } + + error = sm_service_domain_fsm_set_state( domain->name, state, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service domain (%s) failed, " + "error=%s.", sm_service_domain_state_str( state ), + domain->name, sm_error_str( error ) ); + abort(); + } + break; + + default: + DPRINTFD( "Service Domain (%s) ignoring event (%s).", + domain->name, sm_service_domain_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Initialize +// ========================================= +SmErrorT sm_service_domain_waiting_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Finalize +// ======================================= +SmErrorT sm_service_domain_waiting_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_waiting_state.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_waiting_state.h new file mode 100644 index 00000000..47810f9d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_waiting_state.h @@ -0,0 +1,60 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_WAITING_STATE_H__ +#define __SM_SERVICE_DOMAIN_WAITING_STATE_H__ + +#include "sm_types.h" +#include "sm_service_domain_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Waiting State - Entry +// ==================================== +extern SmErrorT sm_service_domain_waiting_state_entry( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Exit +// =================================== +extern SmErrorT sm_service_domain_waiting_state_exit( + SmServiceDomainT* domain ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Transition +// ========================================= +extern SmErrorT sm_service_domain_waiting_state_transition( + SmServiceDomainT* domain, SmServiceDomainStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Event Handler +// ============================================ +extern SmErrorT sm_service_domain_waiting_state_event_handler( + SmServiceDomainT* domain, SmServiceDomainEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Initialize +// ========================================= +extern SmErrorT sm_service_domain_waiting_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Waiting State - Finalize +// ======================================= +extern SmErrorT sm_service_domain_waiting_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_WAITING_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_weight.c b/service-mgmt/sm-1.0.0/src/sm_service_domain_weight.c new file mode 100644 index 00000000..8c45b1b7 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_weight.c @@ -0,0 +1,225 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_domain_weight.h" + +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_nodes.h" +#include "sm_service_domain_assignment_table.h" + +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Domain Weight - Cleanup +// =============================== +static void sm_service_domain_weight_cleanup( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + assignment->sched_weight = SM_SERVICE_DOMAIN_WEIGHT_MINIMUM; +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Weight - Assignments +// =================================== +static void sm_service_domain_weight_assignments( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + int weight = -1; + + switch( assignment->sched_list ) + { + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE: + if( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->desired_state ) + { + if( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->state ) + { + weight = 50; + } else { + weight = 25; + } + } + break; + + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY: + if( SM_SERVICE_GROUP_STATE_STANDBY == assignment->desired_state ) + { + if( SM_SERVICE_GROUP_STATE_STANDBY == assignment->state ) + { + weight = 50; + } else { + weight = 25; + } + } + break; + + case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED: + if( SM_SERVICE_GROUP_STATE_DISABLED == assignment->desired_state ) + { + if( SM_SERVICE_GROUP_STATE_DISABLED == assignment->state ) + { + weight = 50; + } else { + weight = 25; + } + } + break; + + default: + // Ignore. + break; + } + + if( -1 != weight ) + { + assignment->sched_weight += weight; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Weight - Add Location +// ===================================== +static void sm_service_domain_weight_add_location( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + int weight_multipler = *(int*) user_data[0]; + SmDbNodeT* node = (SmDbNodeT*) user_data[1]; + +#ifdef SM_CONFIG_OPTION_STANDBY_ALL_SERVICES_ON_A_LOCKED_NODE + if( SM_NODE_ADMIN_STATE_LOCKED == node->admin_state ) + { + assignment->sched_weight = SM_SERVICE_DOMAIN_WEIGHT_UNSELECTABLE_ACTIVE; + } else { + if( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT != assignment->sched_state ) + { + assignment->sched_weight += weight_multipler * 100; + } + } +#else + assignment->sched_weight += weight_multipler * 100; +#endif // SM_CONFIG_OPTION_STANDBY_ALL_SERVICES_ON_A_LOCKED_NODE +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Weight - Add Location +// ===================================== +static void sm_service_domain_weight_check_availability( void* user_data[], + SmServiceDomainAssignmentT* assignment ) +{ + SmDbNodeT* node = (SmDbNodeT*) user_data[0]; + + if( SM_NODE_AVAIL_STATUS_FAILED == node->avail_status ) + { + DPRINTFD("Node %s is FAILED", node->name); + assignment->sched_weight = SM_SERVICE_DOMAIN_WEIGHT_UNSELECTABLE_ACTIVE; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Weight - By Location +// =================================== +static SmErrorT sm_service_domain_weight_by_location( void* user_data[], + void* record ) +{ + char* service_domain_name = (char*) user_data[0]; + int* weight_multipler = (int*) user_data[1]; + SmDbNodeT* node = (SmDbNodeT*) record; + void* user_data2[] = {weight_multipler, node}; + + sm_service_domain_assignment_table_foreach_node_in_service_domain( + service_domain_name, node->name, user_data2, + sm_service_domain_weight_add_location ); + + ++(*weight_multipler); + + return( SM_OKAY ); +} +// **************************************************************************** + +static SmErrorT sm_service_domain_weight_by_availability(void* user_data[], + void* record ) +{ + char* service_domain_name = (char*) user_data[0]; + SmDbNodeT* node = (SmDbNodeT*) record; + void* user_data2[] = {node}; + + sm_service_domain_assignment_table_foreach_node_in_service_domain( + service_domain_name, node->name, user_data2, + sm_service_domain_weight_check_availability ); + + return( SM_OKAY ); +} + +// **************************************************************************** +// Service Domain Weight - Apply +// ============================= +SmErrorT sm_service_domain_weight_apply( char service_domain_name[] ) +{ + int weight_multipler = 1; + SmDbNodeT node; + void* user_data[] = {service_domain_name, &weight_multipler}; + SmErrorT error; + + // Weight - Cleanup + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data, sm_service_domain_weight_cleanup ); + + // Weight - By Assignment. + sm_service_domain_assignment_table_foreach( service_domain_name, + user_data, sm_service_domain_weight_assignments ); + + // Weight - By Location. + error = sm_db_foreach( SM_DATABASE_NAME, SM_NODES_TABLE_NAME, + NULL, &node, &sm_db_nodes_convert, + sm_service_domain_weight_by_location, + user_data ); + + error = sm_db_foreach( SM_DATABASE_NAME, SM_NODES_TABLE_NAME, + NULL, &node, &sm_db_nodes_convert, + sm_service_domain_weight_by_availability, + user_data ); + + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over nodes, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Weight - Initialize +// ================================== +SmErrorT sm_service_domain_weight_initialize( SmDbHandleT* sm_db_handle ) +{ + _sm_db_handle = sm_db_handle; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Domain Weight - Finalize +// ================================ +SmErrorT sm_service_domain_weight_finalize( void ) +{ + _sm_db_handle = NULL; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_domain_weight.h b/service-mgmt/sm-1.0.0/src/sm_service_domain_weight.h new file mode 100644 index 00000000..9bf28f57 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_domain_weight.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_DOMAIN_WEIGHT_H__ +#define __SM_SERVICE_DOMAIN_WEIGHT_H__ + +#include "sm_types.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Domain Weight - Apply +// ============================= +extern SmErrorT sm_service_domain_weight_apply( char service_domain_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Weight - Initialize +// ================================== +extern SmErrorT sm_service_domain_weight_initialize( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Weight - Finalize +// ================================ +extern SmErrorT sm_service_domain_weight_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_DOMAIN_WEIGHT_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enable.c b/service-mgmt/sm-1.0.0/src/sm_service_enable.c new file mode 100644 index 00000000..5acc4029 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enable.c @@ -0,0 +1,731 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_enable.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_process_death.h" +#include "sm_timer.h" +#include "sm_service_dependency.h" +#include "sm_service_fsm.h" +#include "sm_service_action.h" +#include "sm_configuration_table.h" +#include "sm_node_utils.h" +#include "sm_util_types.h" + +#define SERVICE_ENABLING_THROTTLE_DEFAULT_SIZE 2 +#define EXTRA_CORES_STORAGE "/etc/platform/.task_affining_incomplete" +#define PLATFORM_CORES_FILE "/var/run/sm/.platform_cores" + +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static sem_t sem; +static int num_initial_cores = 0; +static sem_t sem_more_cores; +static bool check_more_cores_available = false; +static bool more_cores_available = false; +static int num_extra_cores = 0; + + +// **************************************************************************** +// add more cores for enabling service +// ============== +void sm_service_enable_throttle_add_cores( bool additional_cores ) +{ + mutex_holder holder(&_mutex); + + check_more_cores_available = additional_cores; + if (!additional_cores) + { + if( more_cores_available ) + { + sem_destroy(&sem); + more_cores_available = false; + } + }else + { + DPRINTFI("Additional cores check enabled"); + } +} +// **************************************************************************** + +// **************************************************************************** +// handling special upgrade case. +// THIS IS A HACK TO TEMPORALLY OVERCOME ISCSI ENABLE TIMEOUT AFTER UPGRADE +// THIS CODE SHOULD BE REMOVED in Release 17.xx +// =============================== +static int handle_special_upgrade_case(SmServiceT* service, int* timeout_ms) +{ + FILE* fp; + char flag_file[] = "/tmp/.extend_sm_iscsi_enable_timeout"; + int reading_sec = 0; + if (0 == strcmp(service->name, "iscsi")) + { + fp = fopen( flag_file, "r" ); + if ( NULL == fp) + return 0; + + fscanf( fp, "%d", &reading_sec ); + fclose(fp); + + if ( reading_sec <= 0 ) + { + reading_sec = 960; // make it 16 minutes + } + + DPRINTFI( "Extending enable timeout for iscsi from %d ms to %d ms", + *timeout_ms, reading_sec * 1000); + *timeout_ms = reading_sec * 1000; + + if( 0 != remove(flag_file) ) + { + DPRINTFE( "Failed to remove flag file (%s).", flag_file ); + } + return 1; + } + return 0; +} + +// **************************************************************************** +// Service Enable - Result Handler +// =============================== +static SmErrorT service_enable_result_handler( SmServiceT* service, + SmServiceActionT action_running, SmServiceActionResultT action_result, + SmServiceStateT service_state, SmServiceStatusT service_status, + SmServiceConditionT service_condition, const char reason_text[] ) +{ + bool retries_exhausted = true; + int max_failure_retries; + int max_timeout_retries; + int max_total_retries; + SmErrorT error; + + if( SM_SERVICE_ACTION_RESULT_SUCCESS == action_result ) + { + DPRINTFD( "Action (%s) of service (%s) completed with success.", + sm_service_action_str( action_running ), service->name ); + goto REPORT; + } + + error = sm_service_action_max_retries( service->name, action_running, + &max_failure_retries, + &max_timeout_retries, + &max_total_retries ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get max retries for action (%s) of service (%s), " + "error=%s.", sm_service_action_str( action_running ), + service->name, sm_error_str( error ) ); + goto REPORT; + } + + if( SM_SERVICE_ACTION_RESULT_FAILED == action_result ) + { + retries_exhausted = + (( max_failure_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + + } else if( SM_SERVICE_ACTION_RESULT_TIMEOUT == action_result ) { + retries_exhausted = + (( max_timeout_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + } + + if( retries_exhausted ) + { + DPRINTFI( "Max retires met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + goto REPORT; + } else { + DPRINTFI( "Max retires not met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + + error = sm_service_enable( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enable service (%s), error=%s.", + service->name, sm_error_str( error ) ); + goto REPORT; + } + } + + return( SM_OKAY ); + +REPORT: + service->action_attempts = 0; + + error = sm_service_fsm_action_complete_handler( service->name, + action_running, action_result, service_state, + service_status, service_condition, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service (%s) fsm action complete, " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Timeout +// ======================== +static bool sm_service_enable_timeout( SmTimerIdT timer_id, int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( false ); + } + + sm_service_enable_throttle_uncheck(); + + if( SM_SERVICE_ACTION_ENABLE != service->action_running ) + { + DPRINTFE( "Service (%s) not running action (%s).", service->name, + sm_service_action_str( service->action_running ) ); + return( false ); + } + + action_running = service->action_running; + + error = sm_service_action_result( SM_SERVICE_ACTION_PLUGIN_TIMEOUT, + service->name, service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) defaulting " + "to failed, exit_code=%i, error=%s.", service->name, + SM_SERVICE_ACTION_PLUGIN_TIMEOUT, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + + DPRINTFI( "Action (%s) timeout with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, SM_SERVICE_ACTION_PLUGIN_TIMEOUT ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_enable_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle enable result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Complete +// ========================= +static void sm_service_enable_complete( pid_t pid, int exit_code, + int64_t user_data ) +{ + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + if( SM_PROCESS_FAILED == exit_code ) + { + exit_code = SM_SERVICE_ACTION_PLUGIN_FAILURE; + } + + service = sm_service_table_read_by_action_pid( (int) pid ); + if( NULL == service ) + { + DPRINTFE( "Failed to query service based on pid (%i), error=%s.", + (int) pid, sm_error_str(SM_NOT_FOUND) ); + return; + } + + sm_service_enable_throttle_uncheck(); + + if( SM_SERVICE_ACTION_ENABLE != service->action_running ) + { + DPRINTFE( "Service (%s) not running enable action.", service->name ); + return; + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY == error ) + { + DPRINTFD( "Timer stopped for action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + } else { + DPRINTFE( "Failed to stop timer for action (%s) of " + "service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + } + + action_running = service->action_running; + + if( SM_SERVICE_ACTION_PLUGIN_FORCE_SUCCESS == exit_code ) + { + DPRINTFI( "Action (%s) for service (%s) force-passed.", + sm_service_action_str( action_running ), service->name ); + + action_result = SM_SERVICE_ACTION_RESULT_SUCCESS; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + + } else { + error = sm_service_action_result( exit_code, service->name, + service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) " + "defaulting to failed, exit_code=%i, error=%s.", + service->name, exit_code, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + } + + DPRINTFI( "Action (%s) completed with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, exit_code ); + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_enable_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle enable result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable +// ============== +SmErrorT sm_service_enable( SmServiceT* service ) +{ + char timer_name[80] = ""; + int process_id = -1; + int timeout = 0; + bool dependency_met; + SmTimerIdT timer_id = SM_TIMER_ID_INVALID; + SmErrorT error; + + // Are enable dependencies met? + error = sm_service_dependency_enable_met( service, &dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check service (%s) dependencies, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + if( !dependency_met ) + { + DPRINTFD( "Some dependencies for service (%s) were not met.", + service->name ); + return( SM_OKAY ); + } + + DPRINTFD( "All dependencies for service (%s) were met.", service->name ); + + // Run action. + error = sm_service_action_run( service->name, + service->instance_name, + service->instance_params, + SM_SERVICE_ACTION_ENABLE, + &process_id, &timeout ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to run enable action for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + // Register for action script exit notification. + error = sm_process_death_register( process_id, true, + sm_service_enable_complete, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for enable action completion for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + abort(); + } + + // Create timer for action completion. + snprintf( timer_name, sizeof(timer_name), "%s %s action", + service->name, sm_service_action_str( SM_SERVICE_ACTION_ENABLE ) ); + + if ( 0 != handle_special_upgrade_case(service, &timeout) ) + { + DPRINTFI( "Extend service (%s) enable timeout to (%d) ms", service->name, timeout); + } + + error = sm_timer_register( timer_name, timeout, sm_service_enable_timeout, + service->id, &timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create a timer for action (%s) for service (%s), " + "error=%s.", sm_service_action_str( SM_SERVICE_ACTION_ENABLE ), + service->name, sm_error_str( error ) ); + abort(); + } + + service->action_running = SM_SERVICE_ACTION_ENABLE; + service->action_pid = process_id; + service->action_timer_id = timer_id; + service->action_attempts += 1; + + DPRINTFI( "Started enable action (%i) for service (%s).", process_id, + service->name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Abort +// ====================== +SmErrorT sm_service_enable_abort( SmServiceT* service ) +{ + SmErrorT error; + sm_service_enable_throttle_uncheck(); + + DPRINTFI( "Aborting action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Cancel timer for action (%s) of service (%s) failed, " + "error=%s.", service->name, + sm_service_action_str( service->action_running ), + sm_error_str( error ) ); + return( error ); + } + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + service->action_attempts = 0; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Exists +// ======================= +SmErrorT sm_service_enable_exists( SmServiceT* service, bool* exists ) +{ + SmErrorT error; + + error = sm_service_action_exist( service->name, SM_SERVICE_ACTION_ENABLE ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to determine if action (%s) exists for service (%s), " + "error=%s.", sm_service_action_str( SM_SERVICE_ACTION_ENABLE ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_OKAY == error ) + { + *exists = true; + } else { + *exists = false; + } + + return( SM_OKAY ); +} +// **************************************************************************** + + +// **************************************************************************** +// Service Enable - get number int items in a comma separated file +// ========================= +static int _get_num_csv_file(const char* filename) +{ + if( 0 != access( filename, F_OK ) ) + { + return -1; + } + + FILE* f = fopen(filename, "r"); + if( NULL == f ) + { + DPRINTFE("Failed open file %s, error %d", filename, errno); + return 0; + } + + int count = 0; + int n, res; + do + { + res = fscanf(f, "%d,", &n); + if( 1 == res ) + { + count ++; + } + }while(EOF != res); + + fclose(f); + return count; +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable - get initial throttle size +// =========================== +static int get_initial_throttle() +{ + bool is_aio; + SmErrorT error; + error = sm_node_utils_is_aio(&is_aio); + if(SM_OKAY != error) + { + DPRINTFE( "Failed to determine if it is AIO, " + "error=%s.", sm_error_str(error) ); + // prepare for the worst + is_aio = true; + } + + #define MAX_SERVICE_EXPECTED 1000 + if( !is_aio ) + { + return MAX_SERVICE_EXPECTED; + } + + char buf[SM_CONFIGURATION_KEY_MAX_CHAR + 1]; + int size; + if( SM_OKAY == sm_configuration_table_get("ENABLING_THROTTLE", buf, sizeof(buf) - 1) ) + { + size = atoi(buf); + }else + { + size = 0; + } + + int num_platform_cores = _get_num_csv_file(PLATFORM_CORES_FILE); + if( num_platform_cores > size ) + { + size = num_platform_cores; + } + + if( SERVICE_ENABLING_THROTTLE_DEFAULT_SIZE > size ) + size = SERVICE_ENABLING_THROTTLE_DEFAULT_SIZE; + + return size; +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Initialize +// =========================== +SmErrorT sm_service_enable_initialize( void ) +{ + num_initial_cores = get_initial_throttle(); + DPRINTFI("Enable services initial throttle size %d ", num_initial_cores); + + if( 0 != sem_init(&sem, 0, num_initial_cores) ) + { + DPRINTFE( "Could not initialize sempaphore. Error (%d)", errno ); + return SM_FAILED; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Finalize +// ========================= +SmErrorT sm_service_enable_finalize( void ) +{ + sem_destroy(&sem); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enable - get number of extra cores +// ========================= +static int get_extra_cores() +{ + return _get_num_csv_file(EXTRA_CORES_STORAGE); +} +// **************************************************************************** + +// **************************************************************************** +// get a ticket to enable service +// ============== +bool sm_service_enable_throttle_check( void ) +{ + int wait_res = sem_trywait(&sem); + if ( 0 == wait_res ) + { + return true; + } else if( EAGAIN == errno ) + { + mutex_holder holder(&_mutex); + if(check_more_cores_available) + { + int new_num_platform_cores = get_extra_cores(); + if( -1 == new_num_platform_cores ) + { + //not ready, will try again next attempt + } + else + { + if (num_initial_cores < new_num_platform_cores) + { + num_extra_cores = new_num_platform_cores - num_initial_cores; + DPRINTFI("Enable services additional throttle size %d ", num_extra_cores); + + if( 0 != sem_init(&sem_more_cores, 0, num_extra_cores) ) + { + DPRINTFE( "Could not initialize sempaphore for additional cores. Error (%d)", errno ); + // cannot use additional cores + num_extra_cores = 0; + }else + { + more_cores_available = true; + } + }else + { + DPRINTFI("Enable services no more additional core available"); + } + check_more_cores_available = false; + } + + }else if (more_cores_available) + { + wait_res = sem_trywait(&sem_more_cores); + if ( 0 == wait_res ) + { + return true; + }else if( EAGAIN != errno ) + { + DPRINTFE( "Wait for additional cores failed error (%d) ", errno ); + } + } + }else + { + DPRINTFE( "Wait failed error (%d) ", errno ); + } + return false; +} +// **************************************************************************** + +// **************************************************************************** +// return a ticket after enabling service completed +// ============== +void sm_service_enable_throttle_uncheck( void ) +{ + int res; + res = sem_post(&sem); + if( -1 == res ) + { + if(EOVERFLOW == errno) + { + res = sem_post(&sem_more_cores); + } + } + + if( 0 != res ) + { + DPRINTFE( "Error uncheck enable throttle. Error (%d)", errno ); + } +} diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enable.h b/service-mgmt/sm-1.0.0/src/sm_service_enable.h new file mode 100644 index 00000000..2254bc69 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enable.h @@ -0,0 +1,68 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ENABLE_H__ +#define __SM_SERVICE_ENABLE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// add more cores for enabling service +// ============== +extern void sm_service_enable_throttle_add_cores( bool additional_cores ); +// **************************************************************************** + +// **************************************************************************** +// get a ticket to enable service +// ============== +extern bool sm_service_enable_throttle_check( void ); +// **************************************************************************** + +// **************************************************************************** +// return a ticket after enabling service completed +// ============== +extern void sm_service_enable_throttle_uncheck( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Enable +// ============== +extern SmErrorT sm_service_enable( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Abort +// ====================== +extern SmErrorT sm_service_enable_abort( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Exists +// ======================= +extern SmErrorT sm_service_enable_exists( SmServiceT* service, bool* exists ); +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Initialize +// =========================== +extern SmErrorT sm_service_enable_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Enable - Finalize +// ========================= +extern SmErrorT sm_service_enable_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ENABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabled_active_state.c b/service-mgmt/sm-1.0.0/src/sm_service_enabled_active_state.c new file mode 100644 index 00000000..7bd50910 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabled_active_state.c @@ -0,0 +1,398 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_enabled_active_state.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_service_dependency.h" +#include "sm_service_fsm.h" +#include "sm_service_go_standby.h" +#include "sm_service_disable.h" +#include "sm_service_audit.h" +#include "sm_service_heartbeat_api.h" + +// **************************************************************************** +// Service Enabled Active State - Audit Timer +// ========================================== +static bool sm_service_enabled_active_state_audit_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_AUDIT, NULL, + "periodic audit" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform audit on service (%s), error=%s.", + service->name, sm_error_str( error ) ); + return( true ); + } + + DPRINTFD( "Audit on service (%s) requested.", service->name ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Entry +// ==================================== +SmErrorT sm_service_enabled_active_state_entry( SmServiceT* service ) +{ + char timer_name[80] = ""; + int audit_interval; + SmTimerIdT audit_timer_id; + SmErrorT error; + + error = sm_service_fsm_process_failure_register( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for process failure for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + } + + error = sm_service_heartbeat_api_start_heartbeat( service->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start service (%s) heartbeat, error=%s.", + service->name, sm_error_str( error ) ); + } + + error = sm_service_fsm_start_fail_countdown_timer( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create fail countdown timer for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + if( service->audit_enabled_exists ) + { + error = sm_service_audit_enabled_interval( service, &audit_interval ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get service (%s) audit interval, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + snprintf( timer_name, sizeof(timer_name), "%s enabled-active audit", + service->name ); + + error = sm_timer_register( timer_name, audit_interval, + sm_service_enabled_active_state_audit_timer, + service->id, &audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create audit-enabled timer for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + service->audit_timer_id = audit_timer_id; + + } else { + DPRINTFI( "No audit for service (%s) exists.", service->name ); + } + + service->transition_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Exit +// =================================== +SmErrorT sm_service_enabled_active_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + error = sm_service_heartbeat_api_stop_heartbeat( service->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop service (%s) heartbeat, error=%s.", + service->name, sm_error_str( error ) ); + } + + error = sm_service_fsm_stop_fail_countdown_timer( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop fail countdown timer for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_SERVICE_ACTION_AUDIT_ENABLED == service->action_running ) + { + error = sm_service_audit_enabled_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + if( SM_TIMER_ID_INVALID != service->audit_timer_id ) + { + error = sm_timer_deregister( service->audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel audit-enabled timer, error=%s.", + sm_error_str( error ) ); + } + + service->audit_timer_id = SM_TIMER_ID_INVALID; + } + + service->transition_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Transition +// ========================================= +SmErrorT sm_service_enabled_active_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + if( SM_SERVICE_STATE_ENABLING == from_state ) + { + service->status = SM_SERVICE_STATUS_NONE; + service->condition = SM_SERVICE_CONDITION_NONE; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Event Handler +// ============================================ +SmErrorT sm_service_enabled_active_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + bool state_dependency_met; + SmServiceStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_HEARTBEAT_OKAY: + service->status = SM_SERVICE_STATUS_NONE; + break; + + case SM_SERVICE_EVENT_HEARTBEAT_WARN: + service->status = SM_SERVICE_STATUS_WARN; + break; + + case SM_SERVICE_EVENT_HEARTBEAT_DEGRADE: + service->status = SM_SERVICE_STATUS_DEGRADED; + break; + + case SM_SERVICE_EVENT_HEARTBEAT_FAIL: + ++(service->fail_count); + + if( service->go_standby_action_exists ) + { + state = SM_SERVICE_STATE_ENABLED_GO_STANDBY; + + } else if( service->disable_action_exists ) { + state = SM_SERVICE_STATE_DISABLING; + + } else { + state = SM_SERVICE_STATE_NIL; + } + + if( SM_SERVICE_STATE_NIL != state ) + { + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_PROCESS_FAILURE: + ++(service->fail_count); + + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLED ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_DISABLED ), + service->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_AUDIT: + error = sm_service_fsm_process_failure_register( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for process failure for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + } + + error = sm_service_heartbeat_api_start_heartbeat( service->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start service (%s) heartbeat, error=%s.", + service->name, sm_error_str( error ) ); + } + + error = sm_service_dependency_enabled_active_state_met( service, + &state_dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check dependency state for service (%s), " + "error=%s", service->name, sm_error_str( error ) ); + return( error ); + } + + if(( state_dependency_met )&&( service->audit_enabled_exists )) + { + error = sm_service_audit_enabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_AUDIT_SUCCESS: + DPRINTFD( "Service (%s) audit success.", service->name ); + break; + + case SM_SERVICE_EVENT_AUDIT_MISMATCH: + ++(service->fail_count); + + state = *(SmServiceStateT*) + event_data[SM_SERVICE_EVENT_DATA_STATE]; + + DPRINTFI( "State mismatch for service (%s), expected=%s, " + "result=%s.", service->name, + sm_service_state_str(SM_SERVICE_STATE_ENABLED_ACTIVE), + sm_service_state_str(state) ); + + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_AUDIT_FAILED: + case SM_SERVICE_EVENT_AUDIT_TIMEOUT: + ++(service->fail_count); + + case SM_SERVICE_EVENT_DISABLE: + if( service->disable_action_exists ) { + state = SM_SERVICE_STATE_DISABLING; + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + } else + { + DPRINTFI( "Service (%s) received disable event without " + "desired action, event is ignored.", service->name ); + } + break; + case SM_SERVICE_EVENT_GO_STANDBY: + if( service->go_standby_action_exists ) { + state = SM_SERVICE_STATE_ENABLED_GO_STANDBY; + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + }else + { + DPRINTFI( "Service (%s) received go_standby event without " + "desired action, event is ignored.", service->name ); + } + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Initialize +// ========================================= +SmErrorT sm_service_enabled_active_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Finalize +// ======================================= +SmErrorT sm_service_enabled_active_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabled_active_state.h b/service-mgmt/sm-1.0.0/src/sm_service_enabled_active_state.h new file mode 100644 index 00000000..4e428ec7 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabled_active_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ENABLED_ACTIVE_STATE_H__ +#define __SM_SERVICE_ENABLED_ACTIVE_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Enabled Active State - Entry +// ==================================== +extern SmErrorT sm_service_enabled_active_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Exit +// =================================== +extern SmErrorT sm_service_enabled_active_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Transition +// ========================================= +extern SmErrorT sm_service_enabled_active_state_transition( + SmServiceT* service, SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Event Handler +// ============================================ +extern SmErrorT sm_service_enabled_active_state_event_handler( + SmServiceT* service, SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Initialize +// ========================================= +extern SmErrorT sm_service_enabled_active_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Active State - Finalize +// ======================================= +extern SmErrorT sm_service_enabled_active_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ENABLED_ACTIVE_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_active_state.c b/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_active_state.c new file mode 100644 index 00000000..d90e93ea --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_active_state.c @@ -0,0 +1,275 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_enabled_go_active_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_fsm.h" +#include "sm_service_go_active.h" + +#define SM_SERVICE_GO_ACTIVE_TIMEOUT_IN_MS 300000 + + +// **************************************************************************** +// handling special upgrade case. +// THIS IS A HACK TO TEMPORALLY OVERCOME ISCSI ENABLE TIMEOUT AFTER UPGRADE +// THIS CODE SHOULD BE REMOVED in Release 17.xx +// =============================== +static int handle_special_upgrade_case(int* timeout_ms) +{ + FILE* fp; + char flag_file[] = "/tmp/.extend_sm_iscsi_enable_timeout"; + int reading_sec; + fp = fopen( flag_file, "r" ); + if ( NULL == fp) + return 0; + + fscanf( fp, "%d", &reading_sec ); + fclose(fp); + + if ( reading_sec <= *timeout_ms ) + { + reading_sec = 960; // make it 16 minutes + } + + DPRINTFI( "Extending go-active timeout from %d ms to %d ms", + *timeout_ms, reading_sec * 1000); + *timeout_ms = reading_sec * 1000; + + return 1; +} + +// **************************************************************************** +// Service Enabled Go-Active State - Timeout Timer +// =============================================== +static bool sm_service_enabled_go_active_state_timeout_timer( + SmTimerIdT timer_id, int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_GO_ACTIVE_TIMEOUT, + NULL, "overall go-active timeout" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal overall go-active timeout to service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( true ); + } + + DPRINTFI( "Service (%s) go-active overall timeout.", service->name ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Entry +// ======================================= +SmErrorT sm_service_enabled_go_active_state_entry( SmServiceT* service ) +{ + char timer_name[80] = ""; + SmTimerIdT action_state_timer_id; + SmErrorT error; + int timeout = SM_SERVICE_GO_ACTIVE_TIMEOUT_IN_MS; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel go-active overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + snprintf( timer_name, sizeof(timer_name), "%s go-active overall timeout", + service->name ); + + handle_special_upgrade_case(&timeout); + error = sm_timer_register( timer_name, + timeout, + sm_service_enabled_go_active_state_timeout_timer, + service->id, &action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create go-active overall timer for service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_state_timer_id = action_state_timer_id; + + error = sm_service_go_active( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-active on service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Exit +// ====================================== +SmErrorT sm_service_enabled_go_active_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel go-active overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + if( SM_SERVICE_ACTION_GO_ACTIVE == service->action_running ) + { + error = sm_service_go_active_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + service->action_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Transition +// ============================================ +SmErrorT sm_service_enabled_go_active_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Event Handler +// =============================================== +SmErrorT sm_service_enabled_go_active_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_GO_ACTIVE: + if( SM_SERVICE_ACTION_GO_ACTIVE != service->action_running ) + { + error = sm_service_go_active( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-active on service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_GO_ACTIVE_SUCCESS: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLED_ACTIVE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( SM_SERVICE_STATE_ENABLED_ACTIVE ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_GO_ACTIVE_FAILED: + case SM_SERVICE_EVENT_GO_ACTIVE_TIMEOUT: + ++(service->fail_count); + ++(service->action_fail_count); + ++(service->transition_fail_count); + + case SM_SERVICE_EVENT_GO_STANDBY: + case SM_SERVICE_EVENT_DISABLE: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLED_GO_STANDBY ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( + SM_SERVICE_STATE_ENABLED_GO_STANDBY ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Initialize +// ============================================ +SmErrorT sm_service_enabled_go_active_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Finalize +// ========================================== +SmErrorT sm_service_enabled_go_active_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_active_state.h b/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_active_state.h new file mode 100644 index 00000000..204b032e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_active_state.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ENABLED_GO_ACTIVE_STATE_H__ +#define __SM_SERVICE_ENABLED_GO_ACTIVE_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Enabled Go-Active State - Entry +// ======================================= +extern SmErrorT sm_service_enabled_go_active_state_entry( + SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Exit +// ====================================== +extern SmErrorT sm_service_enabled_go_active_state_exit( + SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Transition +// ============================================ +extern SmErrorT sm_service_enabled_go_active_state_transition( + SmServiceT* service, SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Event Handler +// =============================================== +extern SmErrorT sm_service_enabled_go_active_state_event_handler( + SmServiceT* service, SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Initialize +// ============================================ +extern SmErrorT sm_service_enabled_go_active_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Active State - Finalize +// ========================================== +extern SmErrorT sm_service_enabled_go_active_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ENABLED_GO_ACTIVE_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_standby_state.c b/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_standby_state.c new file mode 100644 index 00000000..2493b161 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_standby_state.c @@ -0,0 +1,350 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_enabled_go_standby_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_fsm.h" +#include "sm_service_go_standby.h" +#include "sm_service_audit.h" + +#define SM_SERVICE_GO_STANDBY_TIMEOUT_IN_MS 300000 + +// **************************************************************************** +// Service Enabled Go-Standby State - Timeout Timer +// ================================================ +static bool sm_service_enabled_go_standby_state_timeout_timer( + SmTimerIdT timer_id, int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_GO_STANDBY_TIMEOUT, + NULL, "overall go-standby timeout" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal overall go-standby timeout to service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( true ); + } + + DPRINTFI( "Service (%s) go-standby overall timeout.", service->name ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Entry +// ======================================== +SmErrorT sm_service_enabled_go_standby_state_entry( SmServiceT* service ) +{ + char timer_name[80] = ""; + SmTimerIdT action_state_timer_id; + SmErrorT error; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel go-standby overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + snprintf( timer_name, sizeof(timer_name), "%s go-standby overall timeout", + service->name ); + + error = sm_timer_register( timer_name, + SM_SERVICE_GO_STANDBY_TIMEOUT_IN_MS, + sm_service_enabled_go_standby_state_timeout_timer, + service->id, &action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create go-standby overall timer for service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_state_timer_id = action_state_timer_id; + + error = sm_service_go_standby( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-standby on service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Exit +// ======================================= +SmErrorT sm_service_enabled_go_standby_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel go-standby overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + if( SM_SERVICE_ACTION_GO_STANDBY == service->action_running ) + { + error = sm_service_go_standby_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + else if( SM_SERVICE_ACTION_AUDIT_ENABLED == service->action_running ) + { + error = sm_service_audit_enabled_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + service->action_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Transition +// ============================================= +SmErrorT sm_service_enabled_go_standby_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Event Handler +// ================================================ +SmErrorT sm_service_enabled_go_standby_state_event_handler( + SmServiceT* service, SmServiceEventT event, void* event_data[] ) +{ + SmServiceStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_GO_ACTIVE: + if(( SM_SERVICE_ACTION_GO_STANDBY != service->action_running )&& + !(( SM_SERVICE_STATUS_FAILED == service->status )&& + ( SM_SERVICE_CONDITION_FATAL_FAILURE == service->condition ))&& + ( service->go_active_action_exists )) + { + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLED_GO_ACTIVE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( + SM_SERVICE_STATE_ENABLED_GO_ACTIVE ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_GO_STANDBY: + if( service->transition_fail_count >= service->max_transition_failures ) + { + if( SM_SERVICE_CONDITION_FATAL_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_FATAL_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "transition failures (%i).", service->name, + service->max_transition_failures ); + } + } + else if( service->action_fail_count >= service->max_action_failures ) + { + if( SM_SERVICE_CONDITION_ACTION_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_ACTION_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "action failures (%i).", service->name, + service->max_action_failures ); + } + } else { + if(( SM_SERVICE_ACTION_GO_STANDBY != service->action_running )&& + ( SM_SERVICE_ACTION_AUDIT_ENABLED != service->action_running )) + { + error = sm_service_go_standby( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-standby on service (%s), " + "error=%s", service->name, + sm_error_str( error ) ); + return( error ); + } + } + } + break; + + case SM_SERVICE_EVENT_GO_STANDBY_SUCCESS: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLED_STANDBY ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( SM_SERVICE_STATE_ENABLED_STANDBY ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_GO_STANDBY_FAILED: + case SM_SERVICE_EVENT_GO_STANDBY_TIMEOUT: + ++(service->action_fail_count); + ++(service->transition_fail_count); + + if( service->transition_fail_count >= service->max_transition_failures ) + { + if( SM_SERVICE_CONDITION_FATAL_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_FATAL_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "transition failures (%i).", service->name, + service->max_transition_failures ); + } + } + else if( service->action_fail_count >= service->max_action_failures ) + { + if( SM_SERVICE_CONDITION_ACTION_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_ACTION_FAILURE; + + DPRINTFI( "Service (%s) is failed and has reached max " + "action failures (%i).", service->name, + service->max_action_failures ); + } + } + + // Do an audit to make sure the process is still running. + error = sm_service_audit_enabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_AUDIT_SUCCESS: + // Service engine will request an enable-go-standby again. + DPRINTFD( "Service (%s) audit success.", service->name ); + break; + + case SM_SERVICE_EVENT_AUDIT_MISMATCH: + state = *(SmServiceStateT*) + event_data[SM_SERVICE_EVENT_DATA_STATE]; + + DPRINTFI( "State mismatch for service (%s), expected=%s, " + "result=%s.", service->name, + sm_service_state_str(SM_SERVICE_STATE_ENABLED_ACTIVE), + sm_service_state_str(state) ); + + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_AUDIT_FAILED: + case SM_SERVICE_EVENT_AUDIT_TIMEOUT: + // Ignore. + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Initialize +// ============================================= +SmErrorT sm_service_enabled_go_standby_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Finalize +// =========================================== +SmErrorT sm_service_enabled_go_standby_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_standby_state.h b/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_standby_state.h new file mode 100644 index 00000000..8e39e38e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabled_go_standby_state.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ENABLED_GO_STANDBY_STATE_H__ +#define __SM_SERVICE_ENABLED_GO_STANDBY_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Enabled Go-Standby State - Entry +// ======================================== +extern SmErrorT sm_service_enabled_go_standby_state_entry( + SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Exit +// ======================================= +extern SmErrorT sm_service_enabled_go_standby_state_exit( + SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Transition +// ============================================= +extern SmErrorT sm_service_enabled_go_standby_state_transition( + SmServiceT* service, SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Event Handler +// ================================================ +extern SmErrorT sm_service_enabled_go_standby_state_event_handler( + SmServiceT* service, SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Initialize +// ============================================= +extern SmErrorT sm_service_enabled_go_standby_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Go-Standby State - Finalize +// =========================================== +extern SmErrorT sm_service_enabled_go_standby_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ENABLED_GO_STANDBY_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabled_standby_state.c b/service-mgmt/sm-1.0.0/src/sm_service_enabled_standby_state.c new file mode 100644 index 00000000..aaeb99e8 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabled_standby_state.c @@ -0,0 +1,396 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_enabled_standby_state.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_service_dependency.h" +#include "sm_service_fsm.h" +#include "sm_service_disable.h" +#include "sm_service_go_active.h" +#include "sm_service_audit.h" +#include "sm_service_heartbeat_api.h" + +// **************************************************************************** +// Service Enabled Standby State - Audit Timer +// =========================================== +static bool sm_service_enabled_standby_state_audit_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_AUDIT, NULL, + "periodic audit" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to perform audit on service (%s), error=%s.", + service->name, sm_error_str( error ) ); + return( true ); + } + + DPRINTFD( "Audit on service (%s) requested.", service->name ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Entry +// ===================================== +SmErrorT sm_service_enabled_standby_state_entry( SmServiceT* service ) +{ + char timer_name[80] = ""; + int audit_interval; + SmTimerIdT audit_timer_id; + SmErrorT error; + + error = sm_service_fsm_process_failure_register( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for process failure for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + } + + error = sm_service_heartbeat_api_start_heartbeat( service->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start service (%s) heartbeat, error=%s.", + service->name, sm_error_str( error ) ); + } + + error = sm_service_fsm_start_fail_countdown_timer( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create fail countdown timer for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + if( service->audit_enabled_exists ) + { + error = sm_service_audit_enabled_interval( service, &audit_interval ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get service (%s) audit interval, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + snprintf( timer_name, sizeof(timer_name), "%s enabled-standby audit", + service->name ); + + error = sm_timer_register( timer_name, audit_interval, + sm_service_enabled_standby_state_audit_timer, + service->id, &audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create audit-enabled timer for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + service->audit_timer_id = audit_timer_id; + + } else { + DPRINTFI( "No audit for service (%s) exists.", service->name ); + } + + service->transition_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Exit +// ==================================== +SmErrorT sm_service_enabled_standby_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + error = sm_service_heartbeat_api_stop_heartbeat( service->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop service (%s) heartbeat, error=%s.", + service->name, sm_error_str( error ) ); + } + + error = sm_service_fsm_stop_fail_countdown_timer( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to stop fail countdown timer for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_SERVICE_ACTION_AUDIT_ENABLED == service->action_running ) + { + error = sm_service_audit_enabled_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + if( SM_TIMER_ID_INVALID != service->audit_timer_id ) + { + error = sm_timer_deregister( service->audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel audit-enabled timer, error=%s.", + sm_error_str( error ) ); + } + + service->audit_timer_id = SM_TIMER_ID_INVALID; + } + + service->transition_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Transition +// ========================================== +SmErrorT sm_service_enabled_standby_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + if( SM_SERVICE_STATE_ENABLING == from_state ) + { + service->status = SM_SERVICE_STATUS_NONE; + service->condition = SM_SERVICE_CONDITION_NONE; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Event Handler +// ============================================= +SmErrorT sm_service_enabled_standby_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + bool state_dependency_met; + SmServiceStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_HEARTBEAT_OKAY: + service->status = SM_SERVICE_STATUS_NONE; + break; + + case SM_SERVICE_EVENT_HEARTBEAT_WARN: + service->status = SM_SERVICE_STATUS_WARN; + break; + + case SM_SERVICE_EVENT_HEARTBEAT_DEGRADE: + service->status = SM_SERVICE_STATUS_DEGRADED; + break; + + case SM_SERVICE_EVENT_HEARTBEAT_FAIL: + ++(service->fail_count); + + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_DISABLING ), + service->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_PROCESS_FAILURE: + ++(service->fail_count); + + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLED ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_DISABLED ), + service->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_GO_ACTIVE: + if(( service->fail_count < service->max_failures )&& + ( service->go_active_action_exists )) + { + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLED_GO_ACTIVE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( + SM_SERVICE_STATE_ENABLED_GO_ACTIVE ), + service->name, sm_error_str( error ) ); + return( error ); + } + } else if( service->fail_count >= service->max_failures ) { + DPRINTFI( "Service (%s) has reached max failures (%i).", + service->name, service->max_failures ); + + if( service->disable_action_exists ) + { + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( + SM_SERVICE_STATE_DISABLING ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + } + break; + + case SM_SERVICE_EVENT_AUDIT: + error = sm_service_fsm_process_failure_register( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for process failure for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + } + + error = sm_service_heartbeat_api_start_heartbeat( service->name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to start service (%s) heartbeat, error=%s.", + service->name, sm_error_str( error ) ); + } + + error = sm_service_dependency_enabled_standby_state_met( service, + &state_dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check dependency state for service (%s), " + "error=%s", service->name, sm_error_str( error ) ); + return( error ); + } + + if(( state_dependency_met )&&( service->audit_enabled_exists )) + { + error = sm_service_audit_enabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_AUDIT_SUCCESS: + DPRINTFD( "Service (%s) audit success.", service->name ); + break; + + case SM_SERVICE_EVENT_AUDIT_MISMATCH: + ++(service->fail_count); + + state = *(SmServiceStateT*) + event_data[SM_SERVICE_EVENT_DATA_STATE]; + + DPRINTFI( "State mismatch for service (%s), expected=%s, " + "result=%s.", service->name, + sm_service_state_str(SM_SERVICE_STATE_ENABLED_STANDBY), + sm_service_state_str(state) ); + + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_AUDIT_FAILED: + case SM_SERVICE_EVENT_AUDIT_TIMEOUT: + ++(service->fail_count); + + case SM_SERVICE_EVENT_DISABLE: + if( service->disable_action_exists ) + { + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_DISABLING ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Initialize +// ========================================== +SmErrorT sm_service_enabled_standby_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Finalize +// ======================================== +SmErrorT sm_service_enabled_standby_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabled_standby_state.h b/service-mgmt/sm-1.0.0/src/sm_service_enabled_standby_state.h new file mode 100644 index 00000000..877aad7f --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabled_standby_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ENABLED_STANDBY_STATE_H__ +#define __SM_SERVICE_ENABLED_STANDBY_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Enabled Standby State - Entry +// ===================================== +extern SmErrorT sm_service_enabled_standby_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Exit +// ==================================== +extern SmErrorT sm_service_enabled_standby_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Transition +// ========================================== +extern SmErrorT sm_service_enabled_standby_state_transition( + SmServiceT* service, SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Event Handler +// ============================================= +extern SmErrorT sm_service_enabled_standby_state_event_handler( + SmServiceT* service, SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Initialize +// ========================================== +extern SmErrorT sm_service_enabled_standby_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabled Standby State - Finalize +// ======================================== +extern SmErrorT sm_service_enabled_standby_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ENABLED_STANDBY_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabling_state.c b/service-mgmt/sm-1.0.0/src/sm_service_enabling_state.c new file mode 100644 index 00000000..c1fafc0d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabling_state.c @@ -0,0 +1,290 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_enabling_state.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_fsm.h" +#include "sm_service_go_active.h" +#include "sm_service_enable.h" + +#define SM_SERVICE_ENABLING_TIMEOUT_IN_MS 300000 + + +// **************************************************************************** +// handling special upgrade case. +// THIS IS A HACK TO TEMPORALLY OVERCOME ISCSI ENABLE TIMEOUT AFTER UPGRADE +// THIS CODE SHOULD BE REMOVED in Release 17.xx +// =============================== +static int handle_special_upgrade_case(SmServiceT* service, int* timeout_ms) +{ + FILE* fp; + char flag_file[] = "/tmp/.extend_sm_iscsi_enable_timeout"; + int reading_sec = 0; + if (0 == strcmp(service->name, "iscsi")) + { + fp = fopen( flag_file, "r" ); + if ( NULL == fp) + return 0; + + fscanf( fp, "%d", &reading_sec ); + fclose(fp); + + if ( reading_sec <= 0 ) + { + reading_sec = 960; // make it 16 minutes + } + + DPRINTFI( "Extending enabling timeout for iscsi from %d ms to %d ms", + *timeout_ms, reading_sec * 1000); + *timeout_ms = reading_sec * 1000; + + return 1; + } + return 0; +} + + +// **************************************************************************** +// Service Enabling State - Timeout Timer +// ====================================== + +static bool sm_service_enabling_state_timeout_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_ENABLE_TIMEOUT, + NULL, "overall enabling timeout" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal overall enabling timeout to service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( true ); + } + + DPRINTFI( "Service (%s) enabling overall timeout.", service->name ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Entry +// ============================== +SmErrorT sm_service_enabling_state_entry( SmServiceT* service ) +{ + char timer_name[80] = ""; + SmTimerIdT action_state_timer_id; + SmErrorT error; + int timeout = SM_SERVICE_ENABLING_TIMEOUT_IN_MS; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel enabling overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + snprintf( timer_name, sizeof(timer_name), "%s enabling overall timeout", + service->name ); + + if ( 0 != handle_special_upgrade_case(service, &timeout) ) + { + DPRINTFI( "Extend service (%s) enabling timeout to (%d) ms", service->name, timeout); + } + error = sm_timer_register( timer_name, + timeout, + sm_service_enabling_state_timeout_timer, + service->id, &action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create enabling overall timer for service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_state_timer_id = action_state_timer_id; + + error = sm_service_enable( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enable service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Exit +// ============================= +SmErrorT sm_service_enabling_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel enabling overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + if( SM_SERVICE_ACTION_ENABLE == service->action_running ) + { + error = sm_service_enable_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + service->action_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Transition +// =================================== +SmErrorT sm_service_enabling_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Event Handler +// ====================================== +SmErrorT sm_service_enabling_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + SmServiceStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_ENABLE: + if( SM_SERVICE_ACTION_ENABLE != service->action_running ) + { + error = sm_service_enable( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enable service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_EVENT_ENABLE_SUCCESS: + if( service->go_active_action_exists ) + { + state = SM_SERVICE_STATE_ENABLED_STANDBY; + } else { + state = SM_SERVICE_STATE_ENABLED_ACTIVE; + } + + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_ENABLE_FAILED: + case SM_SERVICE_EVENT_ENABLE_TIMEOUT: + ++(service->fail_count); + ++(service->action_fail_count); + ++(service->transition_fail_count); + + case SM_SERVICE_EVENT_DISABLE: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_DISABLING ), + service->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Initialize +// =================================== +SmErrorT sm_service_enabling_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Finalize +// ================================= +SmErrorT sm_service_enabling_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabling_state.h b/service-mgmt/sm-1.0.0/src/sm_service_enabling_state.h new file mode 100644 index 00000000..f9049ec4 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabling_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ENABLING_STATE_H__ +#define __SM_SERVICE_ENABLING_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Enabling State - Entry +// ============================== +extern SmErrorT sm_service_enabling_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Exit +// ============================= +extern SmErrorT sm_service_enabling_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Transition +// =================================== +extern SmErrorT sm_service_enabling_state_transition( SmServiceT* service, + SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Event Handler +// ====================================== +extern SmErrorT sm_service_enabling_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Initialize +// =================================== +extern SmErrorT sm_service_enabling_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling State - Finalize +// ================================== +extern SmErrorT sm_service_enabling_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ENABLING_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabling_throttle_state.c b/service-mgmt/sm-1.0.0/src/sm_service_enabling_throttle_state.c new file mode 100644 index 00000000..068eb4ed --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabling_throttle_state.c @@ -0,0 +1,247 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_enabling_throttle_state.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_fsm.h" +#include "sm_service_go_active.h" +#include "sm_service_enable.h" +#include "sm_service_dependency.h" + +#define SM_SERVICE_ENABLING_THROTTLE_TIMEOUT_IN_MS 25 + +// **************************************************************************** +// Service Enabling Throttle State - Timeout Timer +// ====================================== + +static bool sm_service_enabling_throttle_state_timeout_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + error = sm_service_fsm_event_handler( service->name, + SM_SERVICE_EVENT_ENABLE_THROTTLE, + NULL, "wait for enabling throttle reopen" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service enabling throttle " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( true ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Entry +// ============================== +SmErrorT sm_service_enabling_throttle_state_entry( SmServiceT* service ) +{ + char timer_name[80] = ""; + SmTimerIdT action_state_timer_id; + SmErrorT error; + int timeout = SM_SERVICE_ENABLING_THROTTLE_TIMEOUT_IN_MS; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel enabling overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + bool dependency_met; + // Are enable dependencies met? + error = sm_service_dependency_enable_met( service, &dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check service (%s) dependencies, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + if( !dependency_met ) + { + DPRINTFD( "Some dependencies for service (%s) were not met.", + service->name ); + return( SM_OKAY ); + } + + DPRINTFD( "All dependencies for service (%s) were met.Attempt to enable service ", + service->name ); + + if ( sm_service_enable_throttle_check() ) + { + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_ENABLING ), + service->name, sm_error_str( error ) ); + return( error ); + } + }else + { + snprintf( timer_name, sizeof(timer_name), "%s wait for enabling", + service->name ); + + error = sm_timer_register( timer_name, + timeout, + sm_service_enabling_throttle_state_timeout_timer, + service->id, &action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create enabling throttle timer for service " + "(%s), error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + service->action_state_timer_id = action_state_timer_id; + } + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Exit +// ============================= +SmErrorT sm_service_enabling_throttle_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != service->action_state_timer_id ) + { + error = sm_timer_deregister( service->action_state_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel enabling overall timer, error=%s.", + sm_error_str( error ) ); + } + + service->action_state_timer_id = SM_TIMER_ID_INVALID; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Transition +// =================================== +SmErrorT sm_service_enabling_throttle_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Event Handler +// ====================================== +SmErrorT sm_service_enabling_throttle_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_ENABLE_THROTTLE: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLING_THROTTLE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_ENABLING_THROTTLE ), + service->name, sm_error_str( error ) ); + return( error ); + } + + break; + case SM_SERVICE_EVENT_ENABLE: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_ENABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_ENABLING ), + service->name, sm_error_str( error ) ); + return( error ); + } + + break; + + case SM_SERVICE_EVENT_DISABLE: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_DISABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Set state (%s) of service (%s) failed, error=%s.", + sm_service_state_str( SM_SERVICE_STATE_DISABLING ), + service->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Initialize +// =================================== +SmErrorT sm_service_enabling_throttle_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Finalize +// ================================= +SmErrorT sm_service_enabling_throttle_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_enabling_throttle_state.h b/service-mgmt/sm-1.0.0/src/sm_service_enabling_throttle_state.h new file mode 100644 index 00000000..9c2a278a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_enabling_throttle_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ENABLING_THROTTLE_STATE_H__ +#define __SM_SERVICE_ENABLING_THROTTLE_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Enabling Throttle State - Entry +// ============================== +extern SmErrorT sm_service_enabling_throttle_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Exit +// ============================= +extern SmErrorT sm_service_enabling_throttle_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Transition +// =================================== +extern SmErrorT sm_service_enabling_throttle_state_transition( SmServiceT* service, + SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Event Handler +// ====================================== +extern SmErrorT sm_service_enabling_throttle_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Initialize +// =================================== +extern SmErrorT sm_service_enabling_throttle_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Enabling Throttle State - Finalize +// ================================== +extern SmErrorT sm_service_enabling_throttle_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ENABLING_THROTTLE_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_engine.c b/service-mgmt/sm-1.0.0/src/sm_service_engine.c new file mode 100644 index 00000000..9734a182 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_engine.c @@ -0,0 +1,532 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_engine.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_selobj.h" +#include "sm_time.h" +#include "sm_timer.h" +#include "sm_service_table.h" +#include "sm_service_dependency.h" +#include "sm_service_fsm.h" +#include "sm_service_go_active.h" +#include "sm_service_go_standby.h" + +#define SM_SERVICE_ENGINE_TIMER_IN_MS 500 +#define SM_SERVICE_ENGINE_MIN_TIME_BETWEEN_SIGNALS_IN_MS 100 + +static int _engine_fd = -1; +static SmTimerIdT _engine_timer_id = SM_TIMER_ID_INVALID; + +// **************************************************************************** +// Service Engine - Timeout +// ======================== +static bool sm_service_engine_timeout( SmTimerIdT timer_id, int64_t user_data ) +{ + uint64_t count = 1; + + if( 0 > write( _engine_fd, &count, sizeof(count) ) ) + { + DPRINTFE( "Failed to signal services, error=%s", strerror( errno ) ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Engine - Signal +// ======================= +SmErrorT sm_service_engine_signal( SmServiceT* service ) +{ + static SmTimeT time_last_signal = {0}; + + long ms_expired; + SmTimeT time_now; + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_last_signal ); + + if( SM_SERVICE_ENGINE_MIN_TIME_BETWEEN_SIGNALS_IN_MS > ms_expired ) + { + uint64_t count = 1; + + if( 0 > write( _engine_fd, &count, sizeof(count) ) ) + { + DPRINTFE( "Failed to signal service (%s), error=%s", + service->name, strerror( errno ) ); + return( SM_FAILED ); + } + + time_last_signal = time_now; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Engine - Signal Handler +// =============================== +static void sm_service_engine_signal_handler( void* user_data[], + SmServiceT* service ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + bool disable_required = false; + bool state_dependency_met; + SmServiceStateT desired_state; + SmServiceEventT event = SM_SERVICE_EVENT_UNKNOWN; + SmErrorT error; + + if ( service->disable_skip_dependent ) + { + DPRINTFI( "service %s (state: %s, desired state: %s) to check dependency require disable, skipped", + service->name, sm_service_state_str(service->state), sm_service_state_str(service->desired_state)); + }else + { + // DPRINTFI( "service %s to check dependency require disable", service->name); + error = sm_service_dependency_dependents_require_disable( + service, + &disable_required + ); + + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if dependents require disable for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + return; + } + } + + if( disable_required ) + { + DPRINTFD( "Dependents require disable of service (%s).", + service->name ); + desired_state = SM_SERVICE_STATE_DISABLED; + } else if( SM_SERVICE_STATE_ENABLED_STANDBY == service->desired_state ) + { + if( service->go_standby_action_exists ) + { + desired_state = service->desired_state; + } else { + DPRINTFD( "No go-standby action exists for service (%s), " + "remain disabled.", service->name ); + desired_state = SM_SERVICE_STATE_DISABLED; + } + } else { + desired_state = service->desired_state; + } + + if(( service->clear_fatal_condition )&& + ( SM_SERVICE_STATUS_FAILED == service->status )&& + ( SM_SERVICE_CONDITION_FATAL_FAILURE == service->condition )) + { + service->clear_fatal_condition = false; + service->transition_fail_count = 0; + service->condition = SM_SERVICE_CONDITION_NONE; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str(error) ); + return; + } + + DPRINTFI( "Fail counts and status for service (%s) cleared " + "because clear-fatal-condition indicated.", service->name ); + } else { + service->clear_fatal_condition = false; + + if(( SM_SERVICE_STATUS_FAILED == service->status )&& + ( SM_SERVICE_CONDITION_FATAL_FAILURE == service->condition )) + { + DPRINTFI( "Service (%s) has had a fatal failure and is " + "unrecoverable.", service->name ); + return; + } + } + + switch( service->state ) + { + case SM_SERVICE_STATE_INITIAL: + if( SM_SERVICE_STATE_INITIAL != desired_state ) + { + event = SM_SERVICE_EVENT_AUDIT; + snprintf( reason_text, sizeof(reason_text), + "audit requested" ); + } + break; + + case SM_SERVICE_STATE_UNKNOWN: + event = SM_SERVICE_EVENT_AUDIT; + snprintf( reason_text, sizeof(reason_text), + "audit requested, state is unknown" ); + break; + + case SM_SERVICE_STATE_ENABLED_ACTIVE: + error = sm_service_dependency_enabled_active_state_met( service, + &state_dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check dependency state for service (%s), " + "error=%s", service->name, sm_error_str( error ) ); + return; + } + + if( !state_dependency_met ) + { + event = SM_SERVICE_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-active state dependency was not met" ); + } + else if( SM_SERVICE_STATE_ENABLED_STANDBY == desired_state ) + { + event = SM_SERVICE_EVENT_GO_STANDBY; + snprintf( reason_text, sizeof(reason_text), + "enabled-standby state requested" ); + } + else if( SM_SERVICE_STATE_DISABLED == desired_state ) + { + event = SM_SERVICE_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), + "disable state requested" ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_ACTIVE: + if( SM_SERVICE_STATE_ENABLED_ACTIVE == desired_state ) + { + event = SM_SERVICE_EVENT_GO_ACTIVE; + snprintf( reason_text, sizeof(reason_text), + "enabled-active state requested" ); + } else { + event = SM_SERVICE_EVENT_GO_STANDBY; + snprintf( reason_text, sizeof(reason_text), + "enabled-stanby state requested" ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_STANDBY: + if(( service->recover )&& + ( SM_SERVICE_STATUS_FAILED == service->status )&& + ( SM_SERVICE_CONDITION_ACTION_FAILURE == service->condition )) + { + service->recover = false; + service->action_fail_count = 0; + service->condition = SM_SERVICE_CONDITION_NONE; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str(error) ); + return; + } + + DPRINTFI( "Fail counts and status for service (%s) cleared " + "in enabled-go-standby state.", service->name ); + + if( SM_SERVICE_STATE_ENABLED_ACTIVE == desired_state ) + { + event = SM_SERVICE_EVENT_GO_ACTIVE; + snprintf( reason_text, sizeof(reason_text), + "enabled-active state requested" ); + } else { + service->recover = false; + event = SM_SERVICE_EVENT_GO_STANDBY; + snprintf( reason_text, sizeof(reason_text), + "enabled-standby state requested" ); + } + } else { + service->recover = false; + event = SM_SERVICE_EVENT_GO_STANDBY; + snprintf( reason_text, sizeof(reason_text), + "enabled-standby state requested" ); + } + break; + + case SM_SERVICE_STATE_ENABLED_STANDBY: + error = sm_service_dependency_enabled_standby_state_met( service, + &state_dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check dependency state for service (%s), " + "error=%s", service->name, sm_error_str( error ) ); + return; + } + + if( !state_dependency_met ) + { + event = SM_SERVICE_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-standby state dependency was not met" ); + } + else if( SM_SERVICE_STATE_ENABLED_ACTIVE == desired_state ) + { + event = SM_SERVICE_EVENT_GO_ACTIVE; + snprintf( reason_text, sizeof(reason_text), + "enabled-active state requested" ); + } + else if( SM_SERVICE_STATE_DISABLED == desired_state ) + { + event = SM_SERVICE_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), + "disabled state requested" ); + } + break; + + case SM_SERVICE_STATE_ENABLING_THROTTLE: + if( SM_SERVICE_STATE_ENABLED_ACTIVE == desired_state ) + { + event = SM_SERVICE_EVENT_ENABLE_THROTTLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-active state requested" ); + } + else if( SM_SERVICE_STATE_ENABLED_STANDBY == desired_state ) + { + event = SM_SERVICE_EVENT_ENABLE_THROTTLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-standby state requested" ); + } else { + event = SM_SERVICE_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), + "disabled state requested" ); + } + break; + + case SM_SERVICE_STATE_ENABLING: + if( SM_SERVICE_STATE_ENABLED_ACTIVE == desired_state ) + { + event = SM_SERVICE_EVENT_ENABLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-active state requested" ); + } + else if( SM_SERVICE_STATE_ENABLED_STANDBY == desired_state ) + { + event = SM_SERVICE_EVENT_ENABLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-standby state requested" ); + } else { + event = SM_SERVICE_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), + "disabled state requested" ); + } + break; + + case SM_SERVICE_STATE_DISABLING: + if(( service->recover )&& + ( SM_SERVICE_STATUS_FAILED == service->status )&& + ( SM_SERVICE_CONDITION_ACTION_FAILURE == service->condition )) + { + service->recover = false; + service->action_fail_count = 0; + service->condition = SM_SERVICE_CONDITION_NONE; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str(error) ); + return; + } + + DPRINTFI( "Fail counts and status for service (%s) cleared " + "in disabling state.", service->name ); + + if( SM_SERVICE_STATE_ENABLED_ACTIVE == desired_state ) + { + event = SM_SERVICE_EVENT_ENABLE_THROTTLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-active state requested" ); + } + else if(( SM_SERVICE_STATE_ENABLED_STANDBY == desired_state )&& + ( service->go_active_action_exists )) + { + event = SM_SERVICE_EVENT_ENABLE_THROTTLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-standby state requested" ); + } else { + service->recover = false; + event = SM_SERVICE_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), "disabling" ); + } + } else { + service->recover = false; + event = SM_SERVICE_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), "disabling" ); + } + break; + + case SM_SERVICE_STATE_DISABLED: + if( service->recover ) + { + service->recover = false; + service->fail_count = 0; + service->action_fail_count = 0; + service->transition_fail_count = 0; + service->condition = SM_SERVICE_CONDITION_NONE; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str(error) ); + return; + } + + DPRINTFI( "Fail counts and status for service (%s) cleared " + "in disabled state.", service->name ); + } + + if( SM_SERVICE_STATE_ENABLED_ACTIVE == desired_state ) + { + event = SM_SERVICE_EVENT_ENABLE_THROTTLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-active state requested" ); + } + else if(( SM_SERVICE_STATE_ENABLED_STANDBY == desired_state )&& + ( service->go_active_action_exists )) + { + event = SM_SERVICE_EVENT_ENABLE_THROTTLE; + snprintf( reason_text, sizeof(reason_text), + "enabled-standby state requested" ); + + } else if( SM_SERVICE_STATE_DISABLED == desired_state ) { + service->recover = false; + service->fail_count = 0; + service->action_fail_count = 0; + service->transition_fail_count = 0; + service->status = SM_SERVICE_STATUS_NONE; + service->condition = SM_SERVICE_CONDITION_NONE; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str(error) ); + return; + } + } + break; + + default: + DPRINTFE( "Unknown service (%s) state (%s).", service->name, + sm_service_state_str( service->state ) ); + break; + } + + if( SM_SERVICE_EVENT_UNKNOWN != event ) + { + DPRINTFD( "Sending event (%s) to service (%s).", + sm_service_event_str( event ), service->name ); + + error = sm_service_fsm_event_handler( service->name, event, NULL, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service->name ); + } + } + + return; +} +// **************************************************************************** + +// **************************************************************************** +// Service Engine - Dispatch +// ========================= +static void sm_service_engine_dispatch( int selobj, int64_t user_data ) +{ + uint64_t count; + + read( _engine_fd, &count, sizeof(count) ); + + sm_service_table_foreach( NULL, sm_service_engine_signal_handler ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Engine - Initialize +// =========================== +SmErrorT sm_service_engine_initialize( void ) +{ + SmErrorT error; + + _engine_fd = eventfd( 0, EFD_CLOEXEC | EFD_NONBLOCK ); + if( 0 > _engine_fd ) + { + DPRINTFE( "Failed to open file descriptor,error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + error = sm_selobj_register( _engine_fd, sm_service_engine_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_timer_register( "service engine", + SM_SERVICE_ENGINE_TIMER_IN_MS, + sm_service_engine_timeout, 0, + &_engine_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create engine timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Engine - Finalize +// ========================= +SmErrorT sm_service_engine_finalize( void ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != _engine_timer_id ) + { + error = sm_timer_deregister( _engine_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel engine timer, error=%s.", + sm_error_str( error ) ); + } + _engine_timer_id = SM_TIMER_ID_INVALID; + } + + if( 0 <= _engine_fd ) + { + error = sm_selobj_deregister( _engine_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + close( _engine_fd ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_engine.h b/service-mgmt/sm-1.0.0/src/sm_service_engine.h new file mode 100644 index 00000000..73463dee --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_engine.h @@ -0,0 +1,38 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_ENGINE_H__ +#define __SM_SERVICE_ENGINE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Engine - Signal +// ======================= +extern SmErrorT sm_service_engine_signal( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Engine - Initialize +// =========================== +extern SmErrorT sm_service_engine_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Engine - Finalize +// ========================= +extern SmErrorT sm_service_engine_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_ENGINE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_fsm.c b/service-mgmt/sm-1.0.0/src/sm_service_fsm.c new file mode 100644 index 00000000..a2670181 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_fsm.c @@ -0,0 +1,2014 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_fsm.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_selobj.h" +#include "sm_service_table.h" +#include "sm_service_engine.h" +#include "sm_service_initial_state.h" +#include "sm_service_unknown_state.h" +#include "sm_service_enabled_active_state.h" +#include "sm_service_enabled_go_standby_state.h" +#include "sm_service_enabled_go_active_state.h" +#include "sm_service_enabled_standby_state.h" +#include "sm_service_enabling_state.h" +#include "sm_service_enabling_throttle_state.h" +#include "sm_service_disabling_state.h" +#include "sm_service_disabled_state.h" +#include "sm_service_shutdown_state.h" +#include "sm_service_enable.h" +#include "sm_service_go_active.h" +#include "sm_service_go_standby.h" +#include "sm_service_disable.h" +#include "sm_service_audit.h" +#include "sm_service_heartbeat_api.h" +#include "sm_process_death.h" +#include "sm_log.h" + +#define SM_SERVICE_FSM_PID_FILE_AUDIT_IN_MS 2000 + +static SmServiceHeartbeatCallbacksT _hb_callbacks; +static SmListT* _callbacks = NULL; + +static SmErrorT sm_service_get_terminate_reason(SmServiceT* service, + char reason_text[], int len); + +static bool remove_pid_file(char pid_file[]); + +// **************************************************************************** +// Service FSM - Register Callback +// =============================== +SmErrorT sm_service_fsm_register_callback( SmServiceFsmCallbackT callback ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Deregister Callback +// ================================= +SmErrorT sm_service_fsm_deregister_callback( SmServiceFsmCallbackT callback ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Notify +// ==================== +static void sm_service_fsm_notify( SmServiceT* service ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceFsmCallbackT callback; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callback = (SmServiceFsmCallbackT) entry_data; + + callback( service->name, service->state, service->status, + service->condition ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Fail Countdown Timeout +// ==================================== +static bool sm_service_fsm_fail_countdown_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( true ); + } + + if(( 0 < service->fail_count )&& + ( SM_SERVICE_STATUS_FAILED != service->status )) + { + service->fail_count -= service->fail_countdown; + if( 0 > service->fail_count ) + { + service->fail_count = 0; + + DPRINTFI( "Fail count for service (%s) reset.", + service->name ); + } + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Start Fail Countdown Timer +// ======================================== +SmErrorT sm_service_fsm_start_fail_countdown_timer( SmServiceT* service ) +{ + char timer_name[80] = ""; + SmTimerIdT fail_countdown_timer_id; + SmErrorT error; + + DPRINTFD( "Start fail countdown timer for service (%s).", service->name ); + + snprintf( timer_name, sizeof(timer_name), "%s fail countdown", + service->name ); + + error = sm_timer_register( timer_name, + service->fail_countdown_interval_in_ms, + sm_service_fsm_fail_countdown_timeout, + service->id, &fail_countdown_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create fail countdown timer for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + return( error ); + } + + service->fail_countdown_timer_id = fail_countdown_timer_id; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Stop Fail Countdown Timer +// ======================================= +SmErrorT sm_service_fsm_stop_fail_countdown_timer( SmServiceT* service ) +{ + SmErrorT error; + + DPRINTFD( "Stop fail countdown timer for service (%s).", service->name ); + + if( SM_TIMER_ID_INVALID != service->fail_countdown_timer_id ) + { + error = sm_timer_deregister( service->fail_countdown_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel fail countdown timer for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + } + + service->fail_countdown_timer_id = SM_TIMER_ID_INVALID; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Enter State +// ========================= +static SmErrorT sm_service_fsm_enter_state( SmServiceT* service ) +{ + SmErrorT error; + + switch( service->state ) + { + case SM_SERVICE_STATE_INITIAL: + error = sm_service_initial_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_UNKNOWN: + error = sm_service_unknown_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_ACTIVE: + error = sm_service_enabled_active_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_ACTIVE: + error = sm_service_enabled_go_active_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_STANDBY: + error = sm_service_enabled_go_standby_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_STANDBY: + error = sm_service_enabled_standby_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + + case SM_SERVICE_STATE_ENABLING_THROTTLE: + error = sm_service_enabling_throttle_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLING: + error = sm_service_enabling_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_DISABLING: + error = sm_service_disabling_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_DISABLED: + error = sm_service_disabled_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_SHUTDOWN: + error = sm_service_shutdown_state_entry( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to enter state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service (%s) state (%s).", service->name, + sm_service_state_str( service->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Exit State +// ======================== +static SmErrorT sm_service_fsm_exit_state( SmServiceT* service ) +{ + SmErrorT error; + + switch( service->state ) + { + case SM_SERVICE_STATE_INITIAL: + error = sm_service_initial_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_UNKNOWN: + error = sm_service_unknown_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_ACTIVE: + error = sm_service_enabled_active_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_ACTIVE: + error = sm_service_enabled_go_active_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_STANDBY: + error = sm_service_enabled_go_standby_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_STANDBY: + error = sm_service_enabled_standby_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLING_THROTTLE: + error = sm_service_enabling_throttle_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLING: + error = sm_service_enabling_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_DISABLING: + error = sm_service_disabling_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_DISABLED: + error = sm_service_disabled_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_SHUTDOWN: + error = sm_service_shutdown_state_exit( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to exit state (%s), error=%s.", + service->name, sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service (%s) state (%s).", service->name, + sm_service_state_str( service->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Transition State +// ============================== +static SmErrorT sm_service_fsm_transition_state( SmServiceT* service, + SmServiceStateT from_state ) +{ + SmErrorT error; + + switch( service->state ) + { + case SM_SERVICE_STATE_INITIAL: + error = sm_service_initial_state_transition( service, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_UNKNOWN: + error = sm_service_unknown_state_transition( service, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_ACTIVE: + error = sm_service_enabled_active_state_transition( service, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_ACTIVE: + error = sm_service_enabled_go_active_state_transition( service, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_STANDBY: + error = sm_service_enabled_go_standby_state_transition( service, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_STANDBY: + error = sm_service_enabled_standby_state_transition( service, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLING_THROTTLE: + error = sm_service_enabling_throttle_state_transition( service, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLING: + error = sm_service_enabling_state_transition( service, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_DISABLING: + error = sm_service_disabling_state_transition( service, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_DISABLED: + error = sm_service_disabled_state_transition( service, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_SHUTDOWN: + error = sm_service_shutdown_state_transition( service, from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to transition from state (%s) " + "to state (%s), error=%s.", service->name, + sm_service_state_str( from_state ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service (%s) state (%s).", service->name, + sm_service_state_str( service->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Set State +// ======================= +SmErrorT sm_service_fsm_set_state( SmServiceT* service, SmServiceStateT state ) +{ + SmServiceStateT prev_state; + SmErrorT error, error2; + + prev_state = service->state; + + error = sm_service_fsm_exit_state( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to exit state (%s) service (%s), error=%s.", + sm_service_state_str( service->state ), + service->name, sm_error_str( error ) ); + return( error ); + } + + service->state = state; + + error = sm_service_fsm_transition_state( service, prev_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to transition to state (%s) service (%s), " + "error=%s.", sm_service_state_str( service->state ), + service->name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + error = sm_service_fsm_enter_state( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enter state (%s) service (%s), error=%s.", + sm_service_state_str( service->state ), + service->name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + return( SM_OKAY ); + +STATE_CHANGE_ERROR: + error2 = sm_service_fsm_exit_state( service ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to exit state (%s) service (%s), error=%s.", + sm_service_state_str( service->state ), + service->name, sm_error_str( error2 ) ); + abort(); + } + + service->state = prev_state; + + error2 = sm_service_fsm_transition_state( service, state ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to transition to state (%s) service (%s), " + "error=%s.", sm_service_state_str( service->state ), + service->name, sm_error_str( error2 ) ); + abort(); + } + + error2 = sm_service_fsm_enter_state( service ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to enter state (%s) service (%s), error=%s.", + sm_service_state_str( service->state ), + service->name, sm_error_str( error2 ) ); + abort(); + } + + return( error ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Set Status +// ======================== +SmErrorT sm_service_fsm_set_status( SmServiceT* service, + SmServiceStatusT status, SmServiceConditionT condition ) +{ + bool persist = false; + + switch( status ) + { + case SM_SERVICE_STATUS_NIL: + case SM_SERVICE_STATUS_UNKNOWN: + // Ignore. + break; + + case SM_SERVICE_STATUS_NONE: + service->status = SM_SERVICE_STATUS_NONE; + service->condition = SM_SERVICE_CONDITION_NONE; + persist = true; + break; + + case SM_SERVICE_STATUS_WARN: + if(( SM_SERVICE_STATUS_DEGRADED != service->status )&& + ( SM_SERVICE_STATUS_FAILED != service->status )) + { + service->status = status; + + if(( SM_SERVICE_CONDITION_NIL != condition )&& + ( SM_SERVICE_CONDITION_UNKNOWN != condition )) + { + service->condition = condition; + } else { + service->condition = SM_SERVICE_CONDITION_NONE; + } + persist = true; + } + break; + + case SM_SERVICE_STATUS_DEGRADED: + if( SM_SERVICE_STATUS_FAILED != service->status ) + { + service->status = status; + + if(( SM_SERVICE_CONDITION_NIL != condition )&& + ( SM_SERVICE_CONDITION_UNKNOWN != condition )) + { + service->condition = condition; + } else { + service->condition = SM_SERVICE_CONDITION_NONE; + } + persist = true; + } + break; + + case SM_SERVICE_STATUS_FAILED: + service->status = status; + + if(( SM_SERVICE_CONDITION_NIL != condition )&& + ( SM_SERVICE_CONDITION_UNKNOWN != condition )) + { + service->condition = condition; + } else { + service->condition = SM_SERVICE_CONDITION_NONE; + } + persist = true; + break; + + default: + DPRINTFE( "Uknown status (%i) for service (%s) given.", status, + service->name ); + break; + } + + if( persist ) + { + SmErrorT error; + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str(error) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Event Handler +// =========================== +SmErrorT sm_service_fsm_event_handler( char service_name[], + SmServiceEventT event, void* event_data[], const char reason_text[] ) +{ + SmServiceStateT prev_state; + SmServiceStatusT prev_status; + SmServiceConditionT prev_condition; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = service->state; + prev_status = service->status; + prev_condition = service->condition; + + if( NULL != event_data ) + { + if( NULL != event_data[SM_SERVICE_EVENT_DATA_IS_ACTION] ) + { + bool is_action = *(bool*) event_data[SM_SERVICE_EVENT_DATA_IS_ACTION]; + + if( is_action ) + { + SmServiceStatusT action_status; + SmServiceConditionT action_condition; + + action_status = *(SmServiceStatusT*) + event_data[SM_SERVICE_EVENT_DATA_STATUS]; + action_condition = *(SmServiceConditionT*) + event_data[SM_SERVICE_EVENT_DATA_CONDITION]; + + error = sm_service_fsm_set_status( service, action_status, + action_condition ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set status (%s) and condition (%s) " + "of service (%s), error=%s.", + sm_service_status_str(action_status), + sm_service_condition_str(action_condition), + service->name, sm_error_str( error ) ); + return( error ); + } + } + } + } + + switch( service->state ) + { + case SM_SERVICE_STATE_INITIAL: + error = sm_service_initial_state_event_handler( service, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_UNKNOWN: + error = sm_service_unknown_state_event_handler( service, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_ACTIVE: + error = sm_service_enabled_active_state_event_handler( service, + event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_ACTIVE: + error = sm_service_enabled_go_active_state_event_handler( service, + event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_STANDBY: + error = sm_service_enabled_go_standby_state_event_handler( service, + event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLED_STANDBY: + error = sm_service_enabled_standby_state_event_handler( service, + event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLING_THROTTLE: + error = sm_service_enabling_throttle_state_event_handler( service, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_ENABLING: + error = sm_service_enabling_state_event_handler( service, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + + case SM_SERVICE_STATE_DISABLING: + error = sm_service_disabling_state_event_handler( service, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_DISABLED: + error = sm_service_disabled_state_event_handler( service, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_STATE_SHUTDOWN: + error = sm_service_shutdown_state_event_handler( service, event, + event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_name, + sm_service_event_str( event ), + sm_service_state_str( service->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown state (%s) for service (%s).", + sm_service_state_str( service->state ), + service_name ); + break; + } + + if(( prev_state != service->state )||( prev_status != service->status )|| + ( prev_condition != service->condition )) + { + DPRINTFI( "Service (%s) received event (%s) was in the %s%s%s state " + "and is now in the %s%s%s state%s%s.", + service_name, + sm_service_event_str( event ), + sm_service_state_str( prev_state ), + SM_SERVICE_STATUS_NONE == prev_status + ? "" : "-", + SM_SERVICE_STATUS_NONE == prev_status + ? "" : sm_service_status_str( prev_status ), + sm_service_state_str( service->state ), + SM_SERVICE_STATUS_NONE == service->status + ? "" : "-", + SM_SERVICE_STATUS_NONE == service->status + ? "" : sm_service_status_str( service->status ), + SM_SERVICE_CONDITION_NONE == service->condition + ? "" : ", condition=", + SM_SERVICE_CONDITION_NONE == service->condition + ? "" : sm_service_condition_str( service->condition ) ); + + error = sm_service_table_persist( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service (%s) data, error=%s.", + service->name, sm_error_str(error) ); + return( error ); + } + + if(( prev_state != service->state )||( prev_status != service->status )) + { + sm_log_service_state_change( service_name, + sm_service_state_str( prev_state ), + sm_service_status_str( prev_status ), + sm_service_state_str( service->state ), + sm_service_status_str( service->status ), + reason_text ); + } + + sm_service_fsm_notify( service ); + + if( prev_state != service->state ) + { + error = sm_service_engine_signal( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service (%s), error=%s.", + service_name, sm_error_str( error ) ); + return( error ); + } + } + } else if( SM_SERVICE_EVENT_AUDIT == event ) { + if(( SM_SERVICE_STATE_ENABLED_ACTIVE == service->state )|| + ( SM_SERVICE_STATE_ENABLED_STANDBY == service->state )|| + ( SM_SERVICE_STATE_DISABLED == service->state )) + { + sm_service_fsm_notify( service ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Action Complete Handler +// ===================================== +SmErrorT sm_service_fsm_action_complete_handler( char service_name[], + SmServiceActionT action, SmServiceActionResultT action_result, + SmServiceStateT state, SmServiceStatusT status, + SmServiceConditionT condition, const char reason_text[] ) +{ + bool is_action = true; + SmServiceT* service; + SmServiceEventT event = SM_SERVICE_EVENT_UNKNOWN; + void* event_data[SM_SERVICE_EVENT_DATA_MAX] = {0}; + char event_reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + service = sm_service_table_read( service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service (%s), error=%s.", + service_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + event_data[SM_SERVICE_EVENT_DATA_IS_ACTION] = &is_action; + event_data[SM_SERVICE_EVENT_DATA_STATE] = &state; + event_data[SM_SERVICE_EVENT_DATA_STATUS] = &status; + event_data[SM_SERVICE_EVENT_DATA_CONDITION] = &condition; + + switch( action ) + { + case SM_SERVICE_ACTION_ENABLE: + switch( action_result ) + { + case SM_SERVICE_ACTION_RESULT_SUCCESS: + event = SM_SERVICE_EVENT_ENABLE_SUCCESS; + snprintf( event_reason_text, sizeof(event_reason_text), + "enable success" ); + break; + + case SM_SERVICE_ACTION_RESULT_FATAL: + event = SM_SERVICE_EVENT_SHUTDOWN; + snprintf( event_reason_text, sizeof(event_reason_text), + "enable fatal, shutting down" ); + break; + + case SM_SERVICE_ACTION_RESULT_FAILED: + event = SM_SERVICE_EVENT_ENABLE_FAILED; + snprintf( event_reason_text, sizeof(event_reason_text), + "enable failed" ); + break; + + case SM_SERVICE_ACTION_RESULT_TIMEOUT: + event = SM_SERVICE_EVENT_ENABLE_TIMEOUT; + snprintf( event_reason_text, sizeof(event_reason_text), + "enable timeout" ); + break; + + default: + DPRINTFE( "Unknown action result (%s) for action (%s) of " + "service (%s).", + sm_service_action_result_str( action_result ), + sm_service_action_str( action ), service_name ); + break; + } + break; + + case SM_SERVICE_ACTION_GO_ACTIVE: + switch( action_result ) + { + case SM_SERVICE_ACTION_RESULT_SUCCESS: + event = SM_SERVICE_EVENT_GO_ACTIVE_SUCCESS; + snprintf( event_reason_text, sizeof(event_reason_text), + "go-active success" ); + break; + + case SM_SERVICE_ACTION_RESULT_FATAL: + event = SM_SERVICE_EVENT_SHUTDOWN; + snprintf( event_reason_text, sizeof(event_reason_text), + "go-active fatal, shutting down" ); + break; + + case SM_SERVICE_ACTION_RESULT_FAILED: + event = SM_SERVICE_EVENT_GO_ACTIVE_FAILED; + snprintf( event_reason_text, sizeof(event_reason_text), + "go-active failed" ); + break; + + case SM_SERVICE_ACTION_RESULT_TIMEOUT: + event = SM_SERVICE_EVENT_GO_ACTIVE_TIMEOUT; + snprintf( event_reason_text, sizeof(event_reason_text), + "go-active timeout" ); + break; + + default: + DPRINTFE( "Unknown action result (%s) for action (%s) of " + "service (%s).", + sm_service_action_result_str( action_result ), + sm_service_action_str( action ), service_name ); + break; + } + break; + + case SM_SERVICE_ACTION_GO_STANDBY: + switch( action_result ) + { + case SM_SERVICE_ACTION_RESULT_SUCCESS: + event = SM_SERVICE_EVENT_GO_STANDBY_SUCCESS; + snprintf( event_reason_text, sizeof(event_reason_text), + "go-standby success" ); + break; + + case SM_SERVICE_ACTION_RESULT_FATAL: + event = SM_SERVICE_EVENT_SHUTDOWN; + snprintf( event_reason_text, sizeof(event_reason_text), + "go-standy fatal, shutting down" ); + break; + + case SM_SERVICE_ACTION_RESULT_FAILED: + event = SM_SERVICE_EVENT_GO_STANDBY_FAILED; + snprintf( event_reason_text, sizeof(event_reason_text), + "go-standby failed" ); + break; + + case SM_SERVICE_ACTION_RESULT_TIMEOUT: + event = SM_SERVICE_EVENT_GO_STANDBY_TIMEOUT; + snprintf( event_reason_text, sizeof(event_reason_text), + "go-standby timeout" ); + break; + + default: + DPRINTFE( "Unknown action result (%s) for action (%s) of " + "service (%s).", + sm_service_action_result_str( action_result ), + sm_service_action_str( action ), service_name ); + break; + } + break; + + case SM_SERVICE_ACTION_DISABLE: + switch( action_result ) + { + case SM_SERVICE_ACTION_RESULT_SUCCESS: + event = SM_SERVICE_EVENT_DISABLE_SUCCESS; + snprintf( event_reason_text, sizeof(event_reason_text), + "disable success" ); + break; + + case SM_SERVICE_ACTION_RESULT_FATAL: + event = SM_SERVICE_EVENT_SHUTDOWN; + snprintf( event_reason_text, sizeof(event_reason_text), + "disable fatal, shutting down" ); + break; + + case SM_SERVICE_ACTION_RESULT_FAILED: + event = SM_SERVICE_EVENT_DISABLE_FAILED; + snprintf( event_reason_text, sizeof(event_reason_text), + "disable failed" ); + break; + + case SM_SERVICE_ACTION_RESULT_TIMEOUT: + event = SM_SERVICE_EVENT_DISABLE_TIMEOUT; + snprintf( event_reason_text, sizeof(event_reason_text), + "disable timeout" ); + break; + + default: + DPRINTFE( "Unknown action result (%s) for action (%s) of " + "service (%s).", + sm_service_action_result_str( action_result ), + sm_service_action_str( action ), service_name ); + break; + } + break; + + case SM_SERVICE_ACTION_AUDIT_ENABLED: + case SM_SERVICE_ACTION_AUDIT_DISABLED: + switch( action_result ) + { + case SM_SERVICE_ACTION_RESULT_SUCCESS: + switch( service->state ) + { + case SM_SERVICE_STATE_INITIAL: + case SM_SERVICE_STATE_UNKNOWN: + event = SM_SERVICE_EVENT_AUDIT_SUCCESS; + snprintf( event_reason_text, + sizeof(event_reason_text), + "audit success" ); + break; + + case SM_SERVICE_STATE_ENABLED_GO_STANDBY: + if( SM_SERVICE_STATE_ENABLED_ACTIVE == state ) + { + event = SM_SERVICE_EVENT_AUDIT_SUCCESS; + snprintf( event_reason_text, + sizeof(event_reason_text), + "audit success" ); + } else { + event = SM_SERVICE_EVENT_AUDIT_MISMATCH; + snprintf( event_reason_text, + sizeof(event_reason_text), + "audit state mismatch" ); + } + break; + + default: + if( state == service->state ) + { + event = SM_SERVICE_EVENT_AUDIT_SUCCESS; + snprintf( event_reason_text, + sizeof(event_reason_text), + "audit success" ); + } else { + event = SM_SERVICE_EVENT_AUDIT_MISMATCH; + snprintf( event_reason_text, + sizeof(event_reason_text), + "audit state mismatch" ); + } + break; + } + break; + + case SM_SERVICE_ACTION_RESULT_FATAL: + event = SM_SERVICE_EVENT_SHUTDOWN; + snprintf( event_reason_text, sizeof(event_reason_text), + "audit fatal, shutting down" ); + break; + + case SM_SERVICE_ACTION_RESULT_FAILED: + event = SM_SERVICE_EVENT_AUDIT_FAILED; + snprintf( event_reason_text, sizeof(event_reason_text), + "audit failed" ); + break; + + case SM_SERVICE_ACTION_RESULT_TIMEOUT: + event = SM_SERVICE_EVENT_AUDIT_TIMEOUT; + snprintf( event_reason_text, sizeof(event_reason_text), + "audit timeout" ); + break; + + default: + DPRINTFE( "Unknown action result (%s) for action (%s) of " + "service (%s).", + sm_service_action_result_str( action_result ), + sm_service_action_str( action ), service_name ); + break; + } + break; + + default: + DPRINTFE( "Unknown action (%s) for service (%s).", + sm_service_action_str( action ), service_name ); + break; + } + + if( SM_SERVICE_EVENT_UNKNOWN != event ) + { + error = sm_service_fsm_event_handler( service_name, event, + event_data, event_reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service_name ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Heartbeat Okay Callback +// ======================================== +static void sm_service_fsm_heartbeat_okay_callback( char service_name[] ) +{ + SmServiceEventT event = SM_SERVICE_EVENT_HEARTBEAT_OKAY; + SmErrorT error; + + DPRINTFI( "Service (%s) heartbeat okay.", service_name ); + + error = sm_service_fsm_event_handler( service_name, event, NULL, + "heartbeat okay" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service_name ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Heartbeat Warning Callback +// ======================================== +static void sm_service_fsm_heartbeat_warn_callback( char service_name[] ) +{ + SmServiceEventT event = SM_SERVICE_EVENT_HEARTBEAT_WARN; + SmErrorT error; + + DPRINTFI( "Service (%s) heartbeat warning.", service_name ); + + error = sm_service_fsm_event_handler( service_name, event, NULL, + "heartbeat warning threshold crossed" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service_name ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Heartbeat Degrade Callback +// ======================================== +static void sm_service_fsm_heartbeat_degrade_callback( char service_name[] ) +{ + SmServiceEventT event = SM_SERVICE_EVENT_HEARTBEAT_DEGRADE; + SmErrorT error; + + DPRINTFI( "Service (%s) heartbeat degrade.", service_name ); + + error = sm_service_fsm_event_handler( service_name, event, NULL, + "heartbeat degrade threshold crossed" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service_name ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Heartbeat Failure Callback +// ======================================== +static void sm_service_fsm_heartbeat_fail_callback( char service_name[] ) +{ + SmServiceEventT event = SM_SERVICE_EVENT_HEARTBEAT_FAIL; + SmErrorT error; + + DPRINTFI( "Service (%s) heartbeat failure.", service_name ); + + error = sm_service_fsm_event_handler( service_name, event, NULL, + "heartbeat failure" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service_name ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Process Failure Callback +// ====================================== +static void sm_service_fsm_process_failure_callback( pid_t pid, int exit_code, + int64_t user_data ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceT* service; + SmServiceEventT event = SM_SERVICE_EVENT_PROCESS_FAILURE; + SmErrorT error; + + service = sm_service_table_read_by_pid( (int) pid ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service based on pid (%"PRIu64"), error=%s.", + user_data, sm_error_str(SM_NOT_FOUND) ); + return; + } + + DPRINTFI( "Service (%s) process failure, pid=%i, exit_code=%i.", + service->name, (int) pid, exit_code ); + + sm_service_get_terminate_reason(service, reason_text, sizeof(reason_text)); + + error = sm_service_fsm_event_handler( service->name, event, NULL, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service->name ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Process Audit PID File Timer +// ========================================== +static bool sm_service_fsm_process_audit_pid_file_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + goto EXIT; + } + + service->pid_file_audit_timer_id = SM_TIMER_ID_INVALID; + + error = sm_service_fsm_process_failure_register( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for process failure for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + goto EXIT; + } + +EXIT: + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Process Failure Register +// ====================================== +SmErrorT sm_service_fsm_process_failure_register( SmServiceT* service ) +{ + int pid; + FILE* pid_file; + bool audit_pid_file = false; + char file_line[80] = "\0"; + SmErrorT error; + + if( '\0' != service->pid_file[0] ) + { + pid_file = fopen ( service->pid_file, "r" ); + + if( NULL == pid_file ) + { + DPRINTFE( "Failed to open pid file (%s) for service (%s).", + service->pid_file, service->name ); + audit_pid_file = true; + goto EXIT; + } + + if( NULL == fgets( file_line, sizeof(file_line), pid_file ) ) + { + DPRINTFE( "Failed to read pid from pid file (%s) for " + "service (%s).", service->pid_file, service->name ); + fclose( pid_file ); + + remove_pid_file(service->pid_file); + audit_pid_file = true; + goto EXIT; + } + + fclose( pid_file ); + + if( 1 != sscanf( file_line, "%d", &pid ) ) + { + DPRINTFE( "pid file (%s) for (%s) is invalid. content (%s).", + service->pid_file, service->name, file_line ); + + remove_pid_file( service->pid_file ); + audit_pid_file = true; + goto EXIT; + } + + if( 0 > pid ) + { + DPRINTFE( "Invalid pid (%i) converted from line (%s) from file " + "(%s) for service (%s).", pid, file_line, + service->pid_file, service->name ); + audit_pid_file = true; + goto EXIT; + } + + if ( 0 != kill(pid, 0) ) + { + DPRINTFE( "pid (%i) from file (%s) for service (%s)" + " is no longer valid.", pid, + service->pid_file, service->name ); + remove_pid_file( service->pid_file ); + service->pid = -1; + + if( !sm_process_death_already_registered( pid, + sm_service_fsm_process_failure_callback ) ) + { + sm_service_fsm_process_failure_deregister(service); + } + + service->disable_check_dependency = false; + service->disable_skip_dependent = true; + SmServiceEventT event = SM_SERVICE_EVENT_DISABLE; + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR]; + snprintf(reason_text, sizeof(reason_text), + "Service (%s) process failure, pid=%i, exit_code unknown", + service->name, + (int)pid); + + error = sm_service_fsm_event_handler( service->name, event, NULL, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service (%s).", + sm_service_event_str( event ), service->name ); + } + goto EXIT; + } + + service->pid = pid; + + if( sm_process_death_already_registered( pid, + sm_service_fsm_process_failure_callback ) ) + { + DPRINTFD( "Already registered for process failure callback " + "for service (%s), pid=%i.", service->name, pid ); + goto EXIT; + } + + error = sm_process_death_register( pid, false, + sm_service_fsm_process_failure_callback, + service->id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for process failure callback " + "for service (%s), pid=%i, error=%s.", service->name, + pid, sm_error_str( error ) ); + goto EXIT; + } + } + +EXIT: + if( audit_pid_file ) + { + // Some services do not write their pid file right away when they + // enable, so register an audit to attempt to register the pid again. + char timer_name[80] = ""; + SmTimerIdT audit_timer_id; + + if( SM_TIMER_ID_INVALID != service->pid_file_audit_timer_id ) + { + error = sm_timer_deregister( service->pid_file_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel pid file audit timer, error=%s.", + sm_error_str( error ) ); + } + + service->pid_file_audit_timer_id = SM_TIMER_ID_INVALID; + } + + snprintf( timer_name, sizeof(timer_name), "%s audit pid file", + service->name ); + + error = sm_timer_register( timer_name, + SM_SERVICE_FSM_PID_FILE_AUDIT_IN_MS, + sm_service_fsm_process_audit_pid_file_timer, + service->id, &audit_timer_id ); + if( SM_OKAY == error ) + { + service->pid_file_audit_timer_id = audit_timer_id; + + } else { + DPRINTFE( "Failed to create pid file audit timer for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Process Failure Deregister +// ======================================== +SmErrorT sm_service_fsm_process_failure_deregister( SmServiceT* service ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != service->pid_file_audit_timer_id ) + { + error = sm_timer_deregister( service->pid_file_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel pid file audit timer, error=%s.", + sm_error_str( error ) ); + } + + service->pid_file_audit_timer_id = SM_TIMER_ID_INVALID; + } + + if( 0 <= service->pid ) + { + error = sm_process_death_deregister( service->pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for process failure callback " + "for service (%s), pid=%i, error=%s.", service->name, + service->pid, sm_error_str( error ) ); + } + + service->pid = -1; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Initialize +// ======================== +SmErrorT sm_service_fsm_initialize( void ) +{ + SmErrorT error; + + memset( &_hb_callbacks, 0, sizeof(_hb_callbacks) ); + + error = sm_service_initial_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service initial state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_unknown_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service unknown state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_enabled_active_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service enabled active state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_enabled_go_active_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service enabled go-active state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_enabled_go_standby_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service enabled go-standby state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_enabled_standby_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service enabled standby state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_enabling_throttle_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service enabling throttle state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_enabling_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service enabling state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_disabling_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service disabling state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_disabled_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service disabled state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_shutdown_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service shutdown state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_enable_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service enable module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_go_active_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service go-active module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_go_standby_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service go-standby module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_disable_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service disable module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_audit_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service audit module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + _hb_callbacks.okay_callback = sm_service_fsm_heartbeat_okay_callback; + _hb_callbacks.warn_callback = sm_service_fsm_heartbeat_warn_callback; + _hb_callbacks.degrade_callback = sm_service_fsm_heartbeat_degrade_callback; + _hb_callbacks.fail_callback = sm_service_fsm_heartbeat_fail_callback; + + error = sm_service_heartbeat_api_register_callbacks( &_hb_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register service heartbeat callbacks, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Finalize +// ====================== +SmErrorT sm_service_fsm_finalize( void ) +{ + SmErrorT error; + + error = sm_service_heartbeat_api_deregister_callbacks( &_hb_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister service heartbeat callbacks, " + "error=%s.", sm_error_str( error ) ); + } + + memset( &_hb_callbacks, 0, sizeof(_hb_callbacks) ); + + error = sm_service_initial_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service initial state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_unknown_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service unknown state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_enabled_active_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service enabled active state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_enabled_go_active_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service enabled go-active state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_enabled_go_standby_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service enabled go-standby state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_enabled_standby_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service enabled standby state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_enabling_throttle_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service enabling throttle state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_enabling_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service enabling state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_disabling_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service disabling state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_disabled_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service disabled state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_shutdown_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service shutdown state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_enable_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service enable module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_go_active_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service go-active module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_go_standby_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service go-standby module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_disable_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service disable module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_audit_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service audit module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service FSM - get service terminate reason +// ======================================== +static SmErrorT sm_service_get_terminate_reason(SmServiceT* service, + char reason_text[], int len) +{ + switch( service->state ) + { + case SM_SERVICE_STATE_DISABLING: + case SM_SERVICE_STATE_DISABLED: + case SM_SERVICE_STATE_SHUTDOWN: + snprintf( reason_text, len, "process (pid=%i) terminated", + (int) service->pid ); + break; + default: + snprintf( reason_text, len, "process (pid=%i) failed", + (int) service->pid ); + break; + } + + return SM_OKAY; +} +// **************************************************************************** + + +// **************************************************************************** +// util function for deleting an invalid pid file +// ======================================== +static bool remove_pid_file(char pid_file[]) +{ + if ( 0 == remove( pid_file ) ) + { + DPRINTFI( "pid file (%s) is deleted. ", pid_file ); + return true; + }else + { + DPRINTFE( "Failed to delete pid file (%s). ", pid_file ); + return false; + } +} +// **************************************************************************** \ No newline at end of file diff --git a/service-mgmt/sm-1.0.0/src/sm_service_fsm.h b/service-mgmt/sm-1.0.0/src/sm_service_fsm.h new file mode 100644 index 00000000..10bcfd5c --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_fsm.h @@ -0,0 +1,104 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_FSM_H__ +#define __SM_SERVICE_FSM_H__ + +#include "sm_types.h" +#include "sm_service_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmServiceFsmCallbackT) (char service_name[], + SmServiceStateT state, SmServiceStatusT status, + SmServiceConditionT condition); + +// **************************************************************************** +// Service FSM - Register Callback +// =============================== +extern SmErrorT sm_service_fsm_register_callback( SmServiceFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Deregister Callback +// ================================= +extern SmErrorT sm_service_fsm_deregister_callback( SmServiceFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Set State +// ======================= +extern SmErrorT sm_service_fsm_set_state( SmServiceT* service, + SmServiceStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Set Status +// ======================== +extern SmErrorT sm_service_fsm_set_status( SmServiceT* service, + SmServiceStatusT status, SmServiceConditionT condition ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Event Handler +// =========================== +extern SmErrorT sm_service_fsm_event_handler( char service_name[], + SmServiceEventT event, void* event_data[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Action Complete Handler +// ===================================== +extern SmErrorT sm_service_fsm_action_complete_handler( char service_name[], + SmServiceActionT action, SmServiceActionResultT action_result, + SmServiceStateT state, SmServiceStatusT status, + SmServiceConditionT condition, const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Start Fail Countdown Timer +// ======================================== +extern SmErrorT sm_service_fsm_start_fail_countdown_timer( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Stop Fail Countdown Timer +// ======================================= +extern SmErrorT sm_service_fsm_stop_fail_countdown_timer( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Process Failure Register +// ====================================== +extern SmErrorT sm_service_fsm_process_failure_register( + SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Process Failure Deregister +// ======================================= +extern SmErrorT sm_service_fsm_process_failure_deregister( + SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Initialize +// ======================== +extern SmErrorT sm_service_fsm_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service FSM - Finalize +// ====================== +extern SmErrorT sm_service_fsm_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_FSM_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_go_active.c b/service-mgmt/sm-1.0.0/src/sm_service_go_active.c new file mode 100644 index 00000000..0d951660 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_go_active.c @@ -0,0 +1,465 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_go_active.h" + +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_process_death.h" +#include "sm_timer.h" +#include "sm_service_dependency.h" +#include "sm_service_fsm.h" +#include "sm_service_action.h" + +// **************************************************************************** +// Service Go-Active - Result Handler +// ================================== +static SmErrorT service_go_active_result_handler( SmServiceT* service, + SmServiceActionT action_running, SmServiceActionResultT action_result, + SmServiceStateT service_state, SmServiceStatusT service_status, + SmServiceConditionT service_condition, const char reason_text[] ) +{ + bool retries_exhausted = true; + int max_failure_retries; + int max_timeout_retries; + int max_total_retries; + SmErrorT error; + + if( SM_SERVICE_ACTION_RESULT_SUCCESS == action_result ) + { + DPRINTFD( "Action (%s) of service (%s) completed with success.", + sm_service_action_str( action_running ), service->name ); + goto REPORT; + } + + error = sm_service_action_max_retries( service->name, action_running, + &max_failure_retries, + &max_timeout_retries, + &max_total_retries ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get max retries for action (%s) of service (%s), " + "error=%s.", sm_service_action_str( action_running ), + service->name, sm_error_str( error ) ); + goto REPORT; + } + + if( SM_SERVICE_ACTION_RESULT_FAILED == action_result ) + { + retries_exhausted = + (( max_failure_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + + } else if( SM_SERVICE_ACTION_RESULT_TIMEOUT == action_result ) { + retries_exhausted = + (( max_timeout_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + } + + if( retries_exhausted ) + { + DPRINTFI( "Max retires met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + goto REPORT; + } else { + DPRINTFI( "Max retires not met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + + error = sm_service_go_active( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-active on service (%s), error=%s.", + service->name, sm_error_str( error ) ); + goto REPORT; + } + } + + return( SM_OKAY ); + +REPORT: + service->action_attempts = 0; + + error = sm_service_fsm_action_complete_handler( service->name, + action_running, action_result, service_state, + service_status, service_condition, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service (%s) fsm action complete, " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Timeout +// =========================== +static bool sm_service_go_active_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( false ); + } + + if( SM_SERVICE_ACTION_GO_ACTIVE != service->action_running ) + { + DPRINTFE( "Service (%s) not running action (%s).", service->name, + sm_service_action_str( service->action_running ) ); + return( false ); + } + + action_running = service->action_running; + + error = sm_service_action_result( SM_SERVICE_ACTION_PLUGIN_TIMEOUT, + service->name, service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) defaulting " + "to failed, exit_code=%i, error=%s.", service->name, + SM_SERVICE_ACTION_PLUGIN_TIMEOUT, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + + DPRINTFI( "Action (%s) timeout with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, SM_SERVICE_ACTION_PLUGIN_TIMEOUT ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_go_active_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle go-active result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Complete +// ============================ +static void sm_service_go_active_complete( pid_t pid, int exit_code, + int64_t user_data ) +{ + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + if( SM_PROCESS_FAILED == exit_code ) + { + exit_code = SM_SERVICE_ACTION_PLUGIN_FAILURE; + } + + service = sm_service_table_read_by_action_pid( (int) pid ); + if( NULL == service ) + { + DPRINTFE( "Failed to query service based on pid (%i), error=%s.", + (int) pid, sm_error_str(SM_NOT_FOUND) ); + return; + } + + if( SM_SERVICE_ACTION_GO_ACTIVE != service->action_running ) + { + DPRINTFE( "Service (%s) not running go-active action.", + service->name ); + return; + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY == error ) + { + DPRINTFD( "Timer stopped for action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + } else { + DPRINTFE( "Failed to stop timer for action (%s) of " + "service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + } + + action_running = service->action_running; + + if( SM_SERVICE_ACTION_PLUGIN_FORCE_SUCCESS == exit_code ) + { + DPRINTFI( "Action (%s) for service (%s) is force-passed.", + sm_service_action_str( action_running ), service->name ); + + action_result = SM_SERVICE_ACTION_RESULT_SUCCESS; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + + } else { + error = sm_service_action_result( exit_code, service->name, + service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) " + "defaulting to failed, exit_code=%i, error=%s.", + service->name, exit_code, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + } + + DPRINTFI( "Action (%s) completed with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, exit_code ); + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_go_active_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle go-active result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active +// ================= +SmErrorT sm_service_go_active( SmServiceT* service ) +{ + char timer_name[80] = ""; + int process_id = -1; + int timeout = 0; + bool dependency_met; + SmTimerIdT timer_id = SM_TIMER_ID_INVALID; + SmErrorT error; + + // Are go-active dependencies met? + error = sm_service_dependency_go_active_met( service, &dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check service (%s) dependencies, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + if( !dependency_met ) + { + DPRINTFD( "Some dependencies for service (%s) were not met.", + service->name ); + return( SM_OKAY ); + } + + DPRINTFD( "All dependencies for service (%s) were met.", service->name ); + + // Run action. + error = sm_service_action_run( service->name, + service->instance_name, + service->instance_params, + SM_SERVICE_ACTION_GO_ACTIVE, + &process_id, &timeout ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to run go-active action for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + // Register for action script exit notification. + error = sm_process_death_register( process_id, true, + sm_service_go_active_complete, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for go-active action completion for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + abort(); + } + + // Create timer for action completion. + snprintf( timer_name, sizeof(timer_name), "%s %s action", + service->name, sm_service_action_str( SM_SERVICE_ACTION_GO_ACTIVE ) ); + + error = sm_timer_register( timer_name, timeout, sm_service_go_active_timeout, + service->id, &timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create a timer for action (%s) for service (%s), " + "error=%s.", sm_service_action_str( SM_SERVICE_ACTION_GO_ACTIVE ), + service->name, sm_error_str( error ) ); + abort(); + } + + // Write to database that we are running an action. + service->action_running = SM_SERVICE_ACTION_GO_ACTIVE; + service->action_pid = process_id; + service->action_timer_id = timer_id; + service->action_attempts += 1; + + DPRINTFI( "Started go-active action (%i) for service (%s).", process_id, + service->name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Abort +// ========================= +SmErrorT sm_service_go_active_abort( SmServiceT* service ) +{ + SmErrorT error; + + DPRINTFI( "Aborting action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Cancel timer for action (%s) of service (%s) failed, " + "error=%s.", service->name, + sm_service_action_str( service->action_running ), + sm_error_str( error ) ); + return( error ); + } + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + service->action_attempts = 0; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Exists +// ========================== +SmErrorT sm_service_go_active_exists( SmServiceT* service, bool* exists ) +{ + SmErrorT error; + + error = sm_service_action_exist( service->name, SM_SERVICE_ACTION_GO_ACTIVE ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to determine if action (%s) exists for service (%s), " + "error=%s.", sm_service_action_str( SM_SERVICE_ACTION_GO_ACTIVE ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_OKAY == error ) + { + *exists = true; + } else { + *exists = false; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Initialize +// ============================== +SmErrorT sm_service_go_active_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Finalize +// ============================ +SmErrorT sm_service_go_active_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_go_active.h b/service-mgmt/sm-1.0.0/src/sm_service_go_active.h new file mode 100644 index 00000000..f836bee7 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_go_active.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GO_ACTIVE_H__ +#define __SM_SERVICE_GO_ACTIVE_H__ + +#include + +#include "sm_types.h" +#include "sm_service_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Go-Active +// ================= +extern SmErrorT sm_service_go_active( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Abort +// ========================= +extern SmErrorT sm_service_go_active_abort( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Exists +// ========================== +extern SmErrorT sm_service_go_active_exists( SmServiceT* service, bool* exists ); +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Initialize +// ============================== +extern SmErrorT sm_service_go_active_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Go-Active - Finalize +// ============================ +extern SmErrorT sm_service_go_active_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GO_ACTIVE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_go_standby.c b/service-mgmt/sm-1.0.0/src/sm_service_go_standby.c new file mode 100644 index 00000000..3bdaa237 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_go_standby.c @@ -0,0 +1,463 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_go_standby.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_process_death.h" +#include "sm_service_dependency.h" +#include "sm_service_fsm.h" +#include "sm_service_action.h" + +// **************************************************************************** +// Service Go-Standby - Result Handler +// =================================== +static SmErrorT service_go_standby_result_handler( SmServiceT* service, + SmServiceActionT action_running, SmServiceActionResultT action_result, + SmServiceStateT service_state, SmServiceStatusT service_status, + SmServiceConditionT service_condition, const char reason_text[] ) +{ + bool retries_exhausted = true; + int max_failure_retries; + int max_timeout_retries; + int max_total_retries; + SmErrorT error; + + if( SM_SERVICE_ACTION_RESULT_SUCCESS == action_result ) + { + DPRINTFD( "Action (%s) of service (%s) completed with success.", + sm_service_action_str( action_running ), service->name ); + goto REPORT; + } + + error = sm_service_action_max_retries( service->name, action_running, + &max_failure_retries, + &max_timeout_retries, + &max_total_retries ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get max retries for action (%s) of service (%s), " + "error=%s.", sm_service_action_str( action_running ), + service->name, sm_error_str( error ) ); + goto REPORT; + } + + if( SM_SERVICE_ACTION_RESULT_FAILED == action_result ) + { + retries_exhausted = + (( max_failure_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + + } else if( SM_SERVICE_ACTION_RESULT_TIMEOUT == action_result ) { + retries_exhausted = + (( max_timeout_retries <= service->action_attempts )|| + ( max_total_retries <= service->action_attempts )); + } + + if( retries_exhausted ) + { + DPRINTFI( "Max retires met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + goto REPORT; + } else { + DPRINTFI( "Max retires not met for action (%s) of service (%s), " + "attempts=%i.", sm_service_action_str( action_running ), + service->name, service->action_attempts ); + + error = sm_service_go_standby( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-standby service (%s), error=%s.", + service->name, sm_error_str( error ) ); + goto REPORT; + } + } + + return( SM_OKAY ); + +REPORT: + service->action_attempts = 0; + + error = sm_service_fsm_action_complete_handler( service->name, + action_running, action_result, service_state, + service_status, service_condition, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service (%s) fsm action complete, " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Timeout +// ============================ +static bool sm_service_go_standby_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + service = sm_service_table_read_by_id( id ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( false ); + } + + if( SM_SERVICE_ACTION_GO_STANDBY != service->action_running ) + { + DPRINTFE( "Service (%s) not running action (%s).", service->name, + sm_service_action_str( service->action_running ) ); + return( false ); + } + + action_running = service->action_running; + + error = sm_service_action_result( SM_SERVICE_ACTION_PLUGIN_TIMEOUT, + service->name, service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) defaulting " + "to failed, exit_code=%i, error=%s.", service->name, + SM_SERVICE_ACTION_PLUGIN_TIMEOUT, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + + DPRINTFI( "Action (%s) timeout with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, SM_SERVICE_ACTION_PLUGIN_TIMEOUT ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_go_standby_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle go-standby result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } + + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Complete +// ============================= +static void sm_service_go_standby_complete( pid_t pid, int exit_code, + int64_t user_data ) +{ + SmServiceT* service; + SmServiceActionT action_running; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + char reason_text[SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + if( SM_PROCESS_FAILED == exit_code ) + { + exit_code = SM_SERVICE_ACTION_PLUGIN_FAILURE; + } + + service = sm_service_table_read_by_action_pid( (int) pid ); + if( NULL == service ) + { + DPRINTFE( "Failed to query service based on pid (%i), error=%s.", + (int) pid, sm_error_str(SM_NOT_FOUND) ); + return; + } + + if( SM_SERVICE_ACTION_GO_STANDBY != service->action_running ) + { + DPRINTFE( "Service (%s) not running go-standby action.", + service->name ); + return; + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY == error ) + { + DPRINTFD( "Timer stopped for action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + } else { + DPRINTFE( "Failed to stop timer for action (%s) of " + "service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + } + } + + action_running = service->action_running; + + if( SM_SERVICE_ACTION_PLUGIN_FORCE_SUCCESS == exit_code ) + { + DPRINTFI( "Action (%s) for service (%s) force-passed.", + sm_service_action_str( action_running ), service->name ); + + action_result = SM_SERVICE_ACTION_RESULT_SUCCESS; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + + } else { + error = sm_service_action_result( exit_code, service->name, + service->action_running, + &action_result, &service_state, + &service_status, &service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get action result for service (%s) " + "defaulting to failed, exit_code=%i, error=%s.", + service->name, exit_code, sm_error_str( error ) ); + action_result = SM_SERVICE_ACTION_RESULT_FAILED; + service_state = SM_SERVICE_STATE_UNKNOWN; + service_status = SM_SERVICE_STATUS_UNKNOWN; + service_condition = SM_SERVICE_CONDITION_UNKNOWN; + } + } + + DPRINTFI( "Action (%s) completed with result (%s), state (%s), " + "status (%s), and condition (%s) for service (%s), " + "reason_text=%s, exit_code=%i.", + sm_service_action_str( action_running ), + sm_service_action_result_str( action_result ), + sm_service_state_str( service_state ), + sm_service_status_str( service_status ), + sm_service_condition_str( service_condition ), + service->name, reason_text, exit_code ); + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + + error = service_go_standby_result_handler( service, action_running, + action_result, service_state, + service_status, service_condition, + reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to handle go-standby result for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby +// ================== +SmErrorT sm_service_go_standby( SmServiceT* service ) +{ + char timer_name[80] = ""; + int process_id = -1; + int timeout = 0; + bool dependency_met; + SmTimerIdT timer_id = SM_TIMER_ID_INVALID; + SmErrorT error; + + // Are go-standby dependencies met? + error = sm_service_dependency_go_standby_met( service, &dependency_met ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check service (%s) dependencies, error=%s.", + service->name, sm_error_str( error ) ); + return( error ); + } + + if( !dependency_met ) + { + DPRINTFD( "Some dependencies for service (%s) were not met.", + service->name ); + return( SM_OKAY ); + } + + DPRINTFD( "All dependencies for service (%s) were met.", service->name ); + + // Run action. + error = sm_service_action_run( service->name, + service->instance_name, + service->instance_params, + SM_SERVICE_ACTION_GO_STANDBY, + &process_id, &timeout ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to run go-standby action for service (%s), " + "error=%s.", service->name, sm_error_str( error ) ); + return( error ); + } + + // Register for action script exit notification. + error = sm_process_death_register( process_id, true, + sm_service_go_standby_complete, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for go-standby action completion for " + "service (%s), error=%s.", service->name, + sm_error_str( error ) ); + abort(); + } + + // Create timer for action completion. + snprintf( timer_name, sizeof(timer_name), "%s %s action", + service->name, sm_service_action_str( SM_SERVICE_ACTION_GO_STANDBY ) ); + + error = sm_timer_register( timer_name, timeout, sm_service_go_standby_timeout, + service->id, &timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create a timer for action (%s) for service (%s), " + "error=%s.", sm_service_action_str( SM_SERVICE_ACTION_GO_STANDBY ), + service->name, sm_error_str( error ) ); + abort(); + } + + // Write to database that we are running an action. + service->action_running = SM_SERVICE_ACTION_GO_STANDBY; + service->action_pid = process_id; + service->action_timer_id = timer_id; + service->action_attempts += 1; + + DPRINTFI( "Started go-standby action (%i) for service (%s).", process_id, + service->name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Abort +// ========================== +SmErrorT sm_service_go_standby_abort( SmServiceT* service ) +{ + SmErrorT error; + + DPRINTFI( "Aborting action (%s) of service (%s).", + sm_service_action_str( service->action_running ), + service->name ); + + error = sm_service_action_abort( service->name, service->action_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_TIMER_ID_INVALID != service->action_timer_id ) + { + error = sm_timer_deregister( service->action_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Cancel timer for action (%s) of service (%s) failed, " + "error=%s.", service->name, + sm_service_action_str( service->action_running ), + sm_error_str( error ) ); + return( error ); + } + } + + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + service->action_attempts = 0; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Exists +// =========================== +SmErrorT sm_service_go_standby_exists( SmServiceT* service, bool* exists ) +{ + SmErrorT error; + + error = sm_service_action_exist( service->name, SM_SERVICE_ACTION_GO_STANDBY ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to determine if action (%s) exists for service (%s), " + "error=%s.", sm_service_action_str( SM_SERVICE_ACTION_GO_STANDBY ), + service->name, sm_error_str( error ) ); + return( error ); + } + + if( SM_OKAY == error ) + { + *exists = true; + } else { + *exists = false; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Initialize +// =============================== +SmErrorT sm_service_go_standby_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Finalize +// ============================= +SmErrorT sm_service_go_standby_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_go_standby.h b/service-mgmt/sm-1.0.0/src/sm_service_go_standby.h new file mode 100644 index 00000000..12a41f3a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_go_standby.h @@ -0,0 +1,52 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GO_STANDBY_H__ +#define __SM_SERVICE_GO_STANDBY_H__ + +#include + +#include "sm_types.h" +#include "sm_service_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Go-Standby +// ================== +extern SmErrorT sm_service_go_standby( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Abort +// ========================== +extern SmErrorT sm_service_go_standby_abort( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Exists +// =========================== +extern SmErrorT sm_service_go_standby_exists( SmServiceT* service, bool* exists ); +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Initialize +// =============================== +extern SmErrorT sm_service_go_standby_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Go-Standby - Finalize +// ============================= +extern SmErrorT sm_service_go_standby_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GO_STANDBY_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_active_state.c b/service-mgmt/sm-1.0.0/src/sm_service_group_active_state.c new file mode 100644 index 00000000..eac13f3a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_active_state.c @@ -0,0 +1,181 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_active_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_service_group_notification.h" +#include "sm_service_group_fsm.h" +#include "sm_service_group_go_active.h" +#include "sm_service_group_go_standby.h" +#include "sm_service_group_audit.h" + +// **************************************************************************** +// Service Group Active State - Entry +// ================================== +SmErrorT sm_service_group_active_state_entry( SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_notify( + service_group, SM_SERVICE_GROUP_NOTIFICATION_ACTIVE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_go_active( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-active on service group (%s), error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Exit +// ================================= +SmErrorT sm_service_group_active_state_exit( SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_abort( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Transition +// ======================================= +SmErrorT sm_service_group_active_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Event Handler +// ========================================== +SmErrorT sm_service_group_active_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ) +{ + char* service_name = NULL; + SmServiceStateT service_state; + SmServiceGroupStateT state; + SmErrorT error; + + error = sm_service_group_fsm_get_next_state( service_group->name, + event, &state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine next state for service group (%s), " + "error=%s", service_group->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_GROUP_EVENT_GO_ACTIVE: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT: + // Ignore. + break; + + case SM_SERVICE_GROUP_EVENT_GO_STANDBY: + case SM_SERVICE_GROUP_EVENT_DISABLE: + error = sm_service_group_fsm_set_state( service_group->name, + state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_SERVICE_SCN: + service_name = (char *) + event_data[SM_SERVICE_GROUP_EVENT_DATA_SERVICE_NAME]; + service_state = *(SmServiceStateT *) + event_data[SM_SERVICE_GROUP_EVENT_DATA_SERVICE_STATE]; + + DPRINTFD( "Service group (%s) service (%s) state (%s) received.", + service_group->name, service_name, + sm_service_state_str( service_state ) ); + + case SM_SERVICE_GROUP_EVENT_AUDIT: + error = sm_service_group_audit_status( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_SHUTDOWN: + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_SHUTDOWN ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service group (%s) ignoring event (%s).", + service_group->name, + sm_service_group_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Initialize +// ======================================= +SmErrorT sm_service_group_active_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Finalize +// ===================================== +SmErrorT sm_service_group_active_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_active_state.h b/service-mgmt/sm-1.0.0/src/sm_service_group_active_state.h new file mode 100644 index 00000000..da6f6bba --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_active_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_ACTIVE_STATE_H__ +#define __SM_SERVICE_GROUP_ACTIVE_STATE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Active State - Entry +// ================================== +extern SmErrorT sm_service_group_active_state_entry( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Exit +// ================================= +extern SmErrorT sm_service_group_active_state_exit( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Transition +// ======================================= +extern SmErrorT sm_service_group_active_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Event Handler +// ========================================== +extern SmErrorT sm_service_group_active_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Initialize +// ======================================= +extern SmErrorT sm_service_group_active_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Active State - Finalize +// ===================================== +extern SmErrorT sm_service_group_active_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_ACTIVE_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_api.c b/service-mgmt/sm-1.0.0/src/sm_service_group_api.c new file mode 100644 index 00000000..97965a3a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_api.c @@ -0,0 +1,331 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_api.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_node_api.h" +#include "sm_service_group_table.h" +#include "sm_service_group_member_table.h" +#include "sm_service_group_engine.h" +#include "sm_service_group_fsm.h" + +static SmListT* _callbacks = NULL; + +// **************************************************************************** +// Service Group API - Register Callback +// ===================================== +SmErrorT sm_service_group_api_register_callback( + SmServiceGroupApiCallbackT callback ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Deregister Callback +// ======================================= +SmErrorT sm_service_group_api_deregister_callback( + SmServiceGroupApiCallbackT callback ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Service Group Callback +// ========================================== +static void sm_service_group_api_service_group_callback( + char service_group_name[], SmServiceGroupStateT state, + SmServiceGroupStatusT status, SmServiceGroupConditionT condition, + int64_t health, const char reason_text[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupApiCallbackT callback; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callback = (SmServiceGroupApiCallbackT) entry_data; + + callback( service_group_name, state, status, condition, health, + reason_text ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Go-Active +// ============================= +SmErrorT sm_service_group_api_go_active( char service_group_name[] ) +{ + SmServiceGroupT* service_group; + SmErrorT error; + + service_group = sm_service_group_table_read( service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + service_group_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if( SM_SERVICE_GROUP_STATE_ACTIVE != service_group->desired_state ) + { + service_group->desired_state = SM_SERVICE_GROUP_STATE_ACTIVE; + + error = sm_service_group_table_persist( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service group (%s) data, error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_engine_signal( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Go-Standby +// ============================== +SmErrorT sm_service_group_api_go_standby( char service_group_name[] ) +{ + SmServiceGroupT* service_group; + SmErrorT error; + + service_group = sm_service_group_table_read( service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + service_group_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if( SM_SERVICE_GROUP_STATE_STANDBY != service_group->desired_state ) + { + service_group->desired_state = SM_SERVICE_GROUP_STATE_STANDBY; + + error = sm_service_group_table_persist( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service group (%s) data, error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_engine_signal( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Disable +// =========================== +SmErrorT sm_service_group_api_disable( char service_group_name[] ) +{ + SmServiceGroupT* service_group; + SmErrorT error; + + service_group = sm_service_group_table_read( service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + service_group_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if( SM_SERVICE_GROUP_STATE_DISABLED != service_group->desired_state ) + { + service_group->desired_state = SM_SERVICE_GROUP_STATE_DISABLED; + + error = sm_service_group_table_persist( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service group (%s) data, error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_engine_signal( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Recover +// =========================== +SmErrorT sm_service_group_api_recover( char service_group_name[], + bool escalate_recovery, bool clear_fatal_condition ) +{ + if(( clear_fatal_condition )&&( escalate_recovery )) + { + SmServiceGroupT* service_group; + SmErrorT error; + + service_group = sm_service_group_table_read( service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + service_group_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + if( service_group->fatal_error_reboot ) + { + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + + DPRINTFI( "Service group (%s) recovery from fatal condition " + "escalated to a reboot.", service_group->name ); + + snprintf( reason_text, sizeof(reason_text), "service group (%s) " + "recovery from fatal condition escalated to a reboot.", + service_group->name ); + + error = sm_node_api_reboot( reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to issue reboot to recover service " + "group (%s), error=%s.", service_group->name, + sm_error_str(SM_NOT_FOUND) ); + return( error ); + } + } + } + + return( sm_service_group_fsm_recover( service_group_name, + clear_fatal_condition ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Initialize +// ============================== +SmErrorT sm_service_group_api_initialize( void ) +{ + SmErrorT error; + + error = sm_service_group_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_member_table_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to intialize service group member table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_fsm_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to intialize service group fsm, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_engine_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to intialize service group engine, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_fsm_register_callback( + sm_service_group_api_service_group_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for service group fsm state changes, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Finalize +// ============================ +SmErrorT sm_service_group_api_finalize( void ) +{ + SmErrorT error; + + error = sm_service_group_fsm_deregister_callback( + sm_service_group_api_service_group_callback ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for service group fsm state changes, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_fsm_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group fsm, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_group_engine_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group engine, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_group_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group table, error=%s.", + sm_error_str( error ) ); + } + + error = sm_service_group_member_table_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group member table, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_api.h b/service-mgmt/sm-1.0.0/src/sm_service_group_api.h new file mode 100644 index 00000000..659f25cb --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_api.h @@ -0,0 +1,75 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_API_H__ +#define __SM_SERVICE_GROUP_API_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmServiceGroupApiCallbackT) (char service_group_name[], + SmServiceGroupStateT state, SmServiceGroupStatusT status, + SmServiceGroupConditionT condition, int64_t health, + const char reason_text[]); + +// **************************************************************************** +// Service Group API - Register Callback +// ===================================== +extern SmErrorT sm_service_group_api_register_callback( + SmServiceGroupApiCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Deregister Callback +// ======================================= +extern SmErrorT sm_service_group_api_deregister_callback( + SmServiceGroupApiCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Go-Active +// ============================= +extern SmErrorT sm_service_group_api_go_active( char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Go-Standby +// ============================== +extern SmErrorT sm_service_group_api_go_standby( char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Disable +// =========================== +extern SmErrorT sm_service_group_api_disable( char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Recover +// =========================== +extern SmErrorT sm_service_group_api_recover( char service_group_name[], + bool clear_fatal_condition, bool escalate_recovery ); +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Initialize +// ============================== +extern SmErrorT sm_service_group_api_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group API - Finalize +// ============================ +extern SmErrorT sm_service_group_api_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_API_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_audit.c b/service-mgmt/sm-1.0.0/src/sm_service_group_audit.c new file mode 100644 index 00000000..73d96064 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_audit.c @@ -0,0 +1,498 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_audit.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_service_group_table.h" +#include "sm_service_group_member_table.h" +#include "sm_service_api.h" +#include "sm_service_group_health.h" + +// **************************************************************************** +// Service Group Audit - Set Service Reason Text +// ============================================= +static void sm_service_group_audit_set_service_reason_text( char reason_text[], + char service_name[], SmServiceStateT state, SmServiceStatusT status, + SmServiceConditionT condition ) +{ + bool skip_condition = false; + + if(( SM_SERVICE_CONDITION_NONE == condition )|| + ( SM_SERVICE_CONDITION_RECOVERY_FAILURE == condition )|| + ( SM_SERVICE_CONDITION_ACTION_FAILURE == condition )|| + ( SM_SERVICE_CONDITION_FATAL_FAILURE == condition )) + { + skip_condition = true; + } + + snprintf( reason_text, SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR, + "%s(%s, %s%s%s)", service_name, + sm_service_state_str( state ), sm_service_status_str( status ), + skip_condition ? "" : ", ", + skip_condition ? "" : sm_service_condition_str( condition ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Audit - Write Reason Text +// ======================================= +static bool sm_service_group_audit_write_reason_text( const char data[], + char reason_text[], int reason_text_size ) +{ + bool have_space = true; + + if( '\0' == reason_text[0] ) + { + snprintf( reason_text, reason_text_size, "%s", data ); + } else { + int len = strlen(reason_text); + int left = reason_text_size - len - 1 ; + int data_len = (int) strlen(data); + + if( left > (data_len + 32) ) // reserve extra room + { + snprintf( &(reason_text[len]), left, ", %s", data ); + } else { + snprintf( &(reason_text[len]), left, ", ..." ); + have_space = false; + } + } + + return( have_space ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Audit - Map Service Condition +// =========================================== +static void sm_service_group_audit_map_service_condition( + SmServiceConditionT service_condition, SmServiceGroupConditionT* condition ) +{ + switch( service_condition ) + { + case SM_SERVICE_CONDITION_NIL: + *condition = SM_SERVICE_GROUP_CONDITION_NIL; + break; + + case SM_SERVICE_CONDITION_UNKNOWN: + *condition = SM_SERVICE_GROUP_CONDITION_UNKNOWN; + break; + + case SM_SERVICE_CONDITION_NONE: + *condition = SM_SERVICE_GROUP_CONDITION_NONE; + break; + + case SM_SERVICE_CONDITION_DATA_INCONSISTENT: + *condition = SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT; + break; + + case SM_SERVICE_CONDITION_DATA_OUTDATED: + *condition = SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED; + break; + + case SM_SERVICE_CONDITION_DATA_CONSISTENT: + *condition = SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT; + break; + + case SM_SERVICE_CONDITION_DATA_SYNC: + *condition = SM_SERVICE_GROUP_CONDITION_DATA_SYNC; + break; + + case SM_SERVICE_CONDITION_DATA_STANDALONE: + *condition = SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE; + break; + + case SM_SERVICE_CONDITION_RECOVERY_FAILURE: + *condition = SM_SERVICE_GROUP_CONDITION_RECOVERY_FAILURE; + break; + + case SM_SERVICE_CONDITION_ACTION_FAILURE: + *condition = SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE; + break; + + case SM_SERVICE_CONDITION_FATAL_FAILURE: + *condition = SM_SERVICE_GROUP_CONDITION_FATAL_FAILURE; + break; + + default: + *condition = SM_SERVICE_GROUP_CONDITION_UNKNOWN; + DPRINTFE( "Unknown service condition (%i) given.", + service_condition ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Audit - Service For Status +// ======================================== +static void sm_service_group_audit_service_for_status( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + bool do_increment = true; + long elapsed_ms, delta_ms; + SmServiceGroupT* service_group = (SmServiceGroupT*) user_data[0]; + SmServiceGroupStatusT* status = (SmServiceGroupStatusT*) user_data[1]; + SmServiceGroupConditionT* condition = (SmServiceGroupConditionT*) user_data[2]; + int* failed = (int*) user_data[3]; + int* degraded = (int*) user_data[4]; + int* warn = (int*) user_data[5]; + bool* reason_text_writable = (bool*) user_data[6]; + char* reason_text = (char*) user_data[7]; + int reason_text_size = *(int*) user_data[8]; + SmServiceGroupStatusT prev_status = *status; + SmServiceGroupConditionT prev_condition = *condition; + SmServiceGroupStatusT mapped_status; + SmServiceGroupConditionT mapped_condition; + char service_reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR] = ""; + + if( 0 != service_group_member->service_failure_timestamp ) + { + elapsed_ms = sm_time_get_elapsed_ms( NULL ); + delta_ms = elapsed_ms - service_group_member->service_failure_timestamp; + + if( service_group->failure_debounce_in_ms >= delta_ms ) + { + DPRINTFD( "Service group (%s) member (%s) failure debounce " + "still in effect, indicating member as unhealthy, " + "delta_ms=%li.", service_group->name, + service_group_member->service_name, delta_ms ); + + do_increment = false; + + switch( service_group_member->service_failure_impact ) + { + case SM_SERVICE_SEVERITY_NONE: + break; + + case SM_SERVICE_SEVERITY_MINOR: + ++(*warn); + break; + + case SM_SERVICE_SEVERITY_MAJOR: + ++(*degraded); + break; + + case SM_SERVICE_SEVERITY_CRITICAL: + ++(*failed); + break; + + default: + break; + } + } else { + DPRINTFD( "Service group (%s) member (%s) failure debounce " + "no longer in effect, delta_ms=%li.", service_group->name, + service_group_member->service_name, delta_ms ); + } + } + + switch( service_group_member->service_status ) + { + case SM_SERVICE_STATUS_NONE: + mapped_status = SM_SERVICE_GROUP_STATUS_NONE; + mapped_condition = SM_SERVICE_GROUP_CONDITION_NONE; + break; + + case SM_SERVICE_STATUS_WARN: + mapped_status = SM_SERVICE_GROUP_STATUS_WARN; + mapped_condition = SM_SERVICE_GROUP_CONDITION_NONE; + + sm_service_group_audit_set_service_reason_text( + service_reason_text, + service_group_member->service_name, + service_group_member->service_state, + service_group_member->service_status, + service_group_member->service_condition ); + + if( do_increment ) + { + ++(*warn); + } + break; + + case SM_SERVICE_STATUS_DEGRADED: + mapped_status = SM_SERVICE_GROUP_STATUS_DEGRADED; + + sm_service_group_audit_map_service_condition( + service_group_member->service_condition, + &mapped_condition ); + + sm_service_group_audit_set_service_reason_text( + service_reason_text, + service_group_member->service_name, + service_group_member->service_state, + service_group_member->service_status, + service_group_member->service_condition ); + + if( do_increment ) + { + ++(*degraded); + } + break; + + case SM_SERVICE_STATUS_FAILED: + switch( service_group_member->service_failure_impact ) + { + case SM_SERVICE_SEVERITY_NONE: + mapped_status = SM_SERVICE_GROUP_STATUS_NONE; + mapped_condition = SM_SERVICE_GROUP_CONDITION_NONE; + break; + + case SM_SERVICE_SEVERITY_MINOR: + mapped_status = SM_SERVICE_GROUP_STATUS_WARN; + mapped_condition = SM_SERVICE_GROUP_CONDITION_NONE; + + if( do_increment ) + { + ++(*warn); + } + break; + + case SM_SERVICE_SEVERITY_MAJOR: + mapped_status = SM_SERVICE_GROUP_STATUS_DEGRADED; + mapped_condition = SM_SERVICE_GROUP_CONDITION_NONE; + + if( do_increment ) + { + ++(*degraded); + } + break; + + case SM_SERVICE_SEVERITY_CRITICAL: + mapped_status = SM_SERVICE_GROUP_STATUS_FAILED; + + sm_service_group_audit_map_service_condition( + service_group_member->service_condition, + &mapped_condition ); + + if( do_increment ) + { + ++(*failed); + } + break; + + default: + mapped_status = SM_SERVICE_GROUP_STATUS_UNKNOWN; + mapped_condition = SM_SERVICE_GROUP_CONDITION_UNKNOWN; + break; + } + + sm_service_group_audit_set_service_reason_text( + service_reason_text, + service_group_member->service_name, + service_group_member->service_state, + service_group_member->service_status, + service_group_member->service_condition ); + break; + + default: + mapped_status = SM_SERVICE_GROUP_STATUS_UNKNOWN; + mapped_condition = SM_SERVICE_GROUP_CONDITION_UNKNOWN; + break; + } + + if( SM_SERVICE_GROUP_STATUS_UNKNOWN != mapped_status ) + { + switch( *status ) + { + case SM_SERVICE_GROUP_STATUS_NONE: + *status = mapped_status; + break; + + case SM_SERVICE_GROUP_STATUS_WARN: + if( SM_SERVICE_GROUP_STATUS_NONE != mapped_status ) + { + *status = mapped_status; + } + break; + + case SM_SERVICE_GROUP_STATUS_DEGRADED: + if(( SM_SERVICE_GROUP_STATUS_NONE != mapped_status )&& + ( SM_SERVICE_GROUP_STATUS_WARN != mapped_status )) + { + *status = mapped_status; + } + break; + + case SM_SERVICE_GROUP_STATUS_FAILED: + if(( SM_SERVICE_GROUP_STATUS_NONE != mapped_status )&& + ( SM_SERVICE_GROUP_STATUS_WARN != mapped_status )&& + ( SM_SERVICE_GROUP_STATUS_DEGRADED != mapped_status )) + { + *status = mapped_status; + } + break; + + default: + DPRINTFE( "Service group (%s) status (%s) not handled.", + service_group->name, + sm_service_group_status_str( mapped_status ) ); + break; + } + + switch( *condition ) + { + case SM_SERVICE_GROUP_CONDITION_NONE: + *condition = mapped_condition; + break; + + case SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT: + case SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED: + case SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT: + case SM_SERVICE_GROUP_CONDITION_DATA_SYNC: + case SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE: + if( SM_SERVICE_GROUP_CONDITION_NONE != mapped_condition ) + { + *condition = mapped_condition; + } + break; + + case SM_SERVICE_GROUP_CONDITION_RECOVERY_FAILURE: + if(( SM_SERVICE_GROUP_CONDITION_NONE != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_SYNC != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE != mapped_condition )) + { + *condition = mapped_condition; + } + break; + + case SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE: + if(( SM_SERVICE_GROUP_CONDITION_NONE != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_SYNC != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_RECOVERY_FAILURE != mapped_condition )) + { + *condition = mapped_condition; + } + break; + + case SM_SERVICE_GROUP_CONDITION_FATAL_FAILURE: + if(( SM_SERVICE_GROUP_CONDITION_NONE != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_SYNC != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_RECOVERY_FAILURE != mapped_condition )&& + ( SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE != mapped_condition )) + { + *condition = mapped_condition; + } + break; + + default: + DPRINTFE( "Service group (%s) condition (%s) not handled.", + service_group->name, + sm_service_group_condition_str( mapped_condition ) ); + break; + } + } else { + DPRINTFE( "Service (%s) has unmapped severity (%s) for service " + "group (%s).", service_group_member->service_name, + sm_service_severity_str( + service_group_member->service_failure_impact ), + service_group->name ); + } + + if(( *status != service_group->status )&&( prev_status != *status )) + { + DPRINTFI( "Service group (%s) member (%s) has mapped status (%s), " + "overall_status=%s.", service_group_member->name, + service_group_member->service_name, + sm_service_group_status_str(mapped_status), + sm_service_group_status_str(*status) ); + } + + if(( *condition != service_group->condition )&& + ( prev_condition != *condition )) + { + DPRINTFI( "Service group (%s) member (%s) has mapped condition (%s), " + "overall_condition=%s.", service_group_member->name, + service_group_member->service_name, + sm_service_group_condition_str(mapped_condition), + sm_service_group_condition_str(*condition) ); + } + + if( SM_SERVICE_GROUP_STATUS_NONE != *status ) + { + if( prev_status != *status ) + { + *reason_text_writable = true; + reason_text[0] = '\0'; + } + + if(( '\0' != service_reason_text[0] )&&( *reason_text_writable )) + { + *reason_text_writable + = sm_service_group_audit_write_reason_text( + service_reason_text, reason_text, reason_text_size ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Audit - Status +// ============================ +SmErrorT sm_service_group_audit_status( SmServiceGroupT* service_group ) +{ + int failed=0, degraded=0, warn=0; + SmServiceGroupStatusT audit_status = SM_SERVICE_GROUP_STATUS_NONE; + SmServiceGroupConditionT audit_condition = SM_SERVICE_GROUP_CONDITION_NONE; + int64_t audit_health = 0; + bool reason_text_writable = true; + char reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR] = ""; + int reason_text_size = SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR; + void* user_data[] = { service_group, &audit_status, &audit_condition, + &failed, °raded, &warn, &reason_text_writable, + reason_text, &reason_text_size }; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_audit_service_for_status ); + + audit_health = sm_service_group_health_calculate( failed, degraded, warn ); + + service_group->status = audit_status; + service_group->condition = audit_condition; + service_group->health = audit_health; + + snprintf( service_group->reason_text, sizeof(service_group->reason_text), + "%s", reason_text ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Audit - Initialize +// ================================ +SmErrorT sm_service_group_audit_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Audit - Finalize +// ============================== +SmErrorT sm_service_group_audit_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_audit.h b/service-mgmt/sm-1.0.0/src/sm_service_group_audit.h new file mode 100644 index 00000000..d4c06d8c --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_audit.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_AUDIT_H__ +#define __SM_SERVICE_GROUP_AUDIT_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_service_group_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Audit - Status +// ============================ +extern SmErrorT sm_service_group_audit_status( SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Audit - Initialize +// ================================ +extern SmErrorT sm_service_group_audit_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Audit - Finalize +// ============================== +extern SmErrorT sm_service_group_audit_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_AUDIT_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_disable.c b/service-mgmt/sm-1.0.0/src/sm_service_group_disable.c new file mode 100644 index 00000000..4761850a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_disable.c @@ -0,0 +1,123 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_disable.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_member_table.h" +#include "sm_service_api.h" + +// **************************************************************************** +// Service Group Disable - Service +// =============================== +static void sm_service_group_disable_service( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + SmServiceGroupT* service_group = (SmServiceGroupT*) user_data[0]; + SmErrorT error; + + DPRINTFD( "Disabling %s of %s", service_group_member->service_name, + service_group->name ); + + error = sm_service_api_disable( service_group_member->service_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send disable to service (%s) of " + "service group (%s), error=%s.", + service_group_member->service_name, + service_group->name, sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disable +// ===================== +SmErrorT sm_service_group_disable( SmServiceGroupT* service_group ) +{ + void* user_data[] = { service_group }; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_disable_service ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disable - Service Complete +// ======================================== +static void sm_service_group_disable_service_complete( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + bool* complete_overall = (bool*) user_data[0]; + + if( SM_SERVICE_STATE_DISABLED == service_group_member->service_state ) + { + DPRINTFD( "Disable of service (%s) for service group (%s) complete, " + "state=%s.", service_group_member->service_name, + service_group_member->name, + sm_service_state_str( service_group_member->service_state ) ); + } else { + *complete_overall = false; + + DPRINTFD( "Disable of service (%s) for service group (%s) not yet " + "complete, state=%s.", service_group_member->service_name, + service_group_member->name, + sm_service_state_str( service_group_member->service_state ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disable - Complete +// ================================ +SmErrorT sm_service_group_disable_complete( SmServiceGroupT* service_group, + bool* complete ) +{ + bool disable_complete = true; + void* user_data[] = { &disable_complete }; + + *complete = false; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_disable_service_complete ); + + *complete = disable_complete; + + if( disable_complete ) + { + DPRINTFI( "All services disabled for service group (%s) are " + "complete.", service_group->name ); + } else { + DPRINTFD( "Some service disables for service group (%s) are " + "not yet complete.", service_group->name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disable - Initialize +// ================================== +SmErrorT sm_service_group_disable_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disable - Finalize +// ================================ +SmErrorT sm_service_group_disable_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_disable.h b/service-mgmt/sm-1.0.0/src/sm_service_group_disable.h new file mode 100644 index 00000000..6caa489f --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_disable.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_DISABLE_H__ +#define __SM_SERVICE_GROUP_DISABLE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Disable +// ===================== +extern SmErrorT sm_service_group_disable( SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disable - Complete +// ================================ +extern SmErrorT sm_service_group_disable_complete( + SmServiceGroupT* service_group, bool* complete ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disable - Initialize +// ================================== +extern SmErrorT sm_service_group_disable_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disable - Finalize +// ================================ +extern SmErrorT sm_service_group_disable_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_DISABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_disabled_state.c b/service-mgmt/sm-1.0.0/src/sm_service_group_disabled_state.c new file mode 100644 index 00000000..e67bdabe --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_disabled_state.c @@ -0,0 +1,181 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_disabled_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_notification.h" +#include "sm_service_group_fsm.h" +#include "sm_service_group_disable.h" +#include "sm_service_group_audit.h" + +// **************************************************************************** +// Service Group Disabled State - Entry +// ==================================== +SmErrorT sm_service_group_disabled_state_entry( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_notify( + service_group, SM_SERVICE_GROUP_NOTIFICATION_DISABLED ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_disable( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disable service group (%s), error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Exit +// =================================== +SmErrorT sm_service_group_disabled_state_exit( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_abort( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Transition +// ========================================= +SmErrorT sm_service_group_disabled_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Event Handler +// ============================================ +SmErrorT sm_service_group_disabled_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ) +{ + char* service_name = NULL; + SmServiceStateT service_state; + SmServiceGroupStateT state; + SmErrorT error; + + error = sm_service_group_fsm_get_next_state( service_group->name, + event, &state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine next state for service group (%s), " + "error=%s", service_group->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_GROUP_EVENT_GO_ACTIVE: + case SM_SERVICE_GROUP_EVENT_GO_STANDBY: + error = sm_service_group_fsm_set_state( service_group->name, + state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_DISABLE: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT: + // Ignore. + break; + + case SM_SERVICE_GROUP_EVENT_SERVICE_SCN: + service_name = (char *) + event_data[SM_SERVICE_GROUP_EVENT_DATA_SERVICE_NAME]; + service_state = *(SmServiceStateT *) + event_data[SM_SERVICE_GROUP_EVENT_DATA_SERVICE_STATE]; + + DPRINTFD( "Service group (%s) service (%s) state (%s) received.", + service_group->name, service_name, + sm_service_state_str( service_state ) ); + + case SM_SERVICE_GROUP_EVENT_AUDIT: + error = sm_service_group_audit_status( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_SHUTDOWN: + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_SHUTDOWN ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service group (%s) ignoring event (%s).", + service_group->name, + sm_service_group_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Initialize +// ========================================= +SmErrorT sm_service_group_disabled_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Finalize +// ======================================= +SmErrorT sm_service_group_disabled_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_disabled_state.h b/service-mgmt/sm-1.0.0/src/sm_service_group_disabled_state.h new file mode 100644 index 00000000..ddf14e02 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_disabled_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_DISABLED_STATE_H__ +#define __SM_SERVICE_GROUP_DISABLED_STATE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Disabled State - Entry +// ==================================== +extern SmErrorT sm_service_group_disabled_state_entry( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Exit +// =================================== +extern SmErrorT sm_service_group_disabled_state_exit( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Transition +// ========================================= +extern SmErrorT sm_service_group_disabled_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Event Handler +// ============================================ +extern SmErrorT sm_service_group_disabled_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Initialize +// ========================================= +extern SmErrorT sm_service_group_disabled_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabled State - Finalize +// ======================================= +extern SmErrorT sm_service_group_disabled_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_DISABLED_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_disabling_state.c b/service-mgmt/sm-1.0.0/src/sm_service_group_disabling_state.c new file mode 100644 index 00000000..adfc1ebc --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_disabling_state.c @@ -0,0 +1,197 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_disabling_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_notification.h" +#include "sm_service_group_fsm.h" +#include "sm_service_group_disable.h" +#include "sm_service_group_audit.h" + +// **************************************************************************** +// Service Group Disabling State - Entry +// ===================================== +SmErrorT sm_service_group_disabling_state_entry( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_notify( + service_group, SM_SERVICE_GROUP_NOTIFICATION_DISABLING ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Exit +// ==================================== +SmErrorT sm_service_group_disabling_state_exit( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_abort( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Transition +// ========================================== +SmErrorT sm_service_group_disabling_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Event Handler +// ============================================= +SmErrorT sm_service_group_disabling_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ) +{ + bool complete; + SmServiceGroupStateT state; + SmErrorT error; + + error = sm_service_group_fsm_get_next_state( service_group->name, + event, &state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine next state for service group (%s), " + "error=%s", service_group->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_GROUP_EVENT_GO_ACTIVE: + case SM_SERVICE_GROUP_EVENT_GO_STANDBY: + error = sm_service_group_fsm_set_state( service_group->name, + state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_DISABLE: + // Ignore. + break; + + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT: + error = sm_service_group_disable( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disable service group (%s), error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_AUDIT: + case SM_SERVICE_GROUP_EVENT_SERVICE_SCN: + error = sm_service_group_audit_status( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_disable_complete( service_group, + &complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if disable was complete on " + "service group (%s), error=%s", service_group->name, + sm_error_str( error ) ); + return( error ); + } + + if( complete ) + { + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_DISABLED ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_DISABLED ), + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_GROUP_EVENT_SHUTDOWN: + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_SHUTDOWN ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service group (%s) ignoring event (%s).", + service_group->name, + sm_service_group_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Initialize +// ========================================== +SmErrorT sm_service_group_disabling_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Finalize +// ======================================== +SmErrorT sm_service_group_disabling_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_disabling_state.h b/service-mgmt/sm-1.0.0/src/sm_service_group_disabling_state.h new file mode 100644 index 00000000..2c15267d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_disabling_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_DISABLING_STATE_H__ +#define __SM_SERVICE_GROUP_DISABLING_STATE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Disabling State - Entry +// ===================================== +extern SmErrorT sm_service_group_disabling_state_entry( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Exit +// ==================================== +extern SmErrorT sm_service_group_disabling_state_exit( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Transition +// ========================================== +extern SmErrorT sm_service_group_disabling_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Event Handler +// ============================================= +extern SmErrorT sm_service_group_disabling_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Initialize +// ========================================== +extern SmErrorT sm_service_group_disabling_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Disabling State - Finalize +// ======================================== +extern SmErrorT sm_service_group_disabling_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_DISABLING_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_enable.c b/service-mgmt/sm-1.0.0/src/sm_service_group_enable.c new file mode 100644 index 00000000..6eb5c57d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_enable.c @@ -0,0 +1,120 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_enable.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_member_table.h" +#include "sm_service_api.h" + +// **************************************************************************** +// Service Group Enable - Service +// ============================== +static void sm_service_group_enable_service( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + SmServiceGroupT* service_group = (SmServiceGroupT*) user_data[0]; + + DPRINTFD( "Enabling %s of %s", service_group_member->service_name, + service_group->name ); + + // No api to call. + return; +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Enable +// ==================== +SmErrorT sm_service_group_enable( SmServiceGroupT* service_group ) +{ + void* user_data[] = { service_group }; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_enable_service ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Enable - Service Complete +// ======================================= +static void sm_service_group_enable_service_complete( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + bool* complete_overall = (bool*) user_data[0]; + + if(( SM_SERVICE_STATE_ENABLED_ACTIVE == service_group_member->service_state )|| + ( SM_SERVICE_STATE_ENABLED_GO_ACTIVE == service_group_member->service_state )|| + ( SM_SERVICE_STATE_ENABLED_GO_STANDBY == service_group_member->service_state )|| + ( SM_SERVICE_STATE_ENABLED_STANDBY == service_group_member->service_state )) + { + DPRINTFD( "Enable of service (%s) for service group (%s) complete, " + "state=%s.", service_group_member->service_name, + service_group_member->name, + sm_service_state_str( service_group_member->service_state ) ); + } else { + *complete_overall = false; + + DPRINTFD( "Enable of service (%s) for service group (%s) not yet " + "complete, state=%s.", service_group_member->service_name, + service_group_member->name, + sm_service_state_str( service_group_member->service_state ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Enable - Complete +// =============================== +SmErrorT sm_service_group_enable_complete( SmServiceGroupT* service_group, + bool* complete ) +{ + bool enable_complete = true; + void* user_data[] = { &enable_complete }; + + *complete = false; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_enable_service_complete ); + + *complete = enable_complete; + + if( enable_complete ) + { + DPRINTFI( "All services enabled for service group (%s) " + "are complete.", service_group->name ); + } else { + DPRINTFD( "Some service enables for service group (%s) " + "are not yet complete.", service_group->name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Enable - Initialize +// ================================= + +SmErrorT sm_service_group_enable_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Enable - Finalize +// =============================== + +SmErrorT sm_service_group_enable_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_enable.h b/service-mgmt/sm-1.0.0/src/sm_service_group_enable.h new file mode 100644 index 00000000..8a3db6ae --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_enable.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_GROUP_ENABLE_H__ +#define __SM_DB_SERVICE_GROUP_ENABLE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Enable +// ==================== +extern SmErrorT sm_service_group_enable( SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Enable - Complete +// =============================== +extern SmErrorT sm_service_group_enable_complete( + SmServiceGroupT* service_group, bool* complete ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Enable - Initialize +// ================================= +extern SmErrorT sm_service_group_enable_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Enable - Finalize +// =============================== +extern SmErrorT sm_service_group_enable_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_GROUP_ENABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_engine.c b/service-mgmt/sm-1.0.0/src/sm_service_group_engine.c new file mode 100644 index 00000000..107edcc0 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_engine.c @@ -0,0 +1,299 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_engine.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_selobj.h" +#include "sm_timer.h" +#include "sm_service_group_fsm.h" + +#define SM_SERVICE_GROUP_ENGINE_AUDIT_TIMER_IN_MS 30000 +#define SM_SERVICE_GROUP_ENGINE_TIMER_IN_MS 1250 +#define SM_SERVICE_GROUP_ENGINE_THROTTLE_SIGNALS 0 + +static int _engine_fd = -1; +static SmTimerIdT _engine_timer_id = SM_TIMER_ID_INVALID; +static SmTimerIdT _engine_audit_timer_id = SM_TIMER_ID_INVALID; +static uint64_t _dispatches_per_interval = 0; + +// **************************************************************************** +// Service Group Engine - Audit +// ============================ +static void sm_service_group_engine_audit( void* user_data[], + SmServiceGroupT* service_group ) +{ + SmServiceGroupEventT event = SM_SERVICE_GROUP_EVENT_AUDIT; + SmErrorT error; + + error = sm_service_group_fsm_event_handler( service_group->name, event, + NULL, "periodic audit" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service group (%s).", + sm_service_group_event_str( event ), + service_group->name ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Engine - Audit Timeout +// ==================================== +static bool sm_service_group_engine_audit_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + sm_service_group_table_foreach( NULL, sm_service_group_engine_audit ); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Engine - Timeout +// ============================== +static bool sm_service_group_engine_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + uint64_t count = 1; + + _dispatches_per_interval = 0; + + if( 0 > write( _engine_fd, &count, sizeof(count) ) ) + { + DPRINTFE( "Failed to signal service groups, error=%s", + strerror( errno ) ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Engine - Signal +// ============================= +SmErrorT sm_service_group_engine_signal( SmServiceGroupT* service_group ) +{ + if( service_group->desired_state != service_group->state ) + { + if( SM_SERVICE_GROUP_ENGINE_THROTTLE_SIGNALS > _dispatches_per_interval ) + { + uint64_t count = 1; + + if( 0 > write( _engine_fd, &count, sizeof(count) ) ) + { + DPRINTFE( "Failed to signal service group (%s), error=%s", + service_group->name, strerror( errno ) ); + return( SM_FAILED ); + } + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Engine - Signal Handler +// ===================================== +static void sm_service_group_engine_signal_handler( void* user_data[], + SmServiceGroupT* service_group ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceGroupEventT event = SM_SERVICE_GROUP_EVENT_UNKNOWN; + SmErrorT error; + + if( service_group->desired_state == service_group->state ) + { + DPRINTFD( "Service group (%s) already in desired state (%s).", + service_group->name, + sm_service_group_state_str( service_group->desired_state ) ); + return; + } + + DPRINTFD( "Signal handler called for service group (%s), " + "desired-state=%s, state=%s", service_group->name, + sm_service_group_state_str( service_group->desired_state ), + sm_service_group_state_str( service_group->state ) ); + + switch( service_group->desired_state ) + { + case SM_SERVICE_GROUP_STATE_INITIAL: + return; + break; + + case SM_SERVICE_GROUP_STATE_ACTIVE: + event = SM_SERVICE_GROUP_EVENT_GO_ACTIVE; + snprintf( reason_text, sizeof(reason_text), + "active state requested" ); + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + event = SM_SERVICE_GROUP_EVENT_GO_STANDBY; + snprintf( reason_text, sizeof(reason_text), + "standby state requested" ); + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + event = SM_SERVICE_GROUP_EVENT_DISABLE; + snprintf( reason_text, sizeof(reason_text), + "disabled state requested" ); + break; + + default: + DPRINTFE( "Service group (%s) has unknown desired state (%s).", + service_group->name, + sm_service_group_state_str( service_group->desired_state ) ); + break; + } + + if( SM_SERVICE_GROUP_EVENT_UNKNOWN != event ) + { + error = sm_service_group_fsm_event_handler( service_group->name, + event, NULL, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Event (%s) not handled for service group (%s).", + sm_service_group_event_str( event ), + service_group->name ); + } + } else { + error = sm_service_group_engine_signal( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return; + } + } + + return; +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Engine - Dispatch +// =============================== +static void sm_service_group_engine_dispatch( int selobj, int64_t user_data ) +{ + uint64_t count; + + read( _engine_fd, &count, sizeof(count) ); + + ++_dispatches_per_interval; + + sm_service_group_table_foreach( NULL, + sm_service_group_engine_signal_handler ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Groups Engine - Initialize +// ================================== +SmErrorT sm_service_group_engine_initialize( void ) +{ + SmErrorT error; + + _engine_fd = eventfd( 0, EFD_CLOEXEC | EFD_NONBLOCK ); + if( 0 > _engine_fd ) + { + DPRINTFE( "Failed to open file descriptor,error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + error = sm_selobj_register( _engine_fd, sm_service_group_engine_dispatch, + 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + _dispatches_per_interval = 0; + + error = sm_timer_register( "service group engine", + SM_SERVICE_GROUP_ENGINE_TIMER_IN_MS, + sm_service_group_engine_timeout, + 0, &_engine_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create engine timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_timer_register( "service group audit", + SM_SERVICE_GROUP_ENGINE_AUDIT_TIMER_IN_MS, + sm_service_group_engine_audit_timeout, + 0, &_engine_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create engine audit timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Engine - Finalize +// =============================== +SmErrorT sm_service_group_engine_finalize( void ) +{ + SmErrorT error; + + _dispatches_per_interval = 0; + + if( SM_TIMER_ID_INVALID != _engine_audit_timer_id ) + { + error = sm_timer_deregister( _engine_audit_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel engine audit timer, error=%s.", + sm_error_str( error ) ); + } + _engine_audit_timer_id = SM_TIMER_ID_INVALID; + } + + if( SM_TIMER_ID_INVALID != _engine_timer_id ) + { + error = sm_timer_deregister( _engine_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel engine timer, error=%s.", + sm_error_str( error ) ); + } + _engine_timer_id = SM_TIMER_ID_INVALID; + } + + if( 0 <= _engine_fd ) + { + error = sm_selobj_deregister( _engine_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + close( _engine_fd ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_engine.h b/service-mgmt/sm-1.0.0/src/sm_service_group_engine.h new file mode 100644 index 00000000..0bc0322f --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_engine.h @@ -0,0 +1,39 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_ENGINE_H__ +#define __SM_SERVICE_GROUP_ENGINE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Engine - Signal +// ============================= +extern SmErrorT sm_service_group_engine_signal( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Engine - Initialize +// ================================= +extern SmErrorT sm_service_group_engine_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Engine - Finalize +// =============================== +extern SmErrorT sm_service_group_engine_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_ENGINE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_fsm.c b/service-mgmt/sm-1.0.0/src/sm_service_group_fsm.c new file mode 100644 index 00000000..ec5833e0 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_fsm.c @@ -0,0 +1,1290 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_fsm.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" +#include "sm_list.h" +#include "sm_selobj.h" +#include "sm_service_group_table.h" +#include "sm_service_group_member_table.h" +#include "sm_service_table.h" +#include "sm_service_group_engine.h" +#include "sm_service_group_initial_state.h" +#include "sm_service_group_active_state.h" +#include "sm_service_group_go_standby_state.h" +#include "sm_service_group_go_active_state.h" +#include "sm_service_group_standby_state.h" +#include "sm_service_group_disabling_state.h" +#include "sm_service_group_disabled_state.h" +#include "sm_service_group_shutdown_state.h" +#include "sm_service_group_enable.h" +#include "sm_service_group_go_active.h" +#include "sm_service_group_go_standby.h" +#include "sm_service_group_disable.h" +#include "sm_service_group_audit.h" +#include "sm_service_api.h" +#include "sm_log.h" +#include "sm_node_utils.h" +#include "sm_node_swact_monitor.h" +#include "sm_failover.h" +#include "sm_swact_state.h" + +static SmListT* _callbacks = NULL; + +// **************************************************************************** +// Service Group FSM - Register Callback +// ===================================== +SmErrorT sm_service_group_fsm_register_callback( + SmServiceGroupFsmCallbackT callback ) +{ + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Deregister Callback +// ======================================= +SmErrorT sm_service_group_fsm_deregister_callback( + SmServiceGroupFsmCallbackT callback ) +{ + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callback ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Notify +// ========================== +static void sm_service_group_fsm_notify( SmServiceGroupT* service_group, + const char reason_text[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupFsmCallbackT callback; + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callback = (SmServiceGroupFsmCallbackT) entry_data; + + callback( service_group->name, service_group->state, + service_group->status, service_group->condition, + service_group->health, reason_text ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Update Service Group Member +// =============================================== +static void sm_service_group_fsm_update_service_group_member( + void* user_data[], SmServiceGroupMemberT* service_group_member ) +{ + SmServiceT* service; + + service = sm_service_table_read( service_group_member->service_name ); + if( NULL == service ) + { + DPRINTFE( "Failed to read service group member (%s), error=%s.", + service_group_member->service_name, + sm_error_str(SM_NOT_FOUND) ); + return; + } + + if(( service->state != service_group_member->service_state )|| + ( service->status != service_group_member->service_status )) + { + service_group_member->service_state = service->state; + service_group_member->service_status = service->status; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Update Service Group Members +// ================================================ +static SmErrorT sm_service_group_fsm_update_service_group_members( void ) +{ + sm_service_group_member_table_foreach( NULL, + sm_service_group_fsm_update_service_group_member ); + return( SM_OKAY ); +} +// **************************************************************************** + +static void sm_service_group_state_check( void* user_data[], + SmServiceGroupT* service_group ) +{ + bool *all_good = (bool*)user_data[0]; + if( service_group->desired_state != service_group->state ) + { + *all_good = false; + } +} + +// **************************************************************************** +// Service Group FSM - Enter State +// =============================== +static SmErrorT sm_service_group_fsm_enter_state( SmServiceGroupT* service_group ) +{ + SmErrorT error; + + switch( service_group->state ) + { + case SM_SERVICE_GROUP_STATE_INITIAL: + error = sm_service_group_initial_state_entry( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to enter state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_ACTIVE: + error = sm_service_group_active_state_entry( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to enter state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_GO_ACTIVE: + error = sm_service_group_go_active_state_entry( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to enter state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_GO_STANDBY: + error = sm_service_group_go_standby_state_entry( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to enter state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + error = sm_service_group_standby_state_entry( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to enter state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLING: + error = sm_service_group_disabling_state_entry( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to enter state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + // US102803: This is a workaround for lack of sm message that + // signifies the "end-of-swact" state on both controller nodes. + // + // As all service groups have to transition to disabled state + // during swact regardless of the outcome (success or failure), it + // is a suitable spot to reaffine tasks back to the platform cores. + // Controller services group is often the last group to reach + // any state. Task reaffining is only applicable to AIO duplex. + bool duplex; + sm_node_utils_is_aio_duplex(&duplex); + if (( duplex ) && ( 0 == strcmp( "controller-services", service_group->name ))) + { + DPRINTFI( "Reaffining tasks back to platform cores..." ); + sm_set_swact_state(SM_SWACT_STATE_END); + } + error = sm_service_group_disabled_state_entry( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to enter state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_SHUTDOWN: + error = sm_service_group_shutdown_state_entry( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to enter state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service group (%s) state (%s).", + service_group->name, + sm_service_group_state_str( service_group->state ) ); + break; + } + + if( SM_SERVICE_GROUP_STATE_STANDBY == service_group->state || + SM_SERVICE_GROUP_STATE_ACTIVE == service_group->state ) + { + bool all_good = true; + void* user_data[] = {&all_good}; + sm_service_group_table_foreach( user_data, sm_service_group_state_check ); + if( all_good ) + { + SmNodeScheduleStateT controller_state = get_controller_state(); + char hostname[SM_NODE_NAME_MAX_CHAR]; + error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( error ) ); + hostname[0] = '\0'; + } + if( SM_NODE_STATE_ACTIVE == controller_state ) + { + SmNodeSwactMonitor::SwactUpdate(hostname, SM_NODE_STATE_ACTIVE ); + } + else if ( SM_NODE_STATE_STANDBY == controller_state ) + { + SmNodeSwactMonitor::SwactUpdate(hostname, SM_NODE_STATE_STANDBY ); + }else + { + SmNodeSwactMonitor::SwactUpdate(hostname, SM_NODE_STATE_FAILED ); + } + } + } + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Exit State +// ============================== +static SmErrorT sm_service_group_fsm_exit_state( SmServiceGroupT* service_group ) +{ + SmErrorT error; + + switch( service_group->state ) + { + case SM_SERVICE_GROUP_STATE_INITIAL: + error = sm_service_group_initial_state_exit( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to exit state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_ACTIVE: + error = sm_service_group_active_state_exit( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to exit state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_GO_ACTIVE: + error = sm_service_group_go_active_state_exit( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to exit state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_GO_STANDBY: + error = sm_service_group_go_standby_state_exit( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to exit state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + error = sm_service_group_standby_state_exit( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to exit state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLING: + error = sm_service_group_disabling_state_exit( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to exit state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + error = sm_service_group_disabled_state_exit( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to exit state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_SHUTDOWN: + error = sm_service_group_shutdown_state_exit( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to exit state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service group (%s) state (%s).", + service_group->name, + sm_service_group_state_str( service_group->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Transition State +// ==================================== +static SmErrorT sm_service_group_fsm_transition_state( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + SmErrorT error; + + switch( service_group->state ) + { + case SM_SERVICE_GROUP_STATE_INITIAL: + error = sm_service_group_initial_state_transition( service_group, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + service_group->name, + sm_service_group_state_str( from_state ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_ACTIVE: + error = sm_service_group_active_state_transition( service_group, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + service_group->name, + sm_service_group_state_str( from_state ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_GO_ACTIVE: + error = sm_service_group_go_active_state_transition( service_group, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + service_group->name, + sm_service_group_state_str( from_state ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_GO_STANDBY: + error = sm_service_group_go_standby_state_transition( service_group, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + service_group->name, + sm_service_group_state_str( from_state ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + error = sm_service_group_standby_state_transition( service_group, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + service_group->name, + sm_service_group_state_str( from_state ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLING: + error = sm_service_group_disabling_state_transition( service_group, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + service_group->name, + sm_service_group_state_str( from_state ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + error = sm_service_group_disabled_state_transition( service_group, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + service_group->name, + sm_service_group_state_str( from_state ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_SHUTDOWN: + error = sm_service_group_shutdown_state_transition( service_group, + from_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to transition from " + "state (%s) to state (%s), error=%s.", + service_group->name, + sm_service_group_state_str( from_state ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown service group (%s) state (%s).", + service_group->name, + sm_service_group_state_str( service_group->state ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Set State +// ============================= +SmErrorT sm_service_group_fsm_set_state( char service_group_name[], + SmServiceGroupStateT state ) +{ + SmServiceGroupStateT prev_state; + SmServiceGroupT* service_group; + SmErrorT error, error2; + + service_group = sm_service_group_table_read( service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + service_group_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = service_group->state; + + error = sm_service_group_fsm_exit_state( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to exit state (%s) service group (%s), error=%s.", + sm_service_group_state_str( service_group->state ), + service_group_name, sm_error_str( error ) ); + return( error ); + } + + service_group->state = state; + + error = sm_service_group_fsm_transition_state( service_group, + prev_state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to transition to state (%s) service group (%s), " + "error=%s.", sm_service_group_state_str( service_group->state ), + service_group_name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + error = sm_service_group_fsm_enter_state( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to enter state (%s) service group (%s), error=%s.", + sm_service_group_state_str( service_group->state ), + service_group_name, sm_error_str( error ) ); + goto STATE_CHANGE_ERROR; + } + + + return( SM_OKAY ); + +STATE_CHANGE_ERROR: + error2 = sm_service_group_fsm_exit_state( service_group ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to exit state (%s) service group (%s), error=%s.", + sm_service_group_state_str( service_group->state ), + service_group_name, sm_error_str( error2 ) ); + abort(); + } + + service_group->state = prev_state; + + error2 = sm_service_group_fsm_transition_state( service_group, state ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to transition to state (%s) service group (%s), " + "error=%s.", sm_service_group_state_str( service_group->state ), + service_group_name, sm_error_str( error2 ) ); + abort(); + } + + error2 = sm_service_group_fsm_enter_state( service_group ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to enter state (%s) service group (%s), error=%s.", + sm_service_group_state_str( service_group->state ), + service_group_name, sm_error_str( error2 ) ); + abort(); + } + + return( error ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Get Next State +// ================================== +SmErrorT sm_service_group_fsm_get_next_state( char service_group_name[], + SmServiceGroupEventT event, SmServiceGroupStateT* state ) +{ + bool complete; + SmServiceGroupT* service_group; + SmErrorT error; + + service_group = sm_service_group_table_read( service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + service_group_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + error = sm_service_group_fsm_update_service_group_members(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update service group (%s) members, " + "error=%s.", service_group->name, + sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_GROUP_EVENT_GO_ACTIVE: + error = sm_service_group_go_active_complete( service_group, + &complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if go-active complete on " + "service group (%s), error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + if( complete ) + { + *state = SM_SERVICE_GROUP_STATE_ACTIVE; + } else { + *state = SM_SERVICE_GROUP_STATE_GO_ACTIVE; + } + break; + + case SM_SERVICE_GROUP_EVENT_GO_STANDBY: + error = sm_service_group_go_standby_complete( service_group, + &complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if go-standby complete on " + "service group (%s), error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + if( complete ) + { + *state = SM_SERVICE_GROUP_STATE_STANDBY; + } else { + *state = SM_SERVICE_GROUP_STATE_GO_STANDBY; + } + break; + + case SM_SERVICE_GROUP_EVENT_DISABLE: + error = sm_service_group_disable_complete( service_group, + &complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if disable complete on " + "service group (%s), error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + if( complete ) + { + *state = SM_SERVICE_GROUP_STATE_DISABLED; + } else { + *state = SM_SERVICE_GROUP_STATE_DISABLING; + } + break; + + default: + // Ignore. + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Event Handler +// ================================= +SmErrorT sm_service_group_fsm_event_handler( char service_group_name[], + SmServiceGroupEventT event, void* event_data[], const char reason_text[] ) +{ + SmServiceGroupStateT prev_state; + SmServiceGroupStatusT prev_status; + SmServiceGroupConditionT prev_condition; + char prev_reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR]; + SmServiceGroupT* service_group; + SmErrorT error; + + service_group = sm_service_group_table_read( service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + service_group_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_NOT_FOUND ); + } + + prev_state = service_group->state; + prev_status = service_group->status; + prev_condition = service_group->condition; + + snprintf( prev_reason_text, sizeof(prev_reason_text), "%s", + service_group->reason_text ); + + switch( service_group->state ) + { + case SM_SERVICE_GROUP_STATE_INITIAL: + error = sm_service_group_initial_state_event_handler( + service_group, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_group_name, + sm_service_group_event_str( event ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_ACTIVE: + error = sm_service_group_active_state_event_handler( + service_group, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_group_name, + sm_service_group_event_str( event ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_GO_ACTIVE: + error = sm_service_group_go_active_state_event_handler( + service_group, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_group_name, + sm_service_group_event_str( event ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_GO_STANDBY: + error = sm_service_group_go_standby_state_event_handler( + service_group, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_group_name, + sm_service_group_event_str( event ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + error = sm_service_group_standby_state_event_handler( + service_group, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_group_name, + sm_service_group_event_str( event ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLING: + error = sm_service_group_disabling_state_event_handler( + service_group, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_group_name, + sm_service_group_event_str( event ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + error = sm_service_group_disabled_state_event_handler( + service_group, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_group_name, + sm_service_group_event_str( event ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_STATE_SHUTDOWN: + error = sm_service_group_shutdown_state_event_handler( + service_group, event, event_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service group (%s) unable to handle event (%s) " + "in state (%s), error=%s.", service_group_name, + sm_service_group_event_str( event ), + sm_service_group_state_str( service_group->state ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFE( "Unknown state (%s) for service group (%s).", + sm_service_group_state_str( service_group->state ), + service_group_name ); + break; + } + + if(( prev_state != service_group->state )|| + ( prev_status != service_group->status )|| + ( prev_condition != service_group->condition )) + { + DPRINTFI( "Service group (%s) was in the %s%s%s state and is now " + "in the %s%s%s state%s%s.", + service_group_name, + sm_service_group_state_str( prev_state ), + SM_SERVICE_GROUP_STATUS_NONE == prev_status + ? "" : "-", + SM_SERVICE_GROUP_STATUS_NONE == prev_status + ? "" : sm_service_group_status_str(prev_status), + sm_service_group_state_str( service_group->state ), + SM_SERVICE_GROUP_STATUS_NONE == service_group->status + ? "" : "-", + SM_SERVICE_GROUP_STATUS_NONE == service_group->status + ? "" : sm_service_group_status_str(service_group->status), + SM_SERVICE_GROUP_CONDITION_NONE == service_group->condition + ? "" : ", condition=", + SM_SERVICE_GROUP_CONDITION_NONE == service_group->condition + ? "" : sm_service_group_condition_str( service_group->condition ) ); + + error = sm_service_group_table_persist( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to persist service group (%s) data, error=%s.", + service_group->name, sm_error_str(error) ); + return( error ); + } + + if(( prev_state != service_group->state )|| + ( prev_status != service_group->status )) + { + sm_log_service_group_state_change( service_group_name, + sm_service_group_state_str( prev_state ), + sm_service_group_status_str( prev_status ), + sm_service_group_state_str( service_group->state ), + sm_service_group_status_str( service_group->status ), + service_group->reason_text ); + } + + sm_service_group_fsm_notify( service_group, + service_group->reason_text ); + + } else if( SM_SERVICE_GROUP_EVENT_AUDIT == event ) { + if(( SM_SERVICE_GROUP_STATE_ACTIVE == service_group->state )|| + ( SM_SERVICE_GROUP_STATE_STANDBY == service_group->state )|| + ( SM_SERVICE_GROUP_STATE_DISABLED == service_group->state )) + { + sm_service_group_fsm_notify( service_group, + service_group->reason_text ); + } + + } else if( 0 != strcmp( prev_reason_text, service_group->reason_text ) ) { + + sm_service_group_fsm_notify( service_group, + service_group->reason_text ); + } + + if( service_group->desired_state != service_group->state ) + { + error = sm_service_group_engine_signal( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to signal service group (%s), error=%s.", + service_group_name, sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Recover Member +// ================================== +static void sm_service_group_fsm_recover_member( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + bool clear_fatal_condition = *(bool*) user_data[0]; + SmErrorT error; + + error = sm_service_api_recover( service_group_member->service_name, + clear_fatal_condition ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to recover member (%s), error=%s.", + service_group_member->service_name, + sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Recover +// =========================== +SmErrorT sm_service_group_fsm_recover( char service_group_name[], + bool clear_fatal_condition ) +{ + void* user_data[] = {&clear_fatal_condition}; + + sm_service_group_member_table_foreach_member( service_group_name, user_data, + sm_service_group_fsm_recover_member); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Service State Change Notification +// ===================================================== +static void sm_service_group_fsm_service_scn( char service_name[], + SmServiceStateT state, SmServiceStatusT status, + SmServiceConditionT condition ) +{ + char reason_text[SM_LOG_REASON_TEXT_MAX_CHAR] = ""; + SmServiceGroupMemberT* service_group_member; + void* event_data[SM_SERVICE_GROUP_EVENT_DATA_MAX] = {0}; + SmErrorT error; + + event_data[SM_SERVICE_GROUP_EVENT_DATA_SERVICE_NAME] = service_name; + event_data[SM_SERVICE_GROUP_EVENT_DATA_SERVICE_STATE] = &state; + + service_group_member = sm_service_group_member_table_read_by_service( + service_name ); + if( NULL == service_group_member ) + { + DPRINTFE( "Failed to query service group member by service (%s), " + "error=%s.", service_name, sm_error_str(SM_NOT_FOUND) ); + return; + } + + service_group_member->service_state = state; + service_group_member->service_status = status; + service_group_member->service_condition = condition; + + if( SM_SERVICE_STATUS_FAILED == status ) + { + service_group_member->service_failure_timestamp + = sm_time_get_elapsed_ms( NULL ); + } + + if( SM_SERVICE_STATUS_NONE == status ) + { + snprintf( reason_text, sizeof(reason_text), "%s service state " + "change, state=%s", service_name, sm_service_state_str(state) ); + } else { + if( SM_SERVICE_CONDITION_NONE == condition ) + { + snprintf( reason_text, sizeof(reason_text), "%s service state " + "change, state=%s, status=%s", service_name, + sm_service_state_str(state), + sm_service_status_str(status) ); + } else { + snprintf( reason_text, sizeof(reason_text), "%s service state " + "change, state=%s, status=%s, condition=%s", + service_name, sm_service_state_str(state), + sm_service_status_str(status), + sm_service_condition_str(condition) ); + } + } + + error = sm_service_group_fsm_event_handler( service_group_member->name, + SM_SERVICE_GROUP_EVENT_SERVICE_SCN, + event_data, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Service (%s) scn not handled for service group (%s), " + "error=%s.", service_group_member->service_name, + service_group_member->name, sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Initialize +// ============================== +SmErrorT sm_service_group_fsm_initialize( void ) +{ + SmErrorT error; + + error = sm_service_group_initial_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group initial state module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_active_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group active state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_go_active_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group go-active state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_go_standby_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group go-standby " + "state module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_standby_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group standby state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_disabling_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group disabling state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_disabled_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group disabled state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_shutdown_state_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group shutdown state " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_enable_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group enable module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_go_active_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group go-active module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_go_standby_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group go-standby module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_disable_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group disable module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_audit_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group audit module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_api_register_callback( sm_service_group_fsm_service_scn ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for service state changes, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Finalize +// ============================ +SmErrorT sm_service_group_fsm_finalize( void ) +{ + SmErrorT error; + + error = sm_service_api_deregister_callback( sm_service_group_fsm_service_scn ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister for service state changes, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_initial_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group initial state module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_active_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group active state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_go_active_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group go-active state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_go_standby_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group go-standby state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_standby_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group standby state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_disabling_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group disabling state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_disabled_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group disabled state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_shutdown_state_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group shutdown state " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_enable_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group enable module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_go_active_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group go-active module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_go_standby_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group go-standby module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_disable_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group disable module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_group_audit_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service group audit module, " + "error=%s.", sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_fsm.h b/service-mgmt/sm-1.0.0/src/sm_service_group_fsm.h new file mode 100644 index 00000000..ab346424 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_fsm.h @@ -0,0 +1,78 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_FSM_H__ +#define __SM_SERVICE_GROUP_FSM_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmServiceGroupFsmCallbackT) (char service_group_name[], + SmServiceGroupStateT state,SmServiceGroupStatusT status, + SmServiceGroupConditionT condition, int64_t health, + const char reason_text[] ); + +// **************************************************************************** +// Service Group FSM - Register Callback +// ===================================== +extern SmErrorT sm_service_group_fsm_register_callback( + SmServiceGroupFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Deregister Callback +// ======================================= +extern SmErrorT sm_service_group_fsm_deregister_callback( + SmServiceGroupFsmCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Set State +// ============================= +extern SmErrorT sm_service_group_fsm_set_state( char service_group_name[], + SmServiceGroupStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Get Next State +// ================================== +extern SmErrorT sm_service_group_fsm_get_next_state( char service_group_name[], + SmServiceGroupEventT event, SmServiceGroupStateT* state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Event Handler +// ================================= +extern SmErrorT sm_service_group_fsm_event_handler( char service_group_name[], + SmServiceGroupEventT event, void* event_data[], const char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Recover +// =========================== +extern SmErrorT sm_service_group_fsm_recover( char service_group_name[], + bool clear_fatal_condition ); +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Initialize +// ============================== +extern SmErrorT sm_service_group_fsm_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group FSM - Finalize +// ============================ +extern SmErrorT sm_service_group_fsm_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_FSM_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_go_active.c b/service-mgmt/sm-1.0.0/src/sm_service_group_go_active.c new file mode 100644 index 00000000..bdc4750b --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_go_active.c @@ -0,0 +1,123 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_go_active.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_member_table.h" +#include "sm_service_api.h" + +// **************************************************************************** +// Service Group Go-Active - Service +// ================================= +static void sm_service_group_go_active_service( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + SmServiceGroupT* service_group = (SmServiceGroupT*) user_data[0]; + SmErrorT error; + + DPRINTFD( "Go-Active on %s of %s", service_group_member->service_name, + service_group->name ); + + error = sm_service_api_go_active( service_group_member->service_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send go-active to service (%s) of " + "service group (%s), error=%s.", + service_group_member->service_name, + service_group->name, sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active +// ======================= +SmErrorT sm_service_group_go_active( SmServiceGroupT* service_group ) +{ + void* user_data[] = { service_group }; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_go_active_service ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active - Service Complete +// ========================================== +static void sm_service_group_go_active_service_complete( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + bool* complete_overall = (bool*) user_data[0]; + + if( SM_SERVICE_STATE_ENABLED_ACTIVE == service_group_member->service_state ) + { + DPRINTFD( "Go-Active of service (%s) for service group (%s) complete, " + "state=%s.", service_group_member->service_name, + service_group_member->name, + sm_service_state_str( service_group_member->service_state ) ); + } else { + *complete_overall = false; + + DPRINTFD( "Go-Active of service (%s) for service group (%s) not yet " + "complete, state=%s.", service_group_member->service_name, + service_group_member->name, + sm_service_state_str( service_group_member->service_state ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active - Complete +// ================================== +SmErrorT sm_service_group_go_active_complete( SmServiceGroupT* service_group, + bool* complete ) +{ + bool go_active_complete = true; + void* user_data[] = { &go_active_complete }; + + *complete = false; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_go_active_service_complete ); + + *complete = go_active_complete; + + if( go_active_complete ) + { + DPRINTFI( "All services go-active for service group (%s) " + "are complete.", service_group->name ); + } else { + DPRINTFD( "Some service go-actives for service group (%s) " + "are not yet complete.", service_group->name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active - Initialize +// ==================================== +SmErrorT sm_service_group_go_active_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active - Finalize +// ================================== +SmErrorT sm_service_group_go_active_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_go_active.h b/service-mgmt/sm-1.0.0/src/sm_service_group_go_active.h new file mode 100644 index 00000000..7eaa349e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_go_active.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_GO_ACTIVE_H__ +#define __SM_SERVICE_GROUP_GO_ACTIVE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Go-Active +// ======================= +extern SmErrorT sm_service_group_go_active( SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active - Complete +// ================================== +extern SmErrorT sm_service_group_go_active_complete( + SmServiceGroupT* service_group, bool* complete ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active - Initialize +// ==================================== +extern SmErrorT sm_service_group_go_active_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active - Finalize +// ================================== +extern SmErrorT sm_service_group_go_active_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_GO_ACTIVE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_go_active_state.c b/service-mgmt/sm-1.0.0/src/sm_service_group_go_active_state.c new file mode 100644 index 00000000..57f3c9dd --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_go_active_state.c @@ -0,0 +1,198 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_go_active_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_notification.h" +#include "sm_service_group_fsm.h" +#include "sm_service_group_go_active.h" +#include "sm_service_group_audit.h" + +// **************************************************************************** +// Service Group Go-Active State - Entry +// ===================================== +SmErrorT sm_service_group_go_active_state_entry( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_notify( + service_group, SM_SERVICE_GROUP_NOTIFICATION_GO_ACTIVE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Exit +// ==================================== +SmErrorT sm_service_group_go_active_state_exit( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_abort( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Transition +// ========================================== +SmErrorT sm_service_group_go_active_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Event Handler +// ============================================= +SmErrorT sm_service_group_go_active_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ) +{ + bool complete; + SmServiceGroupStateT state; + SmErrorT error; + + error = sm_service_group_fsm_get_next_state( service_group->name, + event, &state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine next state for service group (%s), " + "error=%s", service_group->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_GROUP_EVENT_GO_ACTIVE: + // Ignore. + break; + + case SM_SERVICE_GROUP_EVENT_GO_STANDBY: + case SM_SERVICE_GROUP_EVENT_DISABLE: + error = sm_service_group_fsm_set_state( service_group->name, + state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT: + error = sm_service_group_go_active( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-active on service group (%s), " + "error=%s", service_group->name, + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_AUDIT: + case SM_SERVICE_GROUP_EVENT_SERVICE_SCN: + error = sm_service_group_audit_status( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_go_active_complete( service_group, + &complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if go-active complete on " + "service group (%s), error=%s", service_group->name, + sm_error_str( error ) ); + return( error ); + } + + if( complete ) + { + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_ACTIVE ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_ACTIVE ), + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_GROUP_EVENT_SHUTDOWN: + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_SHUTDOWN ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service group (%s) ignoring event (%s).", + service_group->name, + sm_service_group_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Initialize +// ========================================== +SmErrorT sm_service_group_go_active_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Finalize +// ======================================== +SmErrorT sm_service_group_go_active_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_go_active_state.h b/service-mgmt/sm-1.0.0/src/sm_service_group_go_active_state.h new file mode 100644 index 00000000..ffe960af --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_go_active_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_GO_ACTIVE_STATE_H__ +#define __SM_SERVICE_GROUP_GO_ACTIVE_STATE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Go-Active State - Entry +// ===================================== +extern SmErrorT sm_service_group_go_active_state_entry( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Exit +// ==================================== +extern SmErrorT sm_service_group_go_active_state_exit( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Transition +// ========================================== +extern SmErrorT sm_service_group_go_active_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Event Handler +// ============================================= +extern SmErrorT sm_service_group_go_active_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Initialize +// ========================================== +extern SmErrorT sm_service_group_go_active_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Active State - Finalize +// ======================================== +extern SmErrorT sm_service_group_go_active_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_GO_ACTIVE_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby.c b/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby.c new file mode 100644 index 00000000..81d52b22 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby.c @@ -0,0 +1,127 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_go_standby.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_member_table.h" +#include "sm_service_api.h" + +// **************************************************************************** +// Service Group Go-Standby - Service +// ================================== +static void sm_service_group_go_standby_service( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + SmServiceGroupT* service_group = (SmServiceGroupT*) user_data[0]; + SmErrorT error; + + DPRINTFD( "Go-Standby on %s of %s", service_group_member->service_name, + service_group->name ); + + error = sm_service_api_go_standby( service_group_member->service_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send go-standby to service (%s) of " + "service group (%s), error=%s.", + service_group_member->service_name, + service_group->name, sm_error_str( error ) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby +// ======================== +SmErrorT sm_service_group_go_standby( SmServiceGroupT* service_group ) +{ + void* user_data[] = { service_group }; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_go_standby_service ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby - Complete +// =================================== +static void sm_service_group_go_standby_service_complete( void* user_data[], + SmServiceGroupMemberT* service_group_member ) +{ + bool* complete_overall = (bool*) user_data[0]; + + if(( SM_SERVICE_STATE_ENABLED_STANDBY == service_group_member->service_state )|| + ( SM_SERVICE_STATE_ENABLING_THROTTLE == service_group_member->service_state )|| + ( SM_SERVICE_STATE_ENABLING == service_group_member->service_state )|| + ( SM_SERVICE_STATE_DISABLING == service_group_member->service_state )|| + ( SM_SERVICE_STATE_DISABLED == service_group_member->service_state )) + { + DPRINTFD( "Go-Standby of service (%s) for service group (%s) complete, " + "state=%s.", service_group_member->service_name, + service_group_member->name, + sm_service_state_str( service_group_member->service_state ) ); + } else { + *complete_overall = false; + + DPRINTFD( "Go-Standby of service (%s) for service group (%s) not yet " + "complete, state=%s.", service_group_member->service_name, + service_group_member->name, + sm_service_state_str( service_group_member->service_state ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby - Complete +// =================================== +SmErrorT sm_service_group_go_standby_complete( SmServiceGroupT* service_group, + bool* complete ) +{ + bool go_standby_complete = true; + void* user_data[] = { &go_standby_complete }; + + *complete = false; + + sm_service_group_member_table_foreach_member( service_group->name, + user_data, sm_service_group_go_standby_service_complete ); + + *complete = go_standby_complete; + + if( go_standby_complete ) + { + DPRINTFI( "All services go-standby for service group (%s) " + "are complete.", service_group->name ); + } else { + DPRINTFD( "Some service go-standby for service group (%s) " + "are not yet complete.", service_group->name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby - Initialize +// ===================================== +SmErrorT sm_service_group_go_standby_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby - Finalize +// =================================== +SmErrorT sm_service_group_go_standby_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby.h b/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby.h new file mode 100644 index 00000000..9af7719c --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_GO_STANDBY_H__ +#define __SM_SERVICE_GROUP_GO_STANDBY_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Go-Standby +// ======================== +extern SmErrorT sm_service_group_go_standby( SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby - Complete +// =================================== +extern SmErrorT sm_service_group_go_standby_complete( + SmServiceGroupT* service_group, bool* complete ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby - Initialize +// ===================================== +extern SmErrorT sm_service_group_go_standby_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby - Finalize +// ===================================== +extern SmErrorT sm_service_group_go_standby_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_GO_STANDBY_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby_state.c b/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby_state.c new file mode 100644 index 00000000..2a224fad --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby_state.c @@ -0,0 +1,198 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_go_standby_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_notification.h" +#include "sm_service_group_fsm.h" +#include "sm_service_group_go_standby.h" +#include "sm_service_group_audit.h" + +// **************************************************************************** +// Service Group Go-Standby State - Entry +// ====================================== +SmErrorT sm_service_group_go_standby_state_entry( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_notify( + service_group, SM_SERVICE_GROUP_NOTIFICATION_GO_STANDBY ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Exit +// ===================================== +SmErrorT sm_service_group_go_standby_state_exit( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_abort( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Transition +// =========================================== +SmErrorT sm_service_group_go_standby_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Event Handler +// ============================================== +SmErrorT sm_service_group_go_standby_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ) +{ + bool complete; + SmServiceGroupStateT state; + SmErrorT error; + + error = sm_service_group_fsm_get_next_state( service_group->name, + event, &state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine next state for service group (%s), " + "error=%s", service_group->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_GROUP_EVENT_GO_ACTIVE: + case SM_SERVICE_GROUP_EVENT_DISABLE: + error = sm_service_group_fsm_set_state( service_group->name, + state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_GO_STANDBY: + // Ignore. + break; + + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT: + error = sm_service_group_go_standby( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-standby on service group (%s), " + "error=%s", service_group->name, + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_AUDIT: + case SM_SERVICE_GROUP_EVENT_SERVICE_SCN: + error = sm_service_group_audit_status( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_go_standby_complete( service_group, + &complete ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if go-standby complete on " + "service group (%s), error=%s", service_group->name, + sm_error_str( error ) ); + return( error ); + } + + if( complete ) + { + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_STANDBY ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_STANDBY ), + sm_error_str( error ) ); + return( error ); + } + } + break; + + case SM_SERVICE_GROUP_EVENT_SHUTDOWN: + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_SHUTDOWN ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service group (%s) ignoring event (%s).", + service_group->name, + sm_service_group_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Initialize +// =========================================== +SmErrorT sm_service_group_go_standby_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Finalize +// ========================================= +SmErrorT sm_service_group_go_standby_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby_state.h b/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby_state.h new file mode 100644 index 00000000..6c5e8da0 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_go_standby_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_GO_STANDBY_STATE_H__ +#define __SM_SERVICE_GROUP_GO_STANDBY_STATE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Go-Standby State - Entry +// ====================================== +extern SmErrorT sm_service_group_go_standby_state_entry( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Exit +// ===================================== +extern SmErrorT sm_service_group_go_standby_state_exit( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Transition +// =========================================== +extern SmErrorT sm_service_group_go_standby_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Event Handler +// ============================================== +extern SmErrorT sm_service_group_go_standby_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Initialize +// =========================================== +extern SmErrorT sm_service_group_go_standby_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Go-Standby State - Finalize +// ========================================= +extern SmErrorT sm_service_group_go_standby_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_GO_STANDBY_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_health.c b/service-mgmt/sm-1.0.0/src/sm_service_group_health.c new file mode 100644 index 00000000..fe5ddc36 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_health.c @@ -0,0 +1,28 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_health.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" + +// **************************************************************************** +// Service Group Health - Calculate +// ================================ +int64_t sm_service_group_health_calculate( int failed, int degraded, int warn ) +{ + int64_t health; + + health = ((failed & 0xFFFFL) << 32) | ((degraded & 0xFFFFL) << 16) + | (warn & 0xFFFFL); + + health = ~health & 0x0000FFFFFFFFFFFFL; + + return( health ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_health.h b/service-mgmt/sm-1.0.0/src/sm_service_group_health.h new file mode 100644 index 00000000..f2f60287 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_health.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_HEALTH_H__ +#define __SM_SERVICE_GROUP_HEALTH_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Health - Calculate +// ================================ +extern int64_t sm_service_group_health_calculate( int failed, int degraded, + int warn ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_HEALTH_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_initial_state.c b/service-mgmt/sm-1.0.0/src/sm_service_group_initial_state.c new file mode 100644 index 00000000..cff067d3 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_initial_state.c @@ -0,0 +1,121 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_initial_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_fsm.h" +#include "sm_service_group_go_active.h" +#include "sm_service_group_go_standby.h" + +// **************************************************************************** +// Service Group Initial State - Entry +// =================================== +SmErrorT sm_service_group_initial_state_entry( SmServiceGroupT* service_group ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Exit +// ================================== +SmErrorT sm_service_group_initial_state_exit( SmServiceGroupT* service_group ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Transition +// ======================================== +SmErrorT sm_service_group_initial_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Event Handler +// =========================================== +SmErrorT sm_service_group_initial_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ) +{ + SmServiceGroupStateT state; + SmErrorT error; + + error = sm_service_group_fsm_get_next_state( service_group->name, + event, &state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine next state for service group (%s), " + "error=%s", service_group->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_GROUP_EVENT_GO_ACTIVE: + case SM_SERVICE_GROUP_EVENT_GO_STANDBY: + case SM_SERVICE_GROUP_EVENT_DISABLE: + error = sm_service_group_fsm_set_state( service_group->name, + state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_SHUTDOWN: + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_SHUTDOWN ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Service group (%s) ignoring event (%s).", + service_group->name, + sm_service_group_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Initialize +// ======================================== +SmErrorT sm_service_group_initial_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Finalize +// ====================================== +SmErrorT sm_service_group_initial_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_initial_state.h b/service-mgmt/sm-1.0.0/src/sm_service_group_initial_state.h new file mode 100644 index 00000000..b8618856 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_initial_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_INITIAL_STATE_H__ +#define __SM_SERVICE_GROUP_INITIAL_STATE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Initial State - Entry +// =================================== +extern SmErrorT sm_service_group_initial_state_entry( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Exit +// ================================== +extern SmErrorT sm_service_group_initial_state_exit( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Transition +// ======================================== +extern SmErrorT sm_service_group_initial_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Event Handler +// =========================================== +extern SmErrorT sm_service_group_initial_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Initialize +// ======================================== +extern SmErrorT sm_service_group_initial_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Initial State - Finalize +// ====================================== +extern SmErrorT sm_service_group_initial_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_INITIAL_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_member_table.c b/service-mgmt/sm-1.0.0/src/sm_service_group_member_table.c new file mode 100644 index 00000000..5903046e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_member_table.c @@ -0,0 +1,300 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_member_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_group_members.h" + +static SmListT* _service_group_members = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Group Member Table - Read +// ================================= +SmServiceGroupMemberT* sm_service_group_member_table_read( + char service_group_name[], char service_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupMemberT* service_group_member; + + SM_LIST_FOREACH( _service_group_members, entry, entry_data ) + { + service_group_member = (SmServiceGroupMemberT*) entry_data; + + if(( 0 == strcmp( service_group_name, service_group_member->name ) )&& + ( 0 == strcmp( service_name, service_group_member->service_name ) )) + { + return( service_group_member ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Read By Identifier +// =============================================== +SmServiceGroupMemberT* sm_service_group_member_table_read_by_id( + int64_t service_group_member_id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupMemberT* service_group_member; + + SM_LIST_FOREACH( _service_group_members, entry, entry_data ) + { + service_group_member = (SmServiceGroupMemberT*) entry_data; + + if( service_group_member_id == service_group_member->id ) + { + return( service_group_member ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Read By Service +// ============================================ +SmServiceGroupMemberT* sm_service_group_member_table_read_by_service( + char service_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupMemberT* service_group_member; + + SM_LIST_FOREACH( _service_group_members, entry, entry_data ) + { + service_group_member = (SmServiceGroupMemberT*) entry_data; + + if( 0 == strcmp( service_name, service_group_member->service_name ) ) + { + return( service_group_member ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - For Each +// ===================================== +void sm_service_group_member_table_foreach( void* user_data[], + SmServiceGroupMemberTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + + SM_LIST_FOREACH( _service_group_members, entry, entry_data ) + { + callback( user_data, (SmServiceGroupMemberT*) entry_data ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - For Each Member +// ============================================ +void sm_service_group_member_table_foreach_member( char service_group_name[], + void* user_data[], SmServiceGroupMemberTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupMemberT* service_group_member; + + SM_LIST_FOREACH( _service_group_members, entry, entry_data ) + { + service_group_member = (SmServiceGroupMemberT*) entry_data; + + if( 0 == strcmp( service_group_name, service_group_member->name ) ) + { + callback( user_data, service_group_member ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Add +// ================================ +static SmErrorT sm_service_group_member_table_add( void* user_data[], + void* record ) +{ + SmServiceGroupMemberT* service_group_member; + SmDbServiceGroupMemberT* db_service_group_member; + + db_service_group_member = (SmDbServiceGroupMemberT*) record; + + service_group_member = sm_service_group_member_table_read( + db_service_group_member->name, + db_service_group_member->service_name ); + if( NULL == service_group_member ) + { + service_group_member + = (SmServiceGroupMemberT*) malloc( sizeof(SmServiceGroupMemberT) ); + if( NULL == service_group_member ) + { + DPRINTFE( "Failed to allocate service group member table entry." ); + return( SM_FAILED ); + } + + memset( service_group_member, 0, sizeof(SmServiceGroupMemberT) ); + + service_group_member->id = db_service_group_member->id; + snprintf( service_group_member->name, sizeof(service_group_member->name), + "%s", db_service_group_member->name ); + snprintf( service_group_member->service_name, + sizeof(service_group_member->service_name), + "%s", db_service_group_member->service_name ); + service_group_member->service_state = SM_SERVICE_STATE_INITIAL; + service_group_member->service_status = SM_SERVICE_STATUS_NONE; + service_group_member->service_condition = SM_SERVICE_CONDITION_NONE; + service_group_member->service_failure_impact + = db_service_group_member->service_failure_impact; + service_group_member->service_failure_timestamp = 0; + + SM_LIST_PREPEND( _service_group_members, + (SmListEntryDataPtrT) service_group_member ); + + } else { + service_group_member->id = db_service_group_member->id; + service_group_member->service_failure_impact + = db_service_group_member->service_failure_impact; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Load +// ================================= +SmErrorT sm_service_group_member_table_load( void ) +{ + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbServiceGroupMemberT service_group_member; + SmErrorT error; + + snprintf( db_query, sizeof(db_query), "%s = 'yes'", + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_PROVISIONED ); + + error = sm_db_foreach( SM_DATABASE_NAME, + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME, + db_query, &service_group_member, + sm_db_service_group_members_convert, + sm_service_group_member_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service group memberss in database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Persist +// ==================================== +SmErrorT sm_service_group_member_table_persist( + SmServiceGroupMemberT* service_group_member ) +{ + SmDbServiceGroupMemberT db_service_group_member; + SmErrorT error; + + memset( &db_service_group_member, 0, sizeof(db_service_group_member) ); + + db_service_group_member.id = service_group_member->id; + snprintf( db_service_group_member.name, + sizeof(db_service_group_member.name), + "%s", service_group_member->name ); + snprintf( db_service_group_member.service_name, + sizeof(db_service_group_member.service_name), + "%s", service_group_member->service_name ); + db_service_group_member.service_failure_impact + = service_group_member->service_failure_impact; + + error = sm_db_service_group_members_update( _sm_db_handle, + &db_service_group_member ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Initialize +// ======================================= +SmErrorT sm_service_group_member_table_initialize( void ) +{ + SmErrorT error; + + _service_group_members = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_member_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service group members from database, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Finalize +// ===================================== +SmErrorT sm_service_group_member_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_group_members ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_member_table.h b/service-mgmt/sm-1.0.0/src/sm_service_group_member_table.h new file mode 100644 index 00000000..16dc3689 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_member_table.h @@ -0,0 +1,98 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_MEMBER_TABLE_H__ +#define __SM_SERVICE_GROUP_MEMBER_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int64_t id; + char name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + char service_name[SM_SERVICE_NAME_MAX_CHAR]; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; + SmServiceSeverityT service_failure_impact; + long service_failure_timestamp; +} SmServiceGroupMemberT; + +typedef void (*SmServiceGroupMemberTableForEachCallbackT) + (void* user_data[], SmServiceGroupMemberT* service_group_member); + +// **************************************************************************** +// Service Group Member Table - Read +// ================================= +extern SmServiceGroupMemberT* sm_service_group_member_table_read( + char service_group_name[], char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Read By Identifier +// =============================================== +extern SmServiceGroupMemberT* sm_service_group_member_table_read_by_id( + int64_t service_group_member_id ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Read By Service +// ============================================ +extern SmServiceGroupMemberT* sm_service_group_member_table_read_by_service( + char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - For Each +// ===================================== +extern void sm_service_group_member_table_foreach( void* user_data[], + SmServiceGroupMemberTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - For Each Member +// ============================================ +extern void sm_service_group_member_table_foreach_member( + char service_group_name[], void* user_data[], + SmServiceGroupMemberTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Load +// ================================= +extern SmErrorT sm_service_group_member_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Persist +// ==================================== +extern SmErrorT sm_service_group_member_table_persist( + SmServiceGroupMemberT* service_group_member ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Initialize +// ======================================= +extern SmErrorT sm_service_group_member_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Member Table - Finalize +// ===================================== +extern SmErrorT sm_service_group_member_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_MEMBER_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_notification.c b/service-mgmt/sm-1.0.0/src/sm_service_group_notification.c new file mode 100644 index 00000000..b3bbd747 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_notification.c @@ -0,0 +1,817 @@ +// +// Copyright (c) 2014-2016 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_notification.h" + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_utils.h" +#include "sm_debug.h" +#include "sm_process_death.h" +#include "sm_service_domain_member_table.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +typedef struct +{ + char seqnum_str[24]; + bool part_of_aggregate; + char service_group_aggregate_name[SM_SERVICE_GROUP_AGGREGATE_NAME_MAX_CHAR]; + SmServiceGroupStateT service_group_aggregate_desired_state; + SmServiceGroupStateT service_group_aggregate_state; + char service_group_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceGroupStateT service_group_desired_state; + SmServiceGroupStateT service_group_state; + SmServiceGroupNotificationT service_group_notification; +} SmNotificationEnvT; + +#define SM_NOTIFICATION_SCRIPT_MAX_DELAY_IN_SECS 4 +#define SM_NOTIFICATION_SCRIPT_TIMEOUT_IN_MS 30000 +#define SM_NOTIFICATION_SCRIPT_TIMER_SKEW_IN_MS 60000 +#define SM_NOTIFICATION_SCRIPT_SUCCESS 0 +#define SM_NOTIFICATION_SCRIPT_TIMEOUT -65534 +#define SM_NOTIFICATION_SCRIPT_FAILURE -65535 + +static unsigned long _seqnum = 0; + + +// **************************************************************************** +// Service Group Notification - Do Abort +// ===================================== +static SmErrorT sm_service_group_notification_do_abort( + char service_group_name[], int process_id ) +{ + if( -1 == process_id ) + { + DPRINTFE( "Trying to abort a process (%i) for service group (%s) " + "notificaton but pid is invalid.", process_id, + service_group_name ); + return( SM_FAILED ); + } + + if( process_id == (int) getpid() ) + { + DPRINTFE( "Trying to abort a process (%i) for service group (%s) " + "notification but pid is self.", process_id, + service_group_name ); + return( SM_FAILED ); + } + + DPRINTFI( "Aborting service group (%s) notification with kill signal, " + "pid=%i.", service_group_name, process_id ); + + if( 0 > kill( process_id, SIGKILL ) ) + { + if( ESRCH == errno ) + { + DPRINTFD( "Service group (%s) notification script not running.", + service_group_name ); + return( SM_OKAY ); + + } else { + DPRINTFE( "Failed to send kill signal to service group (%s) " + "notification script, error=%s.", service_group_name, + strerror( errno ) ); + return( SM_FAILED ); + } + } + + DPRINTFD( "Kill signal sent to service groupt (%s) notification " + "script.", service_group_name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Service Group Aggregate +// ==================================================== +static void sm_service_group_notification_service_group_aggregate( + void* user_data[], SmServiceDomainMemberT* member ) +{ + SmServiceGroupStateT* aggregate_desired_state; + SmServiceGroupStateT* aggregate_state; + SmServiceGroupStateT* transition_state; + SmServiceGroupT* service_group; + + aggregate_desired_state = (SmServiceGroupStateT*) user_data[0]; + aggregate_state = (SmServiceGroupStateT*) user_data[1]; + transition_state = (SmServiceGroupStateT*) user_data[2]; + + service_group = sm_service_group_table_read( member->service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + member->service_group_name, sm_error_str(SM_NOT_FOUND) ); + return; + } + + switch( service_group->desired_state ) + { + case SM_SERVICE_GROUP_STATE_ACTIVE: + if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_desired_state )|| + ( SM_SERVICE_GROUP_STATE_STANDBY != *aggregate_desired_state )|| + ( SM_SERVICE_GROUP_STATE_DISABLED != *aggregate_desired_state )|| + ( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_desired_state )) + *aggregate_desired_state = service_group->desired_state; + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_desired_state )|| + ( SM_SERVICE_GROUP_STATE_DISABLED != *aggregate_desired_state )|| + ( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_desired_state )) + *aggregate_desired_state = service_group->desired_state; + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_desired_state )|| + ( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_desired_state )) + *aggregate_desired_state = service_group->desired_state; + break; + + case SM_SERVICE_GROUP_STATE_SHUTDOWN: + *aggregate_desired_state = service_group->desired_state; + break; + + default: + // Ignore + break; + } + + switch( service_group->state ) + { + case SM_SERVICE_GROUP_STATE_ACTIVE: + if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_state )|| + ( SM_SERVICE_GROUP_STATE_STANDBY != *aggregate_state )|| + ( SM_SERVICE_GROUP_STATE_DISABLED != *aggregate_state )|| + ( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_state )) + *aggregate_state = service_group->state; + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_state )|| + ( SM_SERVICE_GROUP_STATE_DISABLED != *aggregate_state )|| + ( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_state )) + *aggregate_state = service_group->state; + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *aggregate_state )|| + ( SM_SERVICE_GROUP_STATE_SHUTDOWN != *aggregate_state )) + *aggregate_state = service_group->state; + break; + + case SM_SERVICE_GROUP_STATE_SHUTDOWN: + *aggregate_state = service_group->state; + break; + + case SM_SERVICE_GROUP_STATE_GO_ACTIVE: + if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *transition_state )|| + ( SM_SERVICE_GROUP_STATE_GO_STANDBY != *transition_state )|| + ( SM_SERVICE_GROUP_STATE_DISABLING != *transition_state )) + *transition_state = service_group->state; + break; + + case SM_SERVICE_GROUP_STATE_GO_STANDBY: + if(( SM_SERVICE_GROUP_STATE_UNKNOWN == *transition_state )|| + ( SM_SERVICE_GROUP_STATE_DISABLING != *transition_state )) + *transition_state = service_group->state; + break; + + case SM_SERVICE_GROUP_STATE_DISABLING: + *transition_state = service_group->state; + break; + + default: + // Ignore + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Get Environment +// ============================================ +static SmErrorT sm_service_group_notification_get_env( + char service_group_name[], SmServiceGroupNotificationT notification, + SmNotificationEnvT* env ) +{ + SmServiceGroupStateT aggregate_desired_state = SM_SERVICE_GROUP_STATE_UNKNOWN; + SmServiceGroupStateT aggregate_state = SM_SERVICE_GROUP_STATE_UNKNOWN; + SmServiceGroupStateT transition_state = SM_SERVICE_GROUP_STATE_UNKNOWN; + void* user_data[] = {&aggregate_desired_state, &aggregate_state, + &transition_state}; + SmServiceDomainMemberT* service_domain_member = NULL; + SmServiceGroupT* service_group = NULL; + + service_group = sm_service_group_table_read( service_group_name ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group (%s), error=%s.", + service_group_name, sm_error_str(SM_NOT_FOUND) ); + return( SM_FAILED ); + } + + _seqnum++; + snprintf( &(env->seqnum_str[0]), sizeof(env->seqnum_str), "%lu", _seqnum ); + snprintf( &(env->service_group_name[0]), SM_SERVICE_GROUP_NAME_MAX_CHAR, + "%s", service_group->name ); + env->service_group_desired_state = service_group->desired_state; + env->service_group_state = service_group->state; + env->service_group_notification = notification; + + service_domain_member = + sm_service_domain_member_table_read_service_group( service_group->name ); + + if( NULL != service_domain_member ) + { + if( '\0' != service_domain_member->service_group_aggregate[0] ) + { + sm_service_domain_member_table_foreach_service_group_aggregate( + service_domain_member->name, + service_domain_member->service_group_aggregate, user_data, + sm_service_group_notification_service_group_aggregate ); + + switch( aggregate_state ) + { + case SM_SERVICE_GROUP_STATE_ACTIVE: + if(( SM_SERVICE_GROUP_STATE_GO_ACTIVE == transition_state )|| + ( SM_SERVICE_GROUP_STATE_GO_STANDBY == transition_state )|| + ( SM_SERVICE_GROUP_STATE_DISABLING == transition_state )) + aggregate_state = transition_state; + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + if(( SM_SERVICE_GROUP_STATE_GO_STANDBY == transition_state )|| + ( SM_SERVICE_GROUP_STATE_DISABLING == transition_state )) + aggregate_state = transition_state; + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + if( SM_SERVICE_GROUP_STATE_DISABLING == transition_state ) + aggregate_state = transition_state; + break; + + case SM_SERVICE_GROUP_STATE_UNKNOWN: + aggregate_state = transition_state; + break; + + default: + // Ignore + break; + } + + env->part_of_aggregate = true; + snprintf( &(env->service_group_aggregate_name[0]), + SM_SERVICE_GROUP_AGGREGATE_NAME_MAX_CHAR, "%s", + service_domain_member->service_group_aggregate ); + env->service_group_aggregate_desired_state = aggregate_desired_state; + env->service_group_aggregate_state = aggregate_state; + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Setup Environment +// ============================================== +static SmErrorT sm_service_group_notification_setup_env( + SmNotificationEnvT* env ) +{ + if( 0 > setenv( "NOTIFICATION_SEQNUM", env->seqnum_str, 1 ) ) + { + DPRINTFE( "Failed to set environment variable (NOTIFICATION_SEQNUM), " + "error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + + if( 0 > setenv( "SERVICE_GROUP_NAME", env->service_group_name, 1 ) ) + { + DPRINTFE( "Failed to set environment variable (SERVICE_GROUP_NAME), " + "error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + if( 0 > setenv( "SERVICE_GROUP_DESIRED_STATE", + sm_service_group_state_str( + env->service_group_desired_state), 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(SERVICE_GROUP_DESIRED_STATE), error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + if( 0 > setenv( "SERVICE_GROUP_STATE", + sm_service_group_state_str(env->service_group_state), 1 ) ) + { + DPRINTFE( "Failed to set environment variable (SERVICE_GROUP_STATE), " + "error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + if( 0 > setenv( "SERVICE_GROUP_NOTIFICATION", + sm_service_group_notification_str( + env->service_group_notification), 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(SERVICE_GROUP_NOTIFICATION), error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + if( env->part_of_aggregate ) + { + if( 0 > setenv( "SERVICE_GROUP_AGGREGATE_NAME", + env->service_group_aggregate_name, 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(SERVICE_GROUP_AGGREGATE_NAME), error=%s.", + strerror( errno ) ); + return ( SM_FAILED ); + } + + if( 0 > setenv( "SERVICE_GROUP_AGGREGATE_DESIRED_STATE", + sm_service_group_state_str( + env->service_group_aggregate_desired_state), 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(SERVICE_GROUP_AGGREGATE_DESIRED_STATE), error=%s.", + strerror( errno ) ); + return ( SM_FAILED ); + } + + if( 0 > setenv( "SERVICE_GROUP_AGGREGATE_STATE", + sm_service_group_state_str( + env->service_group_aggregate_state), 1 ) ) + { + DPRINTFE( "Failed to set environment variable " + "(SERVICE_GROUP_AGGREGATE_STATE), error=%s.", + strerror( errno ) ); + return ( SM_FAILED ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Run +// ================================ +static SmErrorT sm_service_group_notification_run( char service_group_name[], + SmServiceGroupNotificationT notification, int* process_id ) +{ + pid_t pid; + struct stat stat_data; + int result; + char program_name[80]; + SmNotificationEnvT env; + SmErrorT error; + + *process_id = -1; + + memset( &env, 0, sizeof(SmNotificationEnvT) ); + + if( 0 > access( SM_NOTIFICATION_SCRIPT, F_OK | X_OK ) ) + { + DPRINTFE( "Service group notification script access failed, " + "error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + if( 0 > stat( SM_NOTIFICATION_SCRIPT, &stat_data ) ) + { + DPRINTFE( "Service group notification script stat failed, " + "error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + if( 0 >= stat_data.st_size ) + { + DPRINTFE( "Service group notification script has zero size." ); + return( SM_FAILED ); + } + + error = sm_service_group_notification_get_env( service_group_name, + notification, &env ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get environment for service group (%s) " + "notification (%s), error=%s.", service_group_name, + sm_service_group_notification_str(notification), + sm_error_str( error ) ); + return( SM_FAILED ); + } + + pid = fork(); + if( 0 > pid ) + { + DPRINTFE( "Failed to fork notification process for service group " + "(%s), error=%s.", service_group_name, strerror( errno ) ); + return( SM_FAILED ); + + } else if( 0 == pid ) { + // Child process. + struct rlimit file_limits; + + DPRINTFD( "Child notification process created for service group " + "(%s).", service_group_name ); + + if( 0 > setpgid( 0, 0 ) ) + { + DPRINTFE( "Failed to set notification process group id for " + "service group (%s) notification (%s), error=%s.", + service_group_name, + sm_service_group_notification_str(notification), + strerror( errno ) ); + exit( SM_NOTIFICATION_SCRIPT_FAILURE ); + } + + if( 0 > getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + DPRINTFE( "Failed to get file limits for service group (%s) " + "notification (%s), error=%s.", service_group_name, + sm_service_group_notification_str(notification), + strerror( errno ) ); + exit( SM_NOTIFICATION_SCRIPT_FAILURE ); + } + + unsigned int fd_i; + for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i ) + { + close( fd_i ); + } + + if( 0 > open( "/dev/null", O_RDONLY ) ) + { + DPRINTFE( "Failed to open stdin to /dev/null for service group " + "(%s) notification (%s), error=%s.", service_group_name, + sm_service_group_notification_str(notification), + strerror( errno ) ); + } + + if( 0 > open( "/dev/null", O_WRONLY ) ) + { + DPRINTFE( "Failed to open stdout to /dev/null for service group " + "(%s) notification (%s), error=%s.", service_group_name, + sm_service_group_notification_str(notification), + strerror( errno ) ); + } + + if( 0 > open( "/dev/null", O_WRONLY ) ) + { + DPRINTFE( "Failed to open stderr to /dev/null for service group " + "(%s) notification (%s), error=%s.", service_group_name, + sm_service_group_notification_str(notification), + strerror( errno ) ); + } + + result = setpriority( PRIO_PROCESS, getpid(), -1 ); + if( 0 > result ) + { + DPRINTFE( "Failed to set priority of process, error=%s.", + strerror( errno ) ); + exit( SM_NOTIFICATION_SCRIPT_FAILURE ); + } + + error = sm_service_group_notification_setup_env( &env ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to setup environment for service group (%s) " + "notification (%s), error=%s.", service_group_name, + sm_service_group_notification_str(notification), + sm_error_str( error ) ); + exit( SM_NOTIFICATION_SCRIPT_FAILURE ); + } + + snprintf( program_name, sizeof(program_name), "%s", + SM_NOTIFICATION_SCRIPT ); + + char* argv[] = {program_name, NULL}; + + if( 0 > execv( program_name, argv ) ) + { + DPRINTFE( "Failed to exec command for service group (%s) " + "notification (%s), error=%s.", service_group_name, + sm_service_group_notification_str(notification), + strerror( errno ) ); + } + + exit( SM_NOTIFICATION_SCRIPT_FAILURE ); + + } else { + // Parent process. + *process_id = (int) pid; + + DPRINTFD( "Child notification process (%i) created for service " + "group (%s) notification (%s).", *process_id, + service_group_name, + sm_service_group_notification_str(notification) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Timeout +// ==================================== +static bool sm_service_group_notification_timeout( SmTimerIdT timer_id, + int64_t user_data ) +{ + int64_t id = user_data; + SmServiceGroupT* service_group; + SmErrorT error; + + service_group = sm_service_group_table_read_by_id( id ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to read service group, error=%s.", + sm_error_str(SM_NOT_FOUND) ); + return( false ); + } + + if( -1 == service_group->notification_pid ) + { + DPRINTFE( "Service group (%s) notification script not running.", + service_group->name ); + return( false ); + } + + DPRINTFI( "Notification (%s) timeout for service group (%s).", + service_group->notification_str, service_group->name ); + + error = sm_service_group_notification_do_abort( + service_group->name, service_group->notification_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort notification script for service group " + "(%s), error=%s.", service_group->name, + sm_error_str( error ) ); + } + + service_group->notification_pid = -1; + service_group->notification_timer_id = SM_TIMER_ID_INVALID; + service_group->notification_complete = false; + service_group->notification_failed = true; + service_group->notification_timeout = true; + + error = sm_service_group_fsm_event_handler( service_group->name, + SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT, NULL, + "notification script timed out" ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service group (%s) fsm notification " + "timed out, error=%s.", service_group->name, + sm_error_str( error ) ); + abort(); + } + + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Complete +// ===================================== +static void sm_service_group_notification_complete( pid_t pid, int exit_code, + int64_t user_data ) +{ + SmServiceGroupT* service_group; + SmServiceGroupEventT event; + char reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR] = ""; + SmErrorT error; + + service_group = sm_service_group_table_read_by_notification_pid( (int) pid ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to query service group based on pid (%i), error=%s.", + (int) pid, sm_error_str(SM_NOT_FOUND) ); + return; + } + + if( -1 == service_group->notification_pid ) + { + DPRINTFE( "Service group (%s) not running notification script.", + service_group->name ); + return; + } + + if( SM_TIMER_ID_INVALID != service_group->notification_timer_id ) + { + error = sm_timer_deregister( service_group->notification_timer_id ); + if( SM_OKAY == error ) + { + DPRINTFD( "Timer stopped for notification (%s) for service " + "group (%s).", service_group->notification_str, + service_group->name ); + } else { + DPRINTFE( "Failed to stop timer for notification (%s) for " + "service group (%s), error=%s.", + service_group->notification_str, service_group->name, + sm_error_str( error ) ); + } + } + + service_group->notification_pid = -1; + service_group->notification_timer_id = SM_TIMER_ID_INVALID; + + if( SM_NOTIFICATION_SCRIPT_SUCCESS == exit_code ) + { + DPRINTFI( "Notification (%s) for service group (%s) passed.", + service_group->notification_str, service_group->name ); + + service_group->notification_complete = true; + service_group->notification_failed = false; + service_group->notification_timeout = false; + + event = SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS; + + } else { + DPRINTFI( "Notification (%s) for service group (%s) failed.", + service_group->notification_str, service_group->name ); + + service_group->notification_complete = true; + service_group->notification_failed = true; + service_group->notification_timeout = false; + + event = SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED; + snprintf( reason_text, sizeof(reason_text), "notification script " + "failed" ); + } + + error = sm_service_group_fsm_event_handler( service_group->name, + event, NULL, reason_text ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to notify service group (%s) fsm, error=%s.", + service_group->name, sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Notify +// =================================== +SmErrorT sm_service_group_notification_notify( SmServiceGroupT* service_group, + SmServiceGroupNotificationT notification ) +{ + const char* notification_str; + char timer_name[80] = ""; + int process_id = -1; + int timeout_in_ms = SM_NOTIFICATION_SCRIPT_TIMEOUT_IN_MS; + SmTimerIdT timer_id = SM_TIMER_ID_INVALID; + SmErrorT error; + + notification_str = + sm_service_group_notification_str(notification); + + // Run notification script. + error = sm_service_group_notification_run( service_group->name, + notification, &process_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to run notification script for service group (%s), " + "error=%s.", service_group->name, sm_error_str( error ) ); + return( error ); + } + + // Register for notification script exit. + error = sm_process_death_register( process_id, true, + sm_service_group_notification_complete, + 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register for notification completion for " + "service group (%s), error=%s.", service_group->name, + sm_error_str( error ) ); + abort(); + } + + // Create timer for notification completion. + snprintf( timer_name, sizeof(timer_name), "%s %s notification ", + service_group->name, notification_str ); + + if( sm_utils_watchdog_delayed( SM_NOTIFICATION_SCRIPT_MAX_DELAY_IN_SECS ) ) + { + DPRINTFI( "Notification timeout %d secs increased by %d ms, " + "sm-watchdog delayed.", timeout_in_ms, + SM_NOTIFICATION_SCRIPT_TIMER_SKEW_IN_MS ); + timeout_in_ms += SM_NOTIFICATION_SCRIPT_TIMER_SKEW_IN_MS; + } + + error = sm_timer_register( timer_name, timeout_in_ms, + sm_service_group_notification_timeout, + service_group->id, &timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create a timer for notification for service " + "group (%s), error=%s.", service_group->name, + sm_error_str( error ) ); + abort(); + } + + service_group->notification = notification; + service_group->notification_str = notification_str; + service_group->notification_pid = process_id; + service_group->notification_timer_id = timer_id; + service_group->notification_complete = false; + service_group->notification_failed = false; + service_group->notification_timeout = false; + + DPRINTFI( "Started notification (%s) process (%i) for service group " + "(%s).", service_group->notification_str, process_id, + service_group->name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Abort +// ================================== +SmErrorT sm_service_group_notification_abort( SmServiceGroupT* service_group ) +{ + const char* notification_str; + SmErrorT error; + + notification_str = + sm_service_group_notification_str(service_group->notification); + + DPRINTFI( "Aborting notification (%s) for service group (%s).", + notification_str, service_group->name ); + + if( -1 != service_group->notification_pid ) + { + error = sm_service_group_notification_do_abort( + service_group->name, service_group->notification_pid ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort notification (%s) for service group " + "(%s), error=%s.", notification_str, service_group->name, + sm_error_str( error ) ); + return( error ); + } + } + + if( SM_TIMER_ID_INVALID != service_group->notification_timer_id ) + { + error = sm_timer_deregister( service_group->notification_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Cancel notification timer for service group (%s) " + "failed, error=%s.", service_group->name, + sm_error_str( error ) ); + return( error ); + } + } + + service_group->notification = SM_SERVICE_GROUP_NOTIFICATION_NIL; + service_group->notification_str = NULL; + service_group->notification_pid = -1; + service_group->notification_timer_id = SM_TIMER_ID_INVALID; + service_group->notification_complete = false; + service_group->notification_failed = false; + service_group->notification_timeout = false; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Initialize +// ======================================= +SmErrorT sm_service_group_notification_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Finalize +// ===================================== +SmErrorT sm_service_group_notification_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_notification.h b/service-mgmt/sm-1.0.0/src/sm_service_group_notification.h new file mode 100644 index 00000000..eee5702a --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_notification.h @@ -0,0 +1,47 @@ +// +// Copyright (c) 2014-2016 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_NOTIFICATION_H__ +#define __SM_SERVICE_GROUP_NOTIFICATION_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Notification - Notify +// =================================== +extern SmErrorT sm_service_group_notification_notify( + SmServiceGroupT* service_group, SmServiceGroupNotificationT notification ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Abort +// ================================== +extern SmErrorT sm_service_group_notification_abort( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Initialize +// ======================================= +extern SmErrorT sm_service_group_notification_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Notification - Finalize +// ===================================== +extern SmErrorT sm_service_group_notification_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_NOTIFICATION_H__ + diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_shutdown_state.c b/service-mgmt/sm-1.0.0/src/sm_service_group_shutdown_state.c new file mode 100644 index 00000000..80e52d8e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_shutdown_state.c @@ -0,0 +1,102 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_shutdown_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_notification.h" +#include "sm_service_group_fsm.h" + +// **************************************************************************** +// Service Group Shutdown State - Entry +// ==================================== +SmErrorT sm_service_group_shutdown_state_entry( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_notify( + service_group, SM_SERVICE_GROUP_NOTIFICATION_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + } + + service_group->status = SM_SERVICE_GROUP_STATUS_NONE; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Exit +// =================================== +SmErrorT sm_service_group_shutdown_state_exit( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_abort( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Transition +// ========================================= +SmErrorT sm_service_group_shutdown_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Event Handler +// ============================================ +SmErrorT sm_service_group_shutdown_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ) +{ + switch( event ) + { + default: + DPRINTFD( "Service group (%s) ignoring event (%s).", + service_group->name, + sm_service_group_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Initialize +// ========================================= +SmErrorT sm_service_group_shutdown_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Finalize +// ======================================= +SmErrorT sm_service_group_shutdown_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_shutdown_state.h b/service-mgmt/sm-1.0.0/src/sm_service_group_shutdown_state.h new file mode 100644 index 00000000..797ce13b --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_shutdown_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_SHUTDOWN_STATE_H__ +#define __SM_SERVICE_GROUP_SHUTDOWN_STATE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Shutdown State - Entry +// ==================================== +extern SmErrorT sm_service_group_shutdown_state_entry( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Exit +// =================================== +extern SmErrorT sm_service_group_shutdown_state_exit( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Transition +// ========================================= +extern SmErrorT sm_service_group_shutdown_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Event Handler +// ============================================ +extern SmErrorT sm_service_group_shutdown_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Initialize +// ========================================= +extern SmErrorT sm_service_group_shutdown_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Shutdown State - Finalize +// ======================================= +extern SmErrorT sm_service_group_shutdown_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_SHUTDOWN_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_standby_state.c b/service-mgmt/sm-1.0.0/src/sm_service_group_standby_state.c new file mode 100644 index 00000000..ef659811 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_standby_state.c @@ -0,0 +1,182 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_standby_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_group_notification.h" +#include "sm_service_group_fsm.h" +#include "sm_service_group_go_active.h" +#include "sm_service_group_go_standby.h" +#include "sm_service_group_audit.h" + +// **************************************************************************** +// Service Group Standby State - Entry +// =================================== +SmErrorT sm_service_group_standby_state_entry( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_notify( + service_group, SM_SERVICE_GROUP_NOTIFICATION_STANDBY ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_go_standby( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go-standby on service group (%s), error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Exit +// ================================== +SmErrorT sm_service_group_standby_state_exit( + SmServiceGroupT* service_group ) +{ + SmErrorT error; + + error = sm_service_group_notification_abort( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort service group (%s) notification, error=%s", + service_group->name, sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Transition +// ======================================== +SmErrorT sm_service_group_standby_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Event Handler +// =========================================== +SmErrorT sm_service_group_standby_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ) +{ + char* service_name = NULL; + SmServiceStateT service_state; + SmServiceGroupStateT state; + SmErrorT error; + + error = sm_service_group_fsm_get_next_state( service_group->name, + event, &state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine next state for service group (%s), " + "error=%s", service_group->name, sm_error_str( error ) ); + return( error ); + } + + switch( event ) + { + case SM_SERVICE_GROUP_EVENT_GO_ACTIVE: + case SM_SERVICE_GROUP_EVENT_DISABLE: + error = sm_service_group_fsm_set_state( service_group->name, + state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_GO_STANDBY: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED: + case SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT: + // Ignore. + break; + + case SM_SERVICE_GROUP_EVENT_SERVICE_SCN: + service_name = (char *) + event_data[SM_SERVICE_GROUP_EVENT_DATA_SERVICE_NAME]; + service_state = *(SmServiceStateT *) + event_data[SM_SERVICE_GROUP_EVENT_DATA_SERVICE_STATE]; + + DPRINTFD( "Service group (%s) service (%s) state (%s) received.", + service_group->name, service_name, + sm_service_state_str( service_state ) ); + + case SM_SERVICE_GROUP_EVENT_AUDIT: + error = sm_service_group_audit_status( service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service group (%s), error=%s.", + service_group->name, sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_GROUP_EVENT_SHUTDOWN: + error = sm_service_group_fsm_set_state( service_group->name, + SM_SERVICE_GROUP_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service group (%s) state (%s), " + "error=%s.", service_group->name, + sm_service_group_state_str( + SM_SERVICE_GROUP_STATE_SHUTDOWN ), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFI( "Service group (%s) ignoring event (%s).", + service_group->name, + sm_service_group_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Initialize +// ======================================== +SmErrorT sm_service_group_standby_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Finalize +// ====================================== +SmErrorT sm_service_group_standby_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_standby_state.h b/service-mgmt/sm-1.0.0/src/sm_service_group_standby_state.h new file mode 100644 index 00000000..ec7b7597 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_standby_state.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_STANDBY_STATE_H__ +#define __SM_SERVICE_GROUP_STANDBY_STATE_H__ + +#include "sm_types.h" +#include "sm_service_group_table.h" +#include "sm_service_group_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Group Standby State - Entry +// =================================== +extern SmErrorT sm_service_group_standby_state_entry( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Exit +// ================================== +extern SmErrorT sm_service_group_standby_state_exit( + SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Transition +// ======================================== +extern SmErrorT sm_service_group_standby_state_transition( + SmServiceGroupT* service_group, SmServiceGroupStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Event Handler +// =========================================== +extern SmErrorT sm_service_group_standby_state_event_handler( + SmServiceGroupT* service_group, SmServiceGroupEventT event, + void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Initialize +// ======================================== +extern SmErrorT sm_service_group_standby_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Standby State - Finalize +// ====================================== +extern SmErrorT sm_service_group_standby_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_STANDBY_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_table.c b/service-mgmt/sm-1.0.0/src/sm_service_group_table.c new file mode 100644 index 00000000..53dd2796 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_table.c @@ -0,0 +1,280 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_group_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_service_groups.h" + +static SmListT* _service_groups = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Group Table - Read +// ========================== +SmServiceGroupT* sm_service_group_table_read( char service_group_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupT* service_group; + + SM_LIST_FOREACH( _service_groups, entry, entry_data ) + { + service_group = (SmServiceGroupT*) entry_data; + + if( 0 == strcmp( service_group_name, service_group->name ) ) + { + return( service_group ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Read By Identifier +// ======================================== +SmServiceGroupT* sm_service_group_table_read_by_id( int64_t service_group_id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupT* service_group; + + SM_LIST_FOREACH( _service_groups, entry, entry_data ) + { + service_group = (SmServiceGroupT*) entry_data; + + if( service_group_id == service_group->id ) + { + return( service_group ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Read By Notification Pid +// ============================================== +SmServiceGroupT* sm_service_group_table_read_by_notification_pid( int pid ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceGroupT* service_group; + + SM_LIST_FOREACH( _service_groups, entry, entry_data ) + { + service_group = (SmServiceGroupT*) entry_data; + + if( pid == service_group->notification_pid ) + { + return( service_group ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - For Each +// ============================== +void sm_service_group_table_foreach( void* user_data[], + SmServiceGroupTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + + SM_LIST_FOREACH( _service_groups, entry, entry_data ) + { + callback( user_data, (SmServiceGroupT*) entry_data ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Add +// ========================= +static SmErrorT sm_service_group_table_add( void* user_data[], void* record ) +{ + SmServiceGroupT* service_group; + SmDbServiceGroupT* db_service_group = (SmDbServiceGroupT*) record; + + service_group = sm_service_group_table_read( db_service_group->name ); + if( NULL == service_group ) + { + service_group = (SmServiceGroupT*) malloc( sizeof(SmServiceGroupT) ); + if( NULL == service_group ) + { + DPRINTFE( "Failed to allocate service group table entry." ); + return( SM_FAILED ); + } + + memset( service_group, 0, sizeof(SmServiceGroupT) ); + + service_group->id = db_service_group->id; + snprintf( service_group->name, sizeof(service_group->name), "%s", + db_service_group->name ); + service_group->auto_recover = db_service_group->auto_recover; + service_group->core = db_service_group->core; + service_group->desired_state = db_service_group->desired_state; + service_group->state = db_service_group->state; + service_group->status = db_service_group->status; + service_group->condition = db_service_group->condition; + service_group->failure_debounce_in_ms + = db_service_group->failure_debounce_in_ms; + service_group->fatal_error_reboot + = db_service_group->fatal_error_reboot; + service_group->reason_text[0] = '\0'; + service_group->notification = SM_SERVICE_GROUP_NOTIFICATION_NIL; + service_group->notification_str = NULL; + service_group->notification_pid = -1; + service_group->notification_timer_id = SM_TIMER_ID_INVALID; + service_group->notification_complete = false; + service_group->notification_failed = false; + service_group->notification_timeout = false; + + SM_LIST_PREPEND( _service_groups, (SmListEntryDataPtrT) service_group ); + + } else { + service_group->id = db_service_group->id; + service_group->auto_recover = db_service_group->auto_recover; + service_group->core = db_service_group->core; + service_group->failure_debounce_in_ms + = db_service_group->failure_debounce_in_ms; + service_group->fatal_error_reboot + = db_service_group->fatal_error_reboot; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Load +// ========================== +SmErrorT sm_service_group_table_load( void ) +{ + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbServiceGroupT service_group; + SmErrorT error; + + snprintf( db_query, sizeof(db_query), "%s = 'yes'", + SM_SERVICE_GROUPS_TABLE_COLUMN_PROVISIONED ); + + error = sm_db_foreach( SM_DATABASE_NAME, SM_SERVICE_GROUPS_TABLE_NAME, + db_query, &service_group, + sm_db_service_groups_convert, + sm_service_group_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over service groups in database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Persist +// ============================= +SmErrorT sm_service_group_table_persist( SmServiceGroupT* service_group ) +{ + SmDbServiceGroupT db_service_group; + SmErrorT error; + + memset( &db_service_group, 0, sizeof(db_service_group) ); + + db_service_group.id = service_group->id; + snprintf( db_service_group.name, sizeof(db_service_group.name), "%s", + service_group->name ); + db_service_group.auto_recover = service_group->auto_recover; + db_service_group.core = service_group->core; + db_service_group.desired_state = service_group->desired_state; + db_service_group.state = service_group->state; + db_service_group.status = service_group->status; + db_service_group.condition = service_group->condition; + db_service_group.failure_debounce_in_ms + = service_group->failure_debounce_in_ms; + db_service_group.fatal_error_reboot = service_group->fatal_error_reboot; + + error = sm_db_service_groups_update( _sm_db_handle, &db_service_group ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Initialize +// ================================ +SmErrorT sm_service_group_table_initialize( void ) +{ + SmErrorT error; + + _service_groups = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_group_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load service groups from database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Finalize +// ============================== +SmErrorT sm_service_group_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _service_groups ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_group_table.h b/service-mgmt/sm-1.0.0/src/sm_service_group_table.h new file mode 100644 index 00000000..4b768014 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_group_table.h @@ -0,0 +1,101 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_GROUP_TABLE_H__ +#define __SM_SERVICE_GROUP_TABLE_H__ + +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int64_t id; + char name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + bool auto_recover; + bool core; + SmServiceGroupStateT desired_state; + SmServiceGroupStateT state; + SmServiceGroupStatusT status; + SmServiceGroupConditionT condition; + int64_t health; + int failure_debounce_in_ms; + bool fatal_error_reboot; + char reason_text[SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR]; + SmServiceGroupNotificationT notification; + const char* notification_str; + int notification_pid; + SmTimerIdT notification_timer_id; + bool notification_complete; + bool notification_failed; + bool notification_timeout; +} SmServiceGroupT; + +typedef void (*SmServiceGroupTableForEachCallbackT) + (void* user_data[], SmServiceGroupT* service_group); + +// **************************************************************************** +// Service Group Table - Read +// ========================== +extern SmServiceGroupT* sm_service_group_table_read( + char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Read By Identifier +// ======================================== +extern SmServiceGroupT* sm_service_group_table_read_by_id( + int64_t service_group_id ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Read By Notification Pid +// ============================================== +extern SmServiceGroupT* sm_service_group_table_read_by_notification_pid( + int pid ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - For Each +// ============================== +extern void sm_service_group_table_foreach( void* user_data[], + SmServiceGroupTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Load +// ========================== +extern SmErrorT sm_service_group_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Persist +// ============================= +extern SmErrorT sm_service_group_table_persist( SmServiceGroupT* service_group ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Initialize +// ================================ +extern SmErrorT sm_service_group_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Group Table - Finalize +// ============================== +extern SmErrorT sm_service_group_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_GROUP_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_heartbeat.c b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat.c new file mode 100644 index 00000000..83e7f2b7 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat.c @@ -0,0 +1,570 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_heartbeat.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_selobj.h" +#include "sm_db.h" +#include "sm_db_service_heartbeat.h" +#include "sm_service_heartbeat_api.h" + +static SmDbHandleT* _sm_db_handle = NULL; +static SmServiceHeartbeatCallbacksT _hb_callbacks; + +// **************************************************************************** +// Service Heartbeat - Create Unix Socket +// ====================================== +static SmErrorT sm_service_heartbeat_create_unix_socket( + SmDbServiceHeartbeatT* service_heartbeat, int* socket_fd ) +{ + int sock; + socklen_t len; + struct sockaddr_un src_addr; + int result; + + memset( &src_addr, 0, sizeof(src_addr) ); + + src_addr.sun_family = AF_UNIX; + snprintf( src_addr.sun_path, sizeof(src_addr.sun_path), "%s", + service_heartbeat->src_address ); + + sock = socket( AF_LOCAL, SOCK_DGRAM, 0 ); + if( 0 > sock ) + { + DPRINTFE( "Failed to create socket for service (%s), error=%s.", + service_heartbeat->name, strerror( errno ) ); + return( SM_FAILED ); + } + + unlink( src_addr.sun_path ); + + len = strlen( src_addr.sun_path) + sizeof(src_addr.sun_family); + + result = bind( sock, (struct sockaddr *) &src_addr, len ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind address (%s) to socket for service (%s), " + "error=%s.", src_addr.sun_path, service_heartbeat->name, + strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + *socket_fd = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Create UDP Socket +// ====================================== +static SmErrorT sm_service_heartbeat_create_udp_socket( + SmDbServiceHeartbeatT* service_heartbeat, int* socket_fd ) +{ + int sock; + struct sockaddr_in src_addr; + int result; + + memset( &src_addr, 0, sizeof(src_addr) ); + + src_addr.sin_family = AF_INET; + src_addr.sin_port = htons(service_heartbeat->src_port); + src_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + sock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); + if( 0 > sock ) + { + DPRINTFE( "Failed to create socket for service (%s), error=%s.", + service_heartbeat->name, strerror( errno ) ); + return( SM_FAILED ); + } + + result = bind( sock, (struct sockaddr *) &src_addr, sizeof(src_addr) ); + if( 0 > result ) + { + DPRINTFE( "Failed to bind address to socket for service (%s), " + "error=%s.", service_heartbeat->name, strerror( errno ) ); + close( sock ); + return( SM_FAILED ); + } + + *socket_fd = sock; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Create Socket +// ================================= +static SmErrorT sm_service_heartbeat_create_socket( + SmDbServiceHeartbeatT* service_heartbeat, int* socket_fd ) +{ + if( SM_SERVICE_HEARTBEAT_TYPE_UNIX == service_heartbeat->type ) + { + return( sm_service_heartbeat_create_unix_socket( service_heartbeat, + socket_fd ) ); + } + else if( SM_SERVICE_HEARTBEAT_TYPE_UDP == service_heartbeat->type ) + { + return( sm_service_heartbeat_create_udp_socket( service_heartbeat, + socket_fd ) ); + } else { + DPRINTFE( "Unknown heartbeat type (%s).", + sm_service_heartbeat_type_str(service_heartbeat->type) ); + return( SM_FAILED ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Timer +// ========================= +static bool sm_service_heartbeat_timer( SmTimerIdT timer_id, int64_t user_data ) +{ + int64_t id = user_data; + SmDbServiceHeartbeatT service_heartbeat; + SmErrorT error; + + error = sm_db_service_heartbeat_read_by_id( _sm_db_handle, id, + &service_heartbeat ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Not service heartbeat required for service." ); + return( false ); + } else { + DPRINTFE( "Failed to loop over service heartbeat, error=%s.", + sm_error_str( error ) ); + return( true ); + } + } + + if( timer_id != service_heartbeat.heartbeat_timer_id ) + { + DPRINTFI( "Timer mismatch for service (%s).", service_heartbeat.name ); + return( false ); + } + + if( SM_SERVICE_HEARTBEAT_STATE_STARTED != service_heartbeat.state ) + { + DPRINTFI( "Service (%s) heartbeat in the stopped state.", + service_heartbeat.name ); + return( false ); + } + + service_heartbeat.missed++; + + if(( service_heartbeat.missed > service_heartbeat.missed_fail )&& + ( 0 != service_heartbeat.missed_fail )) + { + error = sm_service_heartbeat_api_fail_heartbeat( service_heartbeat.name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send failure message for service (%s), " + "error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + } + + } else if(( service_heartbeat.missed > service_heartbeat.missed_degrade )&& + ( 0 != service_heartbeat.missed_degrade )) + { + error = sm_service_heartbeat_api_degrade_heartbeat( service_heartbeat.name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send degrade message for service (%s), " + "error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + } + + } else if(( service_heartbeat.missed > service_heartbeat.missed_warn )&& + ( 0 != service_heartbeat.missed_warn )) + { + error = sm_service_heartbeat_api_warn_heartbeat( service_heartbeat.name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send warning message for service (%s), " + "error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + } + } else { + error = sm_service_heartbeat_api_okay_heartbeat( service_heartbeat.name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to send okay message for service (%s), " + "error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + } + } + + error = sm_db_service_heartbeat_update( _sm_db_handle, &service_heartbeat ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update service heartbeat information for " + "service (%s), error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + abort(); + } + + if( SM_SERVICE_HEARTBEAT_TYPE_UNIX == service_heartbeat.type ) + { + struct sockaddr_un dst_addr; + + memset( &dst_addr, 0, sizeof(dst_addr) ); + + dst_addr.sun_family = AF_UNIX; + snprintf( dst_addr.sun_path, sizeof(dst_addr.sun_path), "%s", + service_heartbeat.dst_address ); + + if( 0 > sendto( service_heartbeat.heartbeat_socket, + service_heartbeat.message, + strlen(service_heartbeat.message)+1, 0, + (struct sockaddr*) &dst_addr, sizeof(dst_addr) ) ) + { + DPRINTFE( "Failed to send service heartbeat for service (%s), " + " error=%s", service_heartbeat.name, strerror( errno ) ); + } + + } else if( SM_SERVICE_HEARTBEAT_TYPE_UDP == service_heartbeat.type ) { + struct sockaddr_in dst_addr; + + memset( &dst_addr, 0, sizeof(dst_addr) ); + + dst_addr.sin_family = AF_INET; + dst_addr.sin_port = htons(service_heartbeat.dst_port); + dst_addr.sin_addr.s_addr = htonl(INADDR_ANY); + + if( 0 > sendto( service_heartbeat.heartbeat_socket, + service_heartbeat.message, + strlen(service_heartbeat.message)+1, 0, + (struct sockaddr*) &dst_addr, sizeof(dst_addr) ) ) + { + DPRINTFE( "Failed to send service heartbeat for service (%s), " + " error=%s", service_heartbeat.name, strerror( errno ) ); + } + + } else { + DPRINTFE( "Unknown heartbeat type (%s).", + sm_service_heartbeat_type_str(service_heartbeat.type) ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Dispatch +// ============================ +static void sm_service_heartbeat_dispatch( int selobj, int64_t user_data ) +{ + int bytes_read; + char msg[SM_SERVICE_HEARTBEAT_MESSAGE_MAX_CHAR] = {0}; + int64_t id = user_data; + SmDbServiceHeartbeatT service_heartbeat; + SmErrorT error; + + error = sm_db_service_heartbeat_read_by_id( _sm_db_handle, id, + &service_heartbeat ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Not service heartbeat required." ); + + error = sm_selobj_deregister( selobj ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + close( selobj ); + + } else { + DPRINTFE( "Failed to loop over service heartbeat, error=%s.", + sm_error_str( error ) ); + } + return; + } + + if( selobj != service_heartbeat.heartbeat_socket ) + { + DPRINTFI( "Selection object mismatch for service (%s).", + service_heartbeat.name ); + + error = sm_selobj_deregister( selobj ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + return; + } + + close( selobj ); + return; + } + + int retry_count; + for( retry_count = 5; retry_count != 0; --retry_count ) + { + bytes_read = recv( selobj, &msg, sizeof(msg), 0 ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFD( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_count, strerror( errno ) ); + } + + service_heartbeat.missed = 0; + + error = sm_db_service_heartbeat_update( _sm_db_handle, &service_heartbeat ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update service heartbeat information for " + "service (%s), error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Start Callback +// ================================== +static void sm_service_heartbeat_start_callback( char service_name[] ) +{ + char timer_name[80] = ""; + int socket_fd; + SmTimerIdT timer_id; + SmDbServiceHeartbeatT service_heartbeat; + SmErrorT error; + + DPRINTFD( "Service (%s) heartbeat start callback.", service_name ); + + error = sm_db_service_heartbeat_read( _sm_db_handle, service_name, + &service_heartbeat ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Not service heartbeat required for service (%s).", + service_name ); + } else { + DPRINTFE( "Failed to loop over service (%s) dependencies, " + "error=%s.", service_name, sm_error_str( error ) ); + } + return; + } + + if( SM_SERVICE_HEARTBEAT_STATE_STARTED == service_heartbeat.state ) + { + DPRINTFD( "Service (%s) heartbeat already started.", + service_heartbeat.name ); + return; + } + + error = sm_service_heartbeat_create_socket( &service_heartbeat, + &socket_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create heartbeat socket for service (%s), " + "error=%s.", service_name, sm_error_str( error ) ); + return; + } + + error = sm_selobj_register( socket_fd, sm_service_heartbeat_dispatch, + service_heartbeat.id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + close( socket_fd ); + return; + } + + snprintf( timer_name, sizeof(timer_name), "%s heartbeat", + service_name ); + + error = sm_timer_register( timer_name, service_heartbeat.interval_in_ms, + sm_service_heartbeat_timer, + service_heartbeat.id, &timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service heartbeat timer for service (%s), " + "error=%s.", service_heartbeat.name, sm_error_str( error ) ); + close( socket_fd ); + return; + } + + service_heartbeat.state = SM_SERVICE_HEARTBEAT_STATE_STARTED; + service_heartbeat.heartbeat_timer_id = timer_id; + service_heartbeat.heartbeat_socket = socket_fd; + service_heartbeat.missed = 0; + + error = sm_db_service_heartbeat_update( _sm_db_handle, &service_heartbeat ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update service heartbeat information for " + "service (%s), error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Stop Callback +// ================================= +static void sm_service_heartbeat_stop_callback( char service_name[] ) +{ + SmDbServiceHeartbeatT service_heartbeat; + SmErrorT error; + + DPRINTFD( "Service (%s) heartbeat stop callback.", service_name ); + + error = sm_db_service_heartbeat_read( _sm_db_handle, service_name, + &service_heartbeat ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Not service heartbeat required for service (%s).", + service_name ); + } else { + DPRINTFE( "Failed to loop over service (%s) dependencies, " + "error=%s.", service_name, sm_error_str( error ) ); + } + return; + } + + if( -1 < service_heartbeat.heartbeat_socket ) + { + error = sm_selobj_deregister( service_heartbeat.heartbeat_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + close( service_heartbeat.heartbeat_socket ); + } + + if( SM_TIMER_ID_INVALID != service_heartbeat.heartbeat_timer_id ) + { + error = sm_timer_deregister( service_heartbeat.heartbeat_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to delete service heartbeat timer for " + "service (%s), error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + } + } + + service_heartbeat.state = SM_SERVICE_HEARTBEAT_STATE_STOPPED; + service_heartbeat.heartbeat_timer_id = SM_TIMER_ID_INVALID; + service_heartbeat.heartbeat_socket = -1; + service_heartbeat.missed = 0; + + error = sm_db_service_heartbeat_update( _sm_db_handle, &service_heartbeat ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update service heartbeat information for " + "service (%s), error=%s.", service_heartbeat.name, + sm_error_str( error ) ); + abort(); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Initialize +// ============================== +SmErrorT sm_service_heartbeat_initialize( void ) +{ + SmErrorT error; + + error = sm_db_connect( SM_HEARTBEAT_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + memset( &_hb_callbacks, 0, sizeof(_hb_callbacks) ); + + _hb_callbacks.start_callback = sm_service_heartbeat_start_callback; + _hb_callbacks.stop_callback = sm_service_heartbeat_stop_callback; + + error = sm_service_heartbeat_api_register_callbacks( &_hb_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register service heartbeat callbacks, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Finalize +// ============================ +SmErrorT sm_service_heartbeat_finalize( void ) +{ + SmErrorT error; + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + error = sm_service_heartbeat_api_deregister_callbacks( &_hb_callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister service heartbeat callbacks, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + memset( &_hb_callbacks, 0, sizeof(_hb_callbacks) ); + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_heartbeat.h b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat.h new file mode 100644 index 00000000..2520a466 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat.h @@ -0,0 +1,31 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_HEARTBEAT_H__ +#define __SM_SERVICE_HEARTBEAT_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Heartbeat - Initialize +// ============================== +extern SmErrorT sm_service_heartbeat_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat - Finalize +// ============================ +extern SmErrorT sm_service_heartbeat_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_HEARTBEAT_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_api.c b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_api.c new file mode 100644 index 00000000..5de6fb6d --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_api.c @@ -0,0 +1,488 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_heartbeat_api.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_selobj.h" +#include "sm_timer.h" + +typedef enum +{ + SM_SERVICE_HEARTBEAT_MSG_TYPE_UNKNOWN, + SM_SERVICE_HEARTBEAT_MSG_TYPE_START, + SM_SERVICE_HEARTBEAT_MSG_TYPE_STOP, + SM_SERVICE_HEARTBEAT_MSG_TYPE_OKAY, + SM_SERVICE_HEARTBEAT_MSG_TYPE_WARN, + SM_SERVICE_HEARTBEAT_MSG_TYPE_DEGRADE, + SM_SERVICE_HEARTBEAT_MSG_TYPE_FAIL, + SM_SERVICE_HEARTBEAT_MSG_TYPE_MAX, +} SmServiceHeartbeatApiMsgTypeT; + +typedef struct +{ + char service_name[SM_SERVICE_NAME_MAX_CHAR]; +} SmServiceHeartbeatApiMsgStartT; + +typedef struct +{ + char service_name[SM_SERVICE_NAME_MAX_CHAR]; +} SmServiceHeartbeatApiMsgStopT; + +typedef struct +{ + char service_name[SM_SERVICE_NAME_MAX_CHAR]; +} SmServiceHeartbeatApiMsgOkayT; + +typedef struct +{ + char service_name[SM_SERVICE_NAME_MAX_CHAR]; +} SmServiceHeartbeatApiMsgWarnT; + +typedef struct +{ + char service_name[SM_SERVICE_NAME_MAX_CHAR]; +} SmServiceHeartbeatApiMsgDegradeT; + +typedef struct +{ + char service_name[SM_SERVICE_NAME_MAX_CHAR]; +} SmServiceHeartbeatApiMsgFailT; + +typedef struct +{ + SmServiceHeartbeatApiMsgTypeT msg_type; + union + { + SmServiceHeartbeatApiMsgStartT start; + SmServiceHeartbeatApiMsgStopT stop; + SmServiceHeartbeatApiMsgOkayT okay; + SmServiceHeartbeatApiMsgWarnT warn; + SmServiceHeartbeatApiMsgDegradeT degrade; + SmServiceHeartbeatApiMsgFailT fail; + } u; +} SmServiceHeartbeatApiMsgT; + +static int _sm_heartbeat_api_server_fd = -1; +static int _sm_heartbeat_api_client_fd = -1; +static SmListT* _callbacks = NULL; +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; + +// **************************************************************************** +// Service Heartbeat API - Register Callbacks +// ========================================== +SmErrorT sm_service_heartbeat_api_register_callbacks( + SmServiceHeartbeatCallbacksT* callbacks ) +{ + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + SM_LIST_PREPEND( _callbacks, (SmListEntryDataPtrT) callbacks ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Deregister Callbacks +// ============================================ +SmErrorT sm_service_heartbeat_api_deregister_callbacks( + SmServiceHeartbeatCallbacksT* callbacks ) +{ + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + SM_LIST_REMOVE( _callbacks, (SmListEntryDataPtrT) callbacks ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Start Heartbeat +// ======================================= +SmErrorT sm_service_heartbeat_api_start_heartbeat( char service_name[] ) +{ + SmServiceHeartbeatApiMsgT msg; + SmServiceHeartbeatApiMsgStartT* start_msg = &(msg.u.start); + + memset( &msg, 0, sizeof(msg) ); + msg.msg_type = SM_SERVICE_HEARTBEAT_MSG_TYPE_START; + snprintf( start_msg->service_name, sizeof(start_msg->service_name), + "%s", service_name ); + + if( 0 > send( _sm_heartbeat_api_server_fd, &msg, sizeof(msg), 0 ) ) + { + DPRINTFE( "Failed to signal service heartbeat for service (%s) to " + "start, error=%s", service_name, strerror( errno ) ); + return( SM_FAILED ); + } + + DPRINTFD( "Heartbeat start called for service (%s).", service_name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Stop Heartbeat +// ====================================== +SmErrorT sm_service_heartbeat_api_stop_heartbeat( char service_name[] ) +{ + SmServiceHeartbeatApiMsgT msg; + SmServiceHeartbeatApiMsgStopT* stop_msg = &(msg.u.stop); + + memset( &msg, 0, sizeof(msg) ); + msg.msg_type = SM_SERVICE_HEARTBEAT_MSG_TYPE_STOP; + snprintf( stop_msg->service_name, sizeof(stop_msg->service_name), + "%s", service_name ); + + if( 0 > send( _sm_heartbeat_api_server_fd, &msg, sizeof(msg), 0 ) ) + { + DPRINTFE( "Failed to signal service heartbeat for service (%s) to " + "stop, error=%s", service_name, strerror( errno ) ); + return( SM_FAILED ); + } + + DPRINTFD( "Heartbeat stop called for service (%s).", service_name ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Okay Heartbeat +// ====================================== +SmErrorT sm_service_heartbeat_api_okay_heartbeat( char service_name[] ) +{ + SmServiceHeartbeatApiMsgT msg; + SmServiceHeartbeatApiMsgOkayT* okay_msg = &(msg.u.okay); + + memset( &msg, 0, sizeof(msg) ); + msg.msg_type = SM_SERVICE_HEARTBEAT_MSG_TYPE_OKAY; + snprintf( okay_msg->service_name, sizeof(okay_msg->service_name), + "%s", service_name ); + + if( 0 > send( _sm_heartbeat_api_client_fd, &msg, sizeof(msg), 0 ) ) + { + DPRINTFE( "Failed to send service heartbeat okay for service (%s), " + "error=%s", service_name, strerror( errno ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Warn Heartbeat +// ====================================== +SmErrorT sm_service_heartbeat_api_warn_heartbeat( char service_name[] ) +{ + SmServiceHeartbeatApiMsgT msg; + SmServiceHeartbeatApiMsgWarnT* warn_msg = &(msg.u.warn); + + memset( &msg, 0, sizeof(msg) ); + msg.msg_type = SM_SERVICE_HEARTBEAT_MSG_TYPE_WARN; + snprintf( warn_msg->service_name, sizeof(warn_msg->service_name), + "%s", service_name ); + + if( 0 > send( _sm_heartbeat_api_client_fd, &msg, sizeof(msg), 0 ) ) + { + DPRINTFE( "Failed to send service heartbeat warning for service (%s), " + "error=%s", service_name, strerror( errno ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Degrade Heartbeat +// ========================================= +SmErrorT sm_service_heartbeat_api_degrade_heartbeat( char service_name[] ) +{ + SmServiceHeartbeatApiMsgT msg; + SmServiceHeartbeatApiMsgDegradeT* degrade_msg = &(msg.u.degrade); + + memset( &msg, 0, sizeof(msg) ); + msg.msg_type = SM_SERVICE_HEARTBEAT_MSG_TYPE_DEGRADE; + snprintf( degrade_msg->service_name, sizeof(degrade_msg->service_name), + "%s", service_name ); + + if( 0 > send( _sm_heartbeat_api_client_fd, &msg, sizeof(msg), 0 ) ) + { + DPRINTFE( "Failed to send service heartbeat degrade for service (%s), " + "error=%s", service_name, strerror( errno ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Fail Heartbeat +// ====================================== +SmErrorT sm_service_heartbeat_api_fail_heartbeat( char service_name[] ) +{ + SmServiceHeartbeatApiMsgT msg; + SmServiceHeartbeatApiMsgFailT* fail_msg = &(msg.u.fail); + + memset( &msg, 0, sizeof(msg) ); + msg.msg_type = SM_SERVICE_HEARTBEAT_MSG_TYPE_FAIL; + snprintf( fail_msg->service_name, sizeof(fail_msg->service_name), + "%s", service_name ); + + if( 0 > send( _sm_heartbeat_api_client_fd, &msg, sizeof(msg), 0 ) ) + { + DPRINTFE( "Failed to send service heartbeat failure for service (%s), " + "error=%s", service_name, strerror( errno ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Dispatch +// ================================ +static void sm_service_heartbeat_api_dispatch( int selobj, int64_t user_data ) +{ + int bytes_read; + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceHeartbeatCallbacksT* callbacks; + + SmServiceHeartbeatApiMsgT msg; + + int retry_count; + for( retry_count = 5; retry_count != 0; --retry_count ) + { + bytes_read = recv( selobj, &msg, sizeof(msg), 0 ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + + DPRINTFE( "Interrupted while receiving message, retry=%d, errno=%s.", + retry_count, strerror( errno ) ); + } + + if( bytes_read != sizeof(msg) ) + { + DPRINTFE( "Message truncated, bytes_read=%i, expected=%i", + bytes_read, (int) sizeof(msg) ); + return; + } + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return; + } + + SM_LIST_FOREACH( _callbacks, entry, entry_data ) + { + callbacks = (SmServiceHeartbeatCallbacksT*) entry_data; + + switch( msg.msg_type ) + { + case SM_SERVICE_HEARTBEAT_MSG_TYPE_START: + if( NULL != callbacks->start_callback ) + { + callbacks->start_callback( msg.u.start.service_name ); + } + break; + + case SM_SERVICE_HEARTBEAT_MSG_TYPE_STOP: + if( NULL != callbacks->stop_callback ) + { + callbacks->stop_callback( msg.u.stop.service_name ); + } + break; + + case SM_SERVICE_HEARTBEAT_MSG_TYPE_OKAY: + if( NULL != callbacks->okay_callback ) + { + callbacks->okay_callback( msg.u.okay.service_name ); + } + break; + + case SM_SERVICE_HEARTBEAT_MSG_TYPE_WARN: + if( NULL != callbacks->warn_callback ) + { + callbacks->warn_callback( msg.u.warn.service_name ); + } + break; + + case SM_SERVICE_HEARTBEAT_MSG_TYPE_DEGRADE: + if( NULL != callbacks->degrade_callback ) + { + callbacks->degrade_callback( msg.u.degrade.service_name ); + } + break; + + case SM_SERVICE_HEARTBEAT_MSG_TYPE_FAIL: + if( NULL != callbacks->fail_callback ) + { + callbacks->fail_callback( msg.u.fail.service_name ); + } + break; + + default: + DPRINTFE( "Unknown message type (%i) received.", + msg.msg_type ); + break; + } + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Initialize +// ================================== +SmErrorT sm_service_heartbeat_api_initialize( bool main_process ) +{ + SmErrorT error; + + if( main_process ) + { + int flags; + int sockets[2]; + int result; + + result = socketpair( AF_UNIX, SOCK_DGRAM, 0, sockets ); + if( 0 > result ) + { + DPRINTFE( "Failed to create communication service heartbeat " + "sockets, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + int socket_i; + for( socket_i=0; socket_i < 2; ++socket_i ) + { + flags = fcntl( sockets[socket_i], F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get service heartbeat socket (%i) flags, " + "error=%s.", socket_i, strerror( errno ) ); + return( SM_FAILED ); + } + + result = fcntl( sockets[socket_i], F_SETFL, flags | O_NONBLOCK ); + if( 0 > result ) + { + DPRINTFE( "Failed to set service heartbeat socket (%i) to " + "non-blocking, error=%s.", socket_i, + strerror( errno ) ); + return( SM_FAILED ); + } + } + + _sm_heartbeat_api_server_fd = sockets[0]; + _sm_heartbeat_api_client_fd = sockets[1]; + + error = sm_selobj_register( _sm_heartbeat_api_client_fd, + sm_service_heartbeat_api_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + } else { + error = sm_selobj_register( _sm_heartbeat_api_server_fd, + sm_service_heartbeat_api_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Finialize +// ================================= +SmErrorT sm_service_heartbeat_api_finalize( bool main_process ) +{ + SmErrorT error; + + if( main_process ) + { + if( -1 < _sm_heartbeat_api_client_fd ) + { + error = sm_selobj_deregister( _sm_heartbeat_api_client_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + } + } else { + if( -1 < _sm_heartbeat_api_server_fd ) + { + error = sm_selobj_deregister( _sm_heartbeat_api_server_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + } + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_api.h b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_api.h new file mode 100644 index 00000000..8afd0eba --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_api.h @@ -0,0 +1,100 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_HEARTBEAT_API_H__ +#define __SM_SERVICE_HEARTBEAT_API_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmServiceHeartbeatStartCallbackT) (char service_name[] ); +typedef void (*SmServiceHeartbeatStopCallbackT) (char service_name[] ); +typedef void (*SmServiceHeartbeatOkayCallbackT) (char service_name[] ); +typedef void (*SmServiceHeartbeatWarnCallbackT) (char service_name[] ); +typedef void (*SmServiceHeartbeatDegradeCallbackT) (char service_name[] ); +typedef void (*SmServiceHeartbeatFailCallbackT) (char service_name[] ); + +typedef struct +{ + SmServiceHeartbeatStartCallbackT start_callback; + SmServiceHeartbeatStopCallbackT stop_callback; + SmServiceHeartbeatOkayCallbackT okay_callback; + SmServiceHeartbeatWarnCallbackT warn_callback; + SmServiceHeartbeatDegradeCallbackT degrade_callback; + SmServiceHeartbeatFailCallbackT fail_callback; +} SmServiceHeartbeatCallbacksT; + +// **************************************************************************** +// Service Heartbeat API - Register Callbacks +// ========================================== +extern SmErrorT sm_service_heartbeat_api_register_callbacks( + SmServiceHeartbeatCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Deregister Callbacks +// ============================================ +extern SmErrorT sm_service_heartbeat_api_deregister_callbacks( + SmServiceHeartbeatCallbacksT* callbacks ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Start Heartbeat +// ======================================= +extern SmErrorT sm_service_heartbeat_api_start_heartbeat( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Stop Heartbeat +// ====================================== +extern SmErrorT sm_service_heartbeat_api_stop_heartbeat( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Okay Heartbeat +// ====================================== +extern SmErrorT sm_service_heartbeat_api_okay_heartbeat( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Warn Heartbeat +// ====================================== +extern SmErrorT sm_service_heartbeat_api_warn_heartbeat( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Degrade Heartbeat +// ========================================= +extern SmErrorT sm_service_heartbeat_api_degrade_heartbeat( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Fail Heartbeat +// ====================================== +extern SmErrorT sm_service_heartbeat_api_fail_heartbeat( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Initialize +// ================================== +extern SmErrorT sm_service_heartbeat_api_initialize( bool main_process ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat API - Finialize +// ================================= +extern SmErrorT sm_service_heartbeat_api_finalize( bool main_process ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_HEARTBEAT_API_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_thread.c b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_thread.c new file mode 100644 index 00000000..598e48ee --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_thread.c @@ -0,0 +1,290 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_heartbeat_thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_time.h" +#include "sm_debug.h" +#include "sm_trap.h" +#include "sm_utils.h" +#include "sm_selobj.h" +#include "sm_timer.h" +#include "sm_thread_health.h" +#include "sm_db.h" +#include "sm_db_service_heartbeat.h" +#include "sm_service_heartbeat_api.h" +#include "sm_service_heartbeat.h" + +#define SM_SERVICE_HEARTBEAT_THREAD_NAME "sm_service_hb" +#define SM_SERVICE_HEARTBEAT_TICK_INTERVAL_IN_MS 100 + +static sig_atomic_t _stay_on = 1; +static bool _thread_created = false; +static pthread_t _heartbeat_thread; + +// **************************************************************************** +// Service Heartbeat Thread - Initialize Thread +// ============================================ +SmErrorT sm_service_heartbeat_thread_initialize_thread( void ) +{ + SmErrorT error; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_initialize( SM_SERVICE_HEARTBEAT_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_db_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize database module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_heartbeat_api_initialize( false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service heartbeat api module, " + "error=%s.", sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_db_service_heartbeat_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service heartbeat database module, " + "error=%s.", sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_service_heartbeat_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service heartbeat module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat Thread - Finalize Thread +// ========================================== +SmErrorT sm_service_heartbeat_thread_finalize_thread( void ) +{ + SmErrorT error; + + error = sm_service_heartbeat_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service heartbeat module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_db_service_heartbeat_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service heartbeat database module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_service_heartbeat_api_finalize( false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize service heartbeat api module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_db_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize database module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize timer module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat Thread - Main +// =============================== +static void* sm_service_heartbeat_thread_main( void* arguments ) +{ + SmErrorT error; + + pthread_setname_np( pthread_self(), SM_SERVICE_HEARTBEAT_THREAD_NAME ); + sm_debug_set_thread_info(); + sm_trap_set_thread_info(); + + DPRINTFI( "Starting" ); + + // Warn after 1 second, fail after 3 seconds. + error = sm_thread_health_register( SM_SERVICE_HEARTBEAT_THREAD_NAME, + 1000, 3000 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register service heartbeat thread, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + error = sm_service_heartbeat_thread_initialize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Service heartbeat thread initialize failed, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + DPRINTFI( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_SERVICE_HEARTBEAT_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + + error = sm_thread_health_update( SM_SERVICE_HEARTBEAT_THREAD_NAME ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update service heartbeat thread health, " + "error=%s.", sm_error_str(error) ); + } + } + + DPRINTFI( "Shutting down." ); + + error = sm_service_heartbeat_thread_finalize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Service heartbeat finalize thread failed, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat Thread - Start +// ================================ +SmErrorT sm_service_heartbeat_thread_start( void ) +{ + int result; + + _stay_on = 1; + _thread_created = false; + + result = pthread_create( &_heartbeat_thread, NULL, + sm_service_heartbeat_thread_main, NULL ); + if( 0 != result ) + { + DPRINTFE( "Failed to start service heartbeat thread, error=%s.", + strerror(result) ); + return( SM_FAILED ); + } + + _thread_created = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat Thread - Stop +// =============================== +SmErrorT sm_service_heartbeat_thread_stop( void ) +{ + _stay_on = 0; + + if( _thread_created ) + { + long ms_expired; + SmTimeT time_prev; + int result; + + sm_time_get( &time_prev ); + + while( true ) + { + result = pthread_tryjoin_np( _heartbeat_thread, NULL ); + if(( 0 != result )&&( EBUSY != result )) + { + if(( ESRCH != result )&&( EINVAL != result )) + { + DPRINTFE( "Failed to wait for service heartbeat thread " + "exit, sending kill signal, error=%s.", + strerror(result) ); + pthread_kill( _heartbeat_thread, SIGKILL ); + } + break; + } + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( 5000 <= ms_expired ) + { + DPRINTFE( "Failed to stop service heartbeat thread, sending " + "kill signal." ); + pthread_kill( _heartbeat_thread, SIGKILL ); + break; + } + + usleep( 250000 ); // 250 milliseconds. + } + } + + _thread_created = false; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_thread.h b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_thread.h new file mode 100644 index 00000000..5e7f76b0 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_heartbeat_thread.h @@ -0,0 +1,33 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_HEARTBEAT_THREAD_H__ +#define __SM_SERVICE_HEARTBEAT_THREAD_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Heartbeat Thread - Start +// ================================ +extern SmErrorT sm_service_heartbeat_thread_start( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Heartbeat Thread - Stop +// =============================== +extern SmErrorT sm_service_heartbeat_thread_stop( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_HEARTBEAT_THREAD_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_initial_state.c b/service-mgmt/sm-1.0.0/src/sm_service_initial_state.c new file mode 100644 index 00000000..c87ee7c6 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_initial_state.c @@ -0,0 +1,105 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_initial_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_fsm.h" +#include "sm_service_audit.h" + +// **************************************************************************** +// Service Initial State - Entry +// ============================= +SmErrorT sm_service_initial_state_entry( SmServiceT* service ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Exit +// ============================ +SmErrorT sm_service_initial_state_exit( SmServiceT* service ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Transition +// ================================== +SmErrorT sm_service_initial_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Event Handler +// ===================================== +SmErrorT sm_service_initial_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_AUDIT: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_UNKNOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), " + "error=%s.", service->name, + sm_service_state_str( SM_SERVICE_STATE_UNKNOWN ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Initialize +// ================================== +SmErrorT sm_service_initial_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Finalize +// ================================ +SmErrorT sm_service_initial_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_initial_state.h b/service-mgmt/sm-1.0.0/src/sm_service_initial_state.h new file mode 100644 index 00000000..a5866d36 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_initial_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_INITIAL_STATE_H__ +#define __SM_SERVICE_INITIAL_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Initial State - Entry +// ============================= +extern SmErrorT sm_service_initial_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Exit +// ============================ +extern SmErrorT sm_service_initial_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Transition +// ================================== +extern SmErrorT sm_service_initial_state_transition( SmServiceT* service, + SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Event Handler +// ===================================== +extern SmErrorT sm_service_initial_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Initialize +// ================================== +extern SmErrorT sm_service_initial_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Initial State - Finalize +// ================================ +extern SmErrorT sm_service_initial_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_INITIAL_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_shutdown_state.c b/service-mgmt/sm-1.0.0/src/sm_service_shutdown_state.c new file mode 100644 index 00000000..f20c09b2 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_shutdown_state.c @@ -0,0 +1,77 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_shutdown_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_fsm.h" +#include "sm_service_audit.h" + +// **************************************************************************** +// Service Shutdown State - Entry +// ============================== +SmErrorT sm_service_shutdown_state_entry( SmServiceT* service ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Exit +// ============================= +SmErrorT sm_service_shutdown_state_exit( SmServiceT* service ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Transition +// =================================== +SmErrorT sm_service_shutdown_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Event Handler +// ====================================== +SmErrorT sm_service_shutdown_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + switch( event ) + { + default: + DPRINTFD( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Initialize +// =================================== +SmErrorT sm_service_shutdown_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Finalize +// ================================= +SmErrorT sm_service_shutdown_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_shutdown_state.h b/service-mgmt/sm-1.0.0/src/sm_service_shutdown_state.h new file mode 100644 index 00000000..2083381b --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_shutdown_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_SHUTDOWN_STATE_H__ +#define __SM_SERVICE_SHUTDOWN_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Shutdown State - Entry +// ============================== +extern SmErrorT sm_service_shutdown_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Exit +// ============================= +extern SmErrorT sm_service_shutdown_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Transition +// =================================== +extern SmErrorT sm_service_shutdown_state_transition( SmServiceT* service, + SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Event Handler +// ====================================== +extern SmErrorT sm_service_shutdown_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Initialize +// =================================== +extern SmErrorT sm_service_shutdown_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Shutdown State - Finalize +// ================================= +extern SmErrorT sm_service_shutdown_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_SHUTDOWN_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_table.c b/service-mgmt/sm-1.0.0/src/sm_service_table.c new file mode 100644 index 00000000..cb23dbd6 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_table.c @@ -0,0 +1,406 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_table.h" + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" +#include "sm_db.h" +#include "sm_db_foreach.h" +#include "sm_db_services.h" +#include "sm_db_service_instances.h" +#include "sm_service_enable.h" +#include "sm_service_disable.h" +#include "sm_service_go_active.h" +#include "sm_service_go_standby.h" +#include "sm_service_audit.h" + +static SmListT* _services = NULL; +static SmDbHandleT* _sm_db_handle = NULL; + +// **************************************************************************** +// Service Table - Read +// ==================== +SmServiceT* sm_service_table_read( char service_name[] ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceT* service; + + SM_LIST_FOREACH( _services, entry, entry_data ) + { + service = (SmServiceT*) entry_data; + + if( 0 == strcmp( service_name, service->name ) ) + { + return( service ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - Read By Identifier +// ================================== +SmServiceT* sm_service_table_read_by_id( int64_t service_id ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceT* service; + + SM_LIST_FOREACH( _services, entry, entry_data ) + { + service = (SmServiceT*) entry_data; + + if( service_id == service->id ) + { + return( service ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - Read By Pid +// =========================== +SmServiceT* sm_service_table_read_by_pid( int pid ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceT* service; + + SM_LIST_FOREACH( _services, entry, entry_data ) + { + service = (SmServiceT*) entry_data; + + if( pid == service->pid ) + { + return( service ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - Read By Action Pid +// ================================== +SmServiceT* sm_service_table_read_by_action_pid( int pid ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmServiceT* service; + + SM_LIST_FOREACH( _services, entry, entry_data ) + { + service = (SmServiceT*) entry_data; + + if( pid == service->action_pid ) + { + return( service ); + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - For Each +// ======================== +void sm_service_table_foreach( void* user_data[], + SmServiceTableForEachCallbackT callback ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + + SM_LIST_FOREACH( _services, entry, entry_data ) + { + callback( user_data, (SmServiceT*) entry_data ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - Add +// =================== +static SmErrorT sm_service_table_add( void* user_data[], void* record ) +{ + SmServiceT* service; + SmDbServiceT* db_service = (SmDbServiceT*) record; + SmDbServiceInstanceT db_service_instance; + SmErrorT error; + + error = sm_db_service_instances_read( _sm_db_handle, db_service->name, + &db_service_instance ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read instance for service (%s), error=%s.", + db_service->name, sm_error_str( error ) ); + return( error ); + } + + service = sm_service_table_read( db_service->name ); + if( NULL == service ) + { + service = (SmServiceT*) malloc( sizeof(SmServiceT) ); + if( NULL == service ) + { + DPRINTFE( "Failed to allocate service table entry." ); + return( SM_FAILED ); + } + + memset( service, 0, sizeof(SmServiceT) ); + + service->id = db_service->id; + snprintf( service->name, sizeof(service->name), "%s", + db_service->name ); + snprintf( service->instance_name, sizeof(service->instance_name), + "%s", db_service_instance.instance_name ); + snprintf( service->instance_params, sizeof(service->instance_params), + "%s", db_service_instance.instance_params ); + service->desired_state = db_service->desired_state; + service->state = db_service->state; + service->status = db_service->status; + service->condition = db_service->condition; + service->recover = false; + service->clear_fatal_condition = false; + service->max_failures = db_service->max_failures; + service->fail_count = 0; + service->fail_countdown = db_service->fail_countdown; + service->fail_countdown_interval_in_ms + = db_service->fail_countdown_interval_in_ms; + service->fail_countdown_timer_id = SM_TIMER_ID_INVALID; + service->audit_timer_id = SM_TIMER_ID_INVALID; + service->action_running = SM_SERVICE_ACTION_NONE; + service->action_pid = -1; + service->action_timer_id = SM_TIMER_ID_INVALID; + service->action_attempts = 0; + service->action_state_timer_id = SM_TIMER_ID_INVALID; + service->pid = -1; + snprintf( service->pid_file, sizeof(service->pid_file), "%s", + db_service->pid_file ); + service->pid_file_audit_timer_id = SM_TIMER_ID_INVALID; + service->action_fail_count = 0; + service->max_action_failures = db_service->max_action_failures; + service->transition_fail_count = 0; + service->max_transition_failures = db_service->max_transition_failures; + + error = sm_service_go_active_exists( service, + &service->go_active_action_exists ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if go-active action for " + "service (%s) exists, error=%s.", service->name, + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_go_standby_exists( service, + &service->go_standby_action_exists ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if go-standby action for service " + "(%s) exists, error=%s.", service->name, + sm_error_str( error ) ); + free( service ); + return( error ); + } + + error = sm_service_enable_exists( service, + &service->enable_action_exists ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if enable action for service " + "(%s) exists, error=%s.", service->name, + sm_error_str( error ) ); + return( error ); + } + + error = sm_service_disable_exists( service, + &service->disable_action_exists ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if disable action for service " + "(%s) exists, error=%s.", service->name, + sm_error_str( error ) ); + free( service ); + return( error ); + } + + error = sm_service_audit_enabled_exists( service, + &service->audit_enabled_exists ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if audit enabled action for " + "service (%s) exists, error=%s.", service->name, + sm_error_str( error ) ); + free( service ); + return( error ); + } + + error = sm_service_audit_disabled_exists( service, + &service->audit_disabled_exists ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to determine if audit disabled action for " + "service (%s) exists, error=%s.", service->name, + sm_error_str( error ) ); + free( service ); + return( error ); + } + + service->disable_check_dependency = true; + service->disable_skip_dependent = false; + + SM_LIST_PREPEND( _services, (SmListEntryDataPtrT) service ); + + } else { + service->id = db_service->id; + snprintf( service->instance_name, sizeof(service->instance_name), + "%s", db_service_instance.instance_name ); + snprintf( service->instance_params, sizeof(service->instance_params), + "%s", db_service_instance.instance_params ); + service->max_failures = db_service->max_failures; + service->fail_countdown = db_service->fail_countdown; + service->fail_countdown_interval_in_ms + = db_service->fail_countdown_interval_in_ms; + service->max_action_failures = db_service->max_action_failures; + service->max_transition_failures = db_service->max_transition_failures; + snprintf( service->pid_file, sizeof(service->pid_file), "%s", + db_service->pid_file ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - Load +// ==================== +SmErrorT sm_service_table_load( void ) +{ + char db_query[SM_DB_QUERY_STATEMENT_MAX_CHAR]; + SmDbServiceT service; + SmErrorT error; + + snprintf( db_query, sizeof(db_query), "%s = 'yes'", + SM_SERVICES_TABLE_COLUMN_PROVISIONED ); + + error = sm_db_foreach( SM_DATABASE_NAME, SM_SERVICES_TABLE_NAME, + db_query, &service, sm_db_services_convert, + sm_service_table_add, NULL ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to loop over services in database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - Persist +// ======================= +SmErrorT sm_service_table_persist( SmServiceT* service ) +{ + SmDbServiceT db_service; + SmErrorT error; + + memset( &db_service, 0, sizeof(db_service) ); + + db_service.id = service->id; + snprintf( db_service.name, sizeof(db_service.name), "%s", service->name ); + db_service.desired_state = service->desired_state; + db_service.state = service->state; + db_service.status = service->status; + db_service.condition = service->condition; + db_service.max_failures = service->max_failures; + db_service.fail_countdown = service->fail_countdown; + db_service.fail_countdown_interval_in_ms + = service->fail_countdown_interval_in_ms; + db_service.max_action_failures = service->max_action_failures; + db_service.max_transition_failures = service->max_transition_failures; + snprintf( db_service.pid_file, sizeof(db_service.pid_file), "%s", + service->pid_file ); + + error = sm_db_services_update( _sm_db_handle, &db_service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to update database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - Initialize +// ========================== +SmErrorT sm_service_table_initialize( void ) +{ + SmErrorT error; + + _services = NULL; + + error = sm_db_connect( SM_DATABASE_NAME, &_sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + return( error ); + } + + error = sm_service_table_load(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load services from database, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Table - Finalize +// ======================== +SmErrorT sm_service_table_finalize( void ) +{ + SmErrorT error; + + SM_LIST_CLEANUP_ALL( _services ); + + if( NULL != _sm_db_handle ) + { + error = sm_db_disconnect( _sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database (%s), error=%s.", + SM_DATABASE_NAME, sm_error_str( error ) ); + } + + _sm_db_handle = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_table.h b/service-mgmt/sm-1.0.0/src/sm_service_table.h new file mode 100644 index 00000000..3049f264 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_table.h @@ -0,0 +1,123 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_TABLE_H__ +#define __SM_SERVICE_TABLE_H__ + +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_timer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + int64_t id; + char name[SM_SERVICE_NAME_MAX_CHAR]; + char instance_name[SM_SERVICE_INSTANCE_NAME_MAX_CHAR]; + char instance_params[SM_SERVICE_INSTANCE_PARAMS_MAX_CHAR]; + SmServiceStateT desired_state; + SmServiceStateT state; + SmServiceStatusT status; + SmServiceConditionT condition; + bool recover; + bool clear_fatal_condition; + int max_failures; + int fail_count; + int fail_countdown; + int fail_countdown_interval_in_ms; + SmTimerIdT fail_countdown_timer_id; + SmTimerIdT audit_timer_id; + SmServiceActionT action_running; + int action_pid; + SmTimerIdT action_timer_id; + int action_attempts; + SmTimerIdT action_state_timer_id; + int pid; + char pid_file[SM_SERVICE_PID_FILE_MAX_CHAR]; + SmTimerIdT pid_file_audit_timer_id; + int action_fail_count; + int max_action_failures; + int transition_fail_count; + int max_transition_failures; + bool go_active_action_exists; + bool go_standby_action_exists; + bool enable_action_exists; + bool disable_action_exists; + bool audit_enabled_exists; + bool audit_disabled_exists; + bool disable_check_dependency; + //flag to indicate disable a service without disabling its dependency + bool disable_skip_dependent; +} SmServiceT; + +typedef void (*SmServiceTableForEachCallbackT) + (void* user_data[], SmServiceT* service); + +// **************************************************************************** +// Service Table - Read +// ==================== +extern SmServiceT* sm_service_table_read( char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Table - Read By Identifier +// ================================== +extern SmServiceT* sm_service_table_read_by_id( int64_t service_id ); +// **************************************************************************** + +// **************************************************************************** +// Service Table - Read By Pid +// =========================== +extern SmServiceT* sm_service_table_read_by_pid( int pid ); +// **************************************************************************** + +// **************************************************************************** +// Service Table - Read By Action Pid +// ================================== +extern SmServiceT* sm_service_table_read_by_action_pid( int pid ); +// **************************************************************************** + +// **************************************************************************** +// Service Table - For Each +// ======================== +extern void sm_service_table_foreach( void* user_data[], + SmServiceTableForEachCallbackT callback ); +// **************************************************************************** + +// **************************************************************************** +// Service Table - Load +// ==================== +extern SmErrorT sm_service_table_load( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Table - Persist +// ======================= +extern SmErrorT sm_service_table_persist( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Table - Initialize +// ========================== +extern SmErrorT sm_service_table_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Table - Finalize +// ======================== +extern SmErrorT sm_service_table_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_TABLE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_service_unknown_state.c b/service-mgmt/sm-1.0.0/src/sm_service_unknown_state.c new file mode 100644 index 00000000..aa2c9171 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_unknown_state.c @@ -0,0 +1,218 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_service_unknown_state.h" + +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_service_fsm.h" +#include "sm_service_audit.h" + +// **************************************************************************** +// Service Unknown State - Entry +// ============================= +SmErrorT sm_service_unknown_state_entry( SmServiceT* service ) +{ + SmErrorT error; + + if( service->audit_enabled_exists ) + { + error = sm_service_audit_enabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } else if( service->audit_disabled_exists ) { + error = sm_service_audit_disabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + + service->action_fail_count = 0; + service->transition_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Exit +// ============================ +SmErrorT sm_service_unknown_state_exit( SmServiceT* service ) +{ + SmErrorT error; + + if( SM_SERVICE_ACTION_AUDIT_ENABLED == service->action_running ) + { + error = sm_service_audit_enabled_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + } + + if( SM_SERVICE_ACTION_AUDIT_DISABLED == service->action_running ) + { + error = sm_service_audit_disabled_abort( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to abort action (%s) of service (%s), error=%s.", + sm_service_action_str( service->action_running ), + service->name, sm_error_str( error ) ); + return( error ); + } + + } + + service->action_fail_count = 0; + service->transition_fail_count = 0; + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Transition +// ================================== +SmErrorT sm_service_unknown_state_transition( SmServiceT* service, + SmServiceStateT from_state ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Event Handler +// ===================================== +SmErrorT sm_service_unknown_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ) +{ + SmServiceStateT state; + SmErrorT error; + + switch( event ) + { + case SM_SERVICE_EVENT_AUDIT: + if(( service->audit_enabled_exists )&& + ( SM_SERVICE_ACTION_AUDIT_ENABLED != service->action_running )) + { + error = sm_service_audit_enabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + + if(( service->audit_disabled_exists )&& + ( !service->audit_enabled_exists )&& + ( SM_SERVICE_ACTION_AUDIT_DISABLED != service->action_running )) + { + error = sm_service_audit_disabled( service ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to audit service (%s), error=%s", + service->name, sm_error_str( error ) ); + return( error ); + } + } + + if( service->transition_fail_count >= service->max_transition_failures ) + { + if( SM_SERVICE_CONDITION_FATAL_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_FATAL_FAILURE; + + DPRINTFI( "Service (%s) is unknown and has reached max " + "transition failures (%i).", service->name, + service->max_transition_failures ); + } + } + else if( service->action_fail_count >= service->max_action_failures ) + { + if( SM_SERVICE_CONDITION_ACTION_FAILURE != service->condition ) + { + service->status = SM_SERVICE_STATUS_FAILED; + service->condition = SM_SERVICE_CONDITION_ACTION_FAILURE; + + DPRINTFI( "Service (%s) is unknown and has reached max " + "action failures (%i).", service->name, + service->max_action_failures ); + } + } + break; + + case SM_SERVICE_EVENT_AUDIT_SUCCESS: + state = *(SmServiceStateT*) + event_data[SM_SERVICE_EVENT_DATA_STATE]; + + error = sm_service_fsm_set_state( service, state ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, sm_service_state_str( state ), + sm_error_str( error ) ); + return( error ); + } + break; + + case SM_SERVICE_EVENT_AUDIT_FAILED: + case SM_SERVICE_EVENT_AUDIT_TIMEOUT: + // Service engine will run the audit action again. + ++(service->action_fail_count); + ++(service->transition_fail_count); + break; + + case SM_SERVICE_EVENT_SHUTDOWN: + error = sm_service_fsm_set_state( service, + SM_SERVICE_STATE_SHUTDOWN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set service (%s) state (%s), error=%s.", + service->name, + sm_service_state_str(SM_SERVICE_STATE_SHUTDOWN), + sm_error_str( error ) ); + return( error ); + } + break; + + default: + DPRINTFD( "Service (%s) ignoring event (%s).", service->name, + sm_service_event_str( event ) ); + break; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Initialize +// ================================== +SmErrorT sm_service_unknown_state_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Finalize +// ================================ +SmErrorT sm_service_unknown_state_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_service_unknown_state.h b/service-mgmt/sm-1.0.0/src/sm_service_unknown_state.h new file mode 100644 index 00000000..af70e2b2 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_service_unknown_state.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SERVICE_UNKNOWN_STATE_H__ +#define __SM_SERVICE_UNKNOWN_STATE_H__ + +#include "sm_types.h" +#include "sm_service_table.h" +#include "sm_service_fsm.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Service Unknown State - Entry +// ============================= +extern SmErrorT sm_service_unknown_state_entry( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Exit +// ============================ +extern SmErrorT sm_service_unknown_state_exit( SmServiceT* service ); +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Transition +// ================================== +extern SmErrorT sm_service_unknown_state_transition( SmServiceT* service, + SmServiceStateT from_state ); +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Event Handler +// ===================================== +extern SmErrorT sm_service_unknown_state_event_handler( SmServiceT* service, + SmServiceEventT event, void* event_data[] ); +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Initialize +// ================================== +extern SmErrorT sm_service_unknown_state_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Service Unknown State - Finalize +// ================================ +extern SmErrorT sm_service_unknown_state_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SERVICE_UNKNOWN_STATE_H__ diff --git a/service-mgmt/sm-1.0.0/src/sm_swact_state.c b/service-mgmt/sm-1.0.0/src/sm_swact_state.c new file mode 100644 index 00000000..787696ce --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_swact_state.c @@ -0,0 +1,28 @@ +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_swact_state.h" +#include "pthread.h" + +volatile SmSwactStateT _swact_state = SM_SWACT_STATE_NONE; +static pthread_mutex_t _state_mutex; + +// **************************************************************************** +// Swact State - Swact State Setter +// ============================================ +void sm_set_swact_state(SmSwactStateT state) +{ + // The state is set by sm main thread and task affining thread. + pthread_mutex_lock(&_state_mutex); + _swact_state = state; + pthread_mutex_unlock(&_state_mutex); +} + +// **************************************************************************** +// Swact State - Swact State Getter +// ============================================ +SmSwactStateT sm_get_swact_state( void ) +{ + return _swact_state; +} diff --git a/service-mgmt/sm-1.0.0/src/sm_swact_state.h b/service-mgmt/sm-1.0.0/src/sm_swact_state.h new file mode 100644 index 00000000..c35e3632 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_swact_state.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SWACT_STATE_H__ +#define __SM_SWACT_STATE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + SM_SWACT_STATE_NONE, + SM_SWACT_STATE_START, + SM_SWACT_STATE_END, +} SmSwactStateT; + +// **************************************************************************** +// Swact State - Setter +// ========================================== +// **************************************************************************** +extern void sm_set_swact_state( SmSwactStateT state ); + +// **************************************************************************** +// Swact State - Getter +// ========================================== +extern SmSwactStateT sm_get_swact_state( void ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/service-mgmt/sm-1.0.0/src/sm_task_affining_thread.c b/service-mgmt/sm-1.0.0/src/sm_task_affining_thread.c new file mode 100644 index 00000000..af93829e --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_task_affining_thread.c @@ -0,0 +1,232 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_task_affining_thread.h" +#include "sm_swact_state.h" +#include "sm_time.h" +#include "sm_debug.h" +#include "sm_trap.h" +#include "sm_selobj.h" +#include "sm_thread_health.h" +#include "sm_timer.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +static const char sm_task_affining_thread_name[] = "sm_ta"; +static const int sm_task_affining_tick_interval_in_ms = 500; + +static sig_atomic_t _stay_on = 1; +static bool _thread_created = false; +static pthread_t _task_affining_thread; + +// **************************************************************************** +// Task Affining Thread - Affine Tasks +// ============================================ +void affine_tasks( void ) +{ + switch (sm_get_swact_state()) + { + case SM_SWACT_STATE_START: + DPRINTFI("Invoking system call, affining to idle cores..."); + system("source /etc/init.d/task_affinity_functions.sh; affine_tasks_to_idle_cores 2>/dev/null"); + DPRINTFI("Done affining tasks to idle cores, set state to none"); + sm_set_swact_state( SM_SWACT_STATE_NONE ); + return; + case SM_SWACT_STATE_END: + DPRINTFI("Invoking system call, affining to platform cores..."); + system("source /etc/init.d/task_affinity_functions.sh; affine_tasks_to_platform_cores 2>/dev/null"); + DPRINTFI("Done affining tasks to platform cores, set state to none"); + sm_set_swact_state( SM_SWACT_STATE_NONE ); + return; + default: + // SM_SWACT_STATE_NONE and everything else... + return; + } +} + +// **************************************************************************** +// Task Affining Thread - Initialize Thread +// ============================================ +SmErrorT sm_task_affining_thread_initialize_thread( void ) +{ + SmErrorT error; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_initialize( sm_task_affining_tick_interval_in_ms ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + + +// **************************************************************************** +// Task Affining Thread - Finalize Thread +// ========================================== +SmErrorT sm_task_affining_thread_finalize_thread( void ) +{ + SmErrorT error; + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize timer module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + + +// **************************************************************************** +// Task Affining Thread - Main +// =============================== +static void* sm_task_affining_thread_main( void* arguments ) +{ + SmErrorT error; + + pthread_setname_np( pthread_self(), sm_task_affining_thread_name ); + sm_debug_set_thread_info(); + sm_trap_set_thread_info(); + + DPRINTFI( "Starting" ); + + error = sm_task_affining_thread_initialize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Task affining thread initialization failed, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + DPRINTFI( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( sm_task_affining_tick_interval_in_ms ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + affine_tasks(); + } + + DPRINTFI( "Shutting down." ); + + error = sm_task_affining_thread_finalize_thread(); + if( SM_OKAY != error ) + { + DPRINTFE( "Task affining thread finalization failed, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Task Affining Thread - Start +// ================================ +SmErrorT sm_task_affining_thread_start( void ) +{ + int result; + + _stay_on = 1; + _thread_created = false; + + result = pthread_create( &_task_affining_thread, NULL, + sm_task_affining_thread_main, NULL ); + if( 0 != result ) + { + DPRINTFE( "Failed to start task affining thread, error=%s.", + strerror(result) ); + return( SM_FAILED ); + } + + _thread_created = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Task Affining Thread - Stop +// =============================== +SmErrorT sm_task_affining_thread_stop( void ) +{ + _stay_on = 0; + + if( _thread_created ) + { + long ms_expired; + SmTimeT time_prev; + int result; + + sm_time_get( &time_prev ); + + while( true ) + { + result = pthread_tryjoin_np( _task_affining_thread, NULL ); + if(( 0 != result )&&( EBUSY != result )) + { + if(( ESRCH != result )&&( EINVAL != result )) + { + DPRINTFE( "Failed to wait for task affining thread " + "exit, sending kill signal, error=%s.", + strerror(result) ); + pthread_kill( _task_affining_thread, SIGKILL ); + } + break; + } + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( 12000 <= ms_expired ) + { + DPRINTFE( "Failed to stop task affining thread, sending " + "kill signal." ); + pthread_kill( _task_affining_thread, SIGKILL ); + break; + } + + usleep( 250000 ); // 250 milliseconds. + } + } + + _thread_created = false; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_task_affining_thread.h b/service-mgmt/sm-1.0.0/src/sm_task_affining_thread.h new file mode 100644 index 00000000..88e512ca --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_task_affining_thread.h @@ -0,0 +1,31 @@ +// +// Copyright (c) 2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_TASK_AFFINING_THREAD_H__ +#define __SM_TASK_AFFINING_THREAD_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Task Affining Thread - Start +// ================================ +extern SmErrorT sm_task_affining_thread_start( void ); +// **************************************************************************** + +// **************************************************************************** +// Task Affining Thread - Stop +// =============================== +extern SmErrorT sm_task_affining_thread_stop( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/service-mgmt/sm-1.0.0/src/sm_troubleshoot.c b/service-mgmt/sm-1.0.0/src/sm_troubleshoot.c new file mode 100644 index 00000000..5e319a52 --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_troubleshoot.c @@ -0,0 +1,153 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_troubleshoot.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_debug.h" +#include "sm_timer.h" +#include "sm_msg.h" +#include "sm_failover.h" +#include "sm_service_domain_neighbor_fsm.h" +#include "sm_service_domain_fsm.h" + +#define SM_TROUBLESHOOT_NAME "sm_troubleshoot" + +extern void sm_service_domain_interface_dump_state(FILE* fp); +// **************************************************************************** +// Troubleshoot - Dump Data +// ======================== +SmErrorT sm_troubleshoot_dump_data( const char reason[] ) +{ + pid_t pid; + + pid = fork(); + if( 0 > pid ) + { + DPRINTFE( "Failed to fork process for troubleshoot data dump," + "error=%s.", strerror( errno ) ); + return( SM_FAILED ); + + } else if( 0 == pid ) { + // Child process. + FILE* log = NULL; + struct rlimit file_limits; + int result; + + result = prctl( PR_SET_NAME, SM_TROUBLESHOOT_NAME ); + if( 0 > result ) + { + printf( "Failed to set troubleshoot process name, error=%s.\n", + strerror(errno) ); + exit( EXIT_FAILURE ); + } + + result = prctl( PR_SET_PDEATHSIG, SIGTERM ); + if( 0 > result ) + { + printf( "Failed to set troubleshoot parent death signal, " + "error=%s.\n", strerror(errno) ); + exit( EXIT_FAILURE ); + } + + if( 0 > getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + printf( "Failed to get file limits, error=%s.", + strerror( errno ) ); + exit( EXIT_FAILURE ); + } + + unsigned int fd_i; + for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i ) + { + close( fd_i ); + } + + if( 0 > open( "/dev/null", O_RDONLY ) ) + { + printf( "Failed to open stdin to /dev/null, error=%s.\n", + strerror( errno ) ); + } + + if( 0 > open( "/dev/null", O_WRONLY ) ) + { + printf( "Failed to open stdout to /dev/null, error=%s.\n", + strerror( errno ) ); + } + + if( 0 > open( "/dev/null", O_WRONLY ) ) + { + printf( "Failed to open stderr to /dev/null, error=%s.\n", + strerror( errno ) ); + } + + log = fopen( SM_TROUBLESHOOT_LOG_FILE, "a" ); + if( NULL != log ) + { + char time_str[80]; + char date_str[32]; + struct tm t_real; + struct timespec ts_real; + + clock_gettime( CLOCK_REALTIME, &(ts_real) ); + + if( NULL == localtime_r( &(ts_real.tv_sec), &t_real ) ) + { + snprintf( time_str, sizeof(time_str), "YYYY:MM:DD HH:MM:SS.xxx" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + snprintf( time_str, sizeof(time_str), "%s.%03ld", date_str, + ts_real.tv_nsec/1000000 ); + } + + fprintf( log, "====================================================================\n" ); + fprintf( log, "dump-reason: %s\n", reason ); + fprintf( log, "dump-started-at: %s\n\n", time_str ); + + sm_failover_dump_state( log ); fprintf( log, "\n" ); + sm_service_domain_dump_state( log ); fprintf( log, "\n" ); + sm_service_domain_interface_dump_state( log ); fprintf( log, "\n" ); + sm_domain_neighbor_fsm_dump( log ); + sm_timer_dump_data( log ); fprintf( log, "\n" ); + sm_msg_dump_data( log ); fprintf( log, "\n" ); + + fflush( log ); + fclose( log ); + } + + if( 0 == access( SM_TROUBLESHOOT_SCRIPT, F_OK | X_OK ) ) + { + char cmd[80]; + + snprintf( cmd, sizeof(cmd), "%s %s", SM_TROUBLESHOOT_SCRIPT, + SM_TROUBLESHOOT_LOG_FILE ); + system( cmd ); + } + + exit( EXIT_SUCCESS ); + + } else { + // Parent process. + DPRINTFI( "Troubleshoot process (%i) created.", (int) pid ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-1.0.0/src/sm_troubleshoot.h b/service-mgmt/sm-1.0.0/src/sm_troubleshoot.h new file mode 100644 index 00000000..bf3938ee --- /dev/null +++ b/service-mgmt/sm-1.0.0/src/sm_troubleshoot.h @@ -0,0 +1,26 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_TROUBLESHOOT_H__ +#define __SM_TROUBLESHOOT_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Troubleshoot - Dump Data +// ======================== +extern SmErrorT sm_troubleshoot_dump_data( const char reason[] ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_TROUBLESHOOT_H__ + diff --git a/service-mgmt/sm-common-1.0.0/LICENSE b/service-mgmt/sm-common-1.0.0/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/service-mgmt/sm-common-1.0.0/Makefile b/service-mgmt/sm-common-1.0.0/Makefile new file mode 100644 index 00000000..cdd9bba0 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +build: + @(cd src; make build VER=$(VER) VER_MJR=$(VER_MJR)) + +install_non_bb: + @(cd src; make DEST_DIR=$(DEST_DIR) BIN_DIR=$(BIN_DIR) LIB_DIR=$(LIB_DIR) INC_DIR=$(INC_DIR) VER=$(VER) VER_MJR=$(VER_MJR) install_non_bb) + @(cd scripts; make DEST_DIR=$(DEST_DIR) UNIT_DIR=$(UNIT_DIR) install_non_bb) + +clean: + @( cd src; make clean ) diff --git a/service-mgmt/sm-common-1.0.0/centos/build_srpm.data b/service-mgmt/sm-common-1.0.0/centos/build_srpm.data new file mode 100644 index 00000000..857d6ad4 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/centos/build_srpm.data @@ -0,0 +1,2 @@ +SRC_DIR=$PKG_BASE +TIS_PATCH_VER=19 diff --git a/service-mgmt/sm-common-1.0.0/centos/sm-common.spec b/service-mgmt/sm-common-1.0.0/centos/sm-common.spec new file mode 100644 index 00000000..f76ecfe0 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/centos/sm-common.spec @@ -0,0 +1,168 @@ +Summary: Service Management Common +Name: sm-common +Version: 1.0.0 +Release: %{tis_patch_ver}%{?_tis_dist} +License: Apache-2.0 +Group: base +Packager: Wind River +URL: unknown +Source0: %{name}-%{version}.tar.gz + + +BuildRequires: build-info-dev +BuildRequires: glib2-devel +BuildRequires: sqlite-devel +BuildRequires: gcc +BuildRequires: util-linux +BuildRequires: libuuid-devel + +Requires: cgts-mtce-common-pmon +Requires: /bin/sh +Requires: sqlite +Requires: util-linux +Requires: systemd +# BuildRequires is to get %_unitdir I think +BuildRequires: systemd +BuildRequires: systemd-devel +Requires(post): systemd +Requires: %{name}-libs = %{version}-%{release} + +%description +Service Managment Common + +#%package -n sm-common-dbg +#Summary: Service Management Common - Debugging files +#Group: devel +##Suggests: libsqlite3-dbg +##Suggests: libgcc-s-dbg(x86_64) +##Suggests: libglib-2.0-dbg(x86_64) +##Suggests: lmapi-dbg +##Suggests: libstdc++-dbg(x86_64) +##Suggests: libc6-dbg(x86_64) +##Suggests: util-linux-libuuid-dbg +##Recommends: sm-common = 1.0.0-r7.0 +#Provides: sm-common-dbg(x86_64) = 1.0.0-r7.0 + +#%description -n sm-common-dbg +#Service Managment Common This package contains ELF symbols and related +#sources for debugging purposes. + +%package libs +Summary: Service Management Common - shared library fles +Group: base +#Provides: sm-common-libs(x86_64) = 1.0.0-r7.0 + +%description libs +Service Managment Common This package contains shared libraries. + +%package dev +Summary: Service Management Common - Development files +Group: devel +Requires: %{name}-libs = %{version}-%{release} + +%description dev +Service Managment Common This package contains symbolic links, header +files, and related items necessary for software development. + +%package -n sm-eru +Summary: Service Management ERU +Group: base +Requires: %{name}-libs = %{version}-%{release} + +%description -n sm-eru +Service Managment ERU. + +%prep +%autosetup + +%build +VER=%{version} + +MAJOR=`echo $VER | awk -F . '{print $1}'` +MINOR=`echo $VER | awk -F . '{print $2}'` +make VER=${VER} VER_MJR=$MAJOR %{?_smp_mflags} + +%global _buildsubdir %{_builddir}/%{name}-%{version} + +%install +rm -rf $RPM_BUILD_ROOT +VER=%{version} +MAJOR=`echo $VER | awk -F . '{print $1}'` +MINOR=`echo $VER | awk -F . '{print $2}'` +make DEST_DIR=$RPM_BUILD_ROOT BIN_DIR=%{_bindir} UNIT_DIR=%{_unitdir} LIB_DIR=%{_libdir} INC_DIR=%{_includedir} VER=$VER VER_MJR=$MAJOR install_non_bb + +install -m 750 -d %{buildroot}/usr +install -m 750 -d %{buildroot}/usr/bin +install -m 750 -p -D %{_buildsubdir}/src/sm_eru %{buildroot}%{_bindir}/sm-eru +install -m 750 -p -D %{_buildsubdir}/src/sm_eru_dump %{buildroot}%{_bindir}/sm-eru-dump +install -m 750 -p -D %{_buildsubdir}/src/sm_watchdog %{buildroot}%{_bindir}/sm-watchdog + +install -m 644 -p -D %{_buildsubdir}/scripts/sm-eru.service %{buildroot}%{_unitdir}/sm-eru.service +install -m 644 -p -D %{_buildsubdir}/scripts/sm-watchdog.service %{buildroot}%{_unitdir}/sm-watchdog.service + +install -m 750 -d %{buildroot}%{_sysconfdir}/pmon.d +install -m 640 -p -D %{_buildsubdir}/scripts/sm-eru.conf %{buildroot}%{_sysconfdir}/pmon.d/sm-eru.conf +install -m 640 -p -D %{_buildsubdir}/scripts/sm-watchdog.conf %{buildroot}%{_sysconfdir}/pmon.d/sm-watchdog.conf + +install -m 750 -p -D %{_buildsubdir}/scripts/sm-eru %{buildroot}%{_sysconfdir}/init.d/sm-eru +install -m 750 -p -D %{_buildsubdir}/scripts/sm-watchdog %{buildroot}%{_sysconfdir}/init.d/sm-watchdog + +%post +/usr/bin/systemctl enable sm-watchdog.service >/dev/null 2>&1 + +%post -n sm-eru +/usr/bin/systemctl enable sm-eru.service >/dev/null 2>&1 + + +%files +%license LICENSE +%defattr(-,root,root,-) +/etc/init.d/sm-watchdog +/etc/pmon.d/sm-watchdog.conf +/usr/bin/sm-watchdog +/usr/lib/systemd/system/sm-watchdog.service + +#%{_unitdir}/* +#%{_bindir}/* +#/etc/init.d/* +#/etc/pmon.d/* + +%files libs +%{_libdir}/*.so.* +%dir "/var/lib/sm" +%dir "/var/lib/sm/watchdog" +%dir "/var/lib/sm/watchdog/modules" +/var/lib/sm/watchdog/modules/*.so.* + +%files -n sm-eru +%defattr(-,root,root,-) +/etc/init.d/sm-eru +/etc/pmon.d/sm-eru.conf +/usr/bin/sm-eru +/usr/bin/sm-eru-dump +/usr/lib/systemd/system/sm-eru.service + + +# Commented out for now, but something seems to auto generate +# a sm-common-debuginfo RPM even without this. +#%files -n sm-common-dbg +#%defattr(-,-,-,-) +#%dir "/usr/lib64/.debug" +#"/usr/lib64/.debug/libsm_common.so.1.0.0" +#%dir "/usr/bin/.debug" +#"/usr/bin/.debug/sm-eru-dump" +#"/usr/bin/.debug/sm-watchdog" +#"/usr/bin/.debug/sm-eru" +#%dir "/usr/src/debug/sm-common" +#%dir "/usr/src/debug/sm-common/1.0.0-r7" +#%dir "/usr/src/debug/sm-common/1.0.0-r7/src" +#/usr/src/debug/sm-common/1.0.0-r7/src/*.h +#/usr/src/debug/sm-common/1.0.0-r7/src/*.c +#%dir "/var/lib/sm/watchdog/modules/.debug" +#"/var/lib/sm/watchdog/modules/.debug/libsm_watchdog_nfs.so.1.0.0" + +%files dev +%defattr(-,root,root,-) +%{_includedir}/* +%{_libdir}/*.so +/var/lib/sm/watchdog/modules/libsm_watchdog_nfs.so diff --git a/service-mgmt/sm-common-1.0.0/scripts/Makefile b/service-mgmt/sm-common-1.0.0/scripts/Makefile new file mode 100644 index 00000000..c1427199 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/scripts/Makefile @@ -0,0 +1,8 @@ +install_non_bb: + install -d $(DEST_DIR)$(UNIT_DIR) + install -m 644 *.service $(DEST_DIR)$(UNIT_DIR) + install -d $(DEST_DIR)/etc/init.d + install sm-watchdog sm-eru $(DEST_DIR)/etc/init.d + install -d $(DEST_DIR)/etc/pmon.d + install *.conf $(DEST_DIR)/etc/pmon.d + diff --git a/service-mgmt/sm-common-1.0.0/scripts/sm-eru b/service-mgmt/sm-common-1.0.0/scripts/sm-eru new file mode 100755 index 00000000..64f99ff1 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/scripts/sm-eru @@ -0,0 +1,131 @@ +#! /bin/sh +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# chkconfig: - 86 86 +# processname: sm-eru +# description: Service Management Event Recorder Unit +# +### BEGIN INIT INFO +# Description: sm-eru +# +# Short-Description: Service Management Event Recorder Unit +# Provides: sm-eru +# Required-Start: $network +# Should-Start: $syslog +# Required-Stop: $network +# Default-Start: 3 5 +# Default-Stop: 0 6 +### END INIT INFO + +. /etc/init.d/functions + +RETVAL=0 + +SM_ERU_NAME="sm-eru" +SM_ERU="/usr/bin/${SM_ERU_NAME}" +SM_ERU_PIDFILE="/var/run/${SM_ERU_NAME}.pid" + +if [ ! -e "${SM_ERU}" ] +then + logger "${SM_ERU} is missing" + exit 5 +fi + +PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin + +case "$1" in + start) + echo -n "Starting ${SM_ERU_NAME}: " + if [ -n "`pidof ${SM_ERU}`" ] + then + # PMOND might have restarted SM-ERU already. + RETVAL=0 + else + start-stop-daemon --start -b -x ${SM_ERU} + RETVAL=$? + fi + if [ ${RETVAL} -eq 0 ] + then + echo "OK" + else + echo "FAIL" + RETVAL=1 + fi + ;; + + stop) + echo -n "Stopping ${SM_ERU_NAME}: " + if [ -n "`pidof ${SM_ERU}`" ] + then + killproc ${SM_ERU} + fi + + SHUTDOWN_TIMEOUT=5 + count=0 + while [ ${count} -lt ${SHUTDOWN_TIMEOUT} ] + do + pidof ${SM_ERU} &> /dev/null + rc=$? + if [ ${rc} -eq 1 ] + then + echo "OK" + break + fi + count=`expr ${count} + 1` + sleep 1 + done + + pidof ${SM_ERU} &> /dev/null + rc=$? + if [ ${rc} -eq 0 ] + then + echo "FAIL" + RETVAL=7 + fi + + rm -f ${SM_ERU_PIDFILE} + ;; + + status) + pid=`cat ${SM_ERU_PIDFILE} 2>/dev/null` + if [ -n "${pid}" ] + then + if ps -p ${pid} &>/dev/null + then + echo "${SM_ERU_NAME} is running" + RETVAL=0 + else + echo "${SM_ERU_NAME} is not running but has pid file" + RETVAL=1 + fi + else + echo "${SM_ERU_NAME} is not running" + RETVAL=3 + fi + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + reload) + echo "${SM_ERU_NAME} reload" + $0 restart + ;; + + force-reload) + echo "${SM_ERU_NAME} force-reload" + $0 restart + ;; + + *) + echo "usage: $0 { start | stop | status | restart | reload | force-reload }" + ;; +esac + +exit ${RETVAL} diff --git a/service-mgmt/sm-common-1.0.0/scripts/sm-eru.conf b/service-mgmt/sm-common-1.0.0/scripts/sm-eru.conf new file mode 100644 index 00000000..3daf3163 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/scripts/sm-eru.conf @@ -0,0 +1,15 @@ +; +; Copyright (c) 2014 Wind River Systems, Inc. +; +; SPDX-License-Identifier: Apache-2.0 +; +[process] +process = sm-eru +pidfile = /var/run/sm-eru.pid +script = /etc/init.d/sm-eru +style = lsb ; lsb +severity = minor ; minor, major, critical +restarts = 3 ; restarts before error assertion +startuptime = 5 ; seconds to wait after process start +interval = 5 ; number of seconds to wait between restarts +debounce = 20 ; number of seconds to wait before degrade clear diff --git a/service-mgmt/sm-common-1.0.0/scripts/sm-eru.service b/service-mgmt/sm-common-1.0.0/scripts/sm-eru.service new file mode 100644 index 00000000..0c35ffe7 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/scripts/sm-eru.service @@ -0,0 +1,15 @@ +[Unit] +Description=Service Management Event Recorder Unit +After=network-online.target syslog-ng.service sm-api.service +Before=pmon.service + +[Service] +Type=forking +RemainAfterExit=yes +User=root +ExecStart=/etc/init.d/sm-eru start +ExecStop=/etc/init.d/sm-eru stop +PIDFile=/var/run/sm-eru.pid + +[Install] +WantedBy=multi-user.target diff --git a/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog b/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog new file mode 100755 index 00000000..1588b6c0 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog @@ -0,0 +1,131 @@ +#! /bin/sh +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +# chkconfig: - 87 87 +# processname: sm-watchdog +# description: Service Management Watchdog +# +### BEGIN INIT INFO +# Description: sm-watchdog +# +# Short-Description: Service Management Watchdog +# Provides: sm-watchdog +# Required-Start: $network +# Should-Start: $syslog +# Required-Stop: $network +# Default-Start: 3 5 +# Default-Stop: 0 6 +### END INIT INFO + +. /etc/init.d/functions + +RETVAL=0 + +SM_WATCHDOG_NAME="sm-watchdog" +SM_WATCHDOG="/usr/bin/${SM_WATCHDOG_NAME}" +SM_WATCHDOG_PIDFILE="/var/run/${SM_WATCHDOG_NAME}.pid" + +if [ ! -e "${SM_WATCHDOG}" ] +then + logger "${SM_WATCHDOG} is missing" + exit 5 +fi + +PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin + +case "$1" in + start) + echo -n "Starting ${SM_WATCHDOG_NAME}: " + if [ -n "`pidof ${SM_WATCHDOG}`" ] + then + # PMOND might have restarted SM-WATCHDOG already. + RETVAL=0 + else + start-stop-daemon --start -b -x ${SM_WATCHDOG} + RETVAL=$? + fi + if [ ${RETVAL} -eq 0 ] + then + echo "OK" + else + echo "FAIL" + RETVAL=1 + fi + ;; + + stop) + echo -n "Stopping ${SM_WATCHDOG_NAME}: " + if [ -n "`pidof ${SM_WATCHDOG}`" ] + then + killproc ${SM_WATCHDOG} + fi + + SHUTDOWN_TIMEOUT=5 + count=0 + while [ ${count} -lt ${SHUTDOWN_TIMEOUT} ] + do + pidof ${SM_WATCHDOG} &> /dev/null + rc=$? + if [ ${rc} -eq 1 ] + then + echo "OK" + break + fi + count=`expr ${count} + 1` + sleep 1 + done + + pidof ${SM_WATCHDOG} &> /dev/null + rc=$? + if [ ${rc} -eq 0 ] + then + echo "FAIL" + RETVAL=7 + fi + + rm -f ${SM_WATCHDOG_PIDFILE} + ;; + + status) + pid=`cat ${SM_WATCHDOG_PIDFILE} 2>/dev/null` + if [ -n "${pid}" ] + then + if ps -p ${pid} &>/dev/null + then + echo "${SM_WATCHDOG_NAME} is running" + RETVAL=0 + else + echo "${SM_WATCHDOG_NAME} is not running but has pid file" + RETVAL=1 + fi + else + echo "${SM_WATCHDOG_NAME} is not running" + RETVAL=3 + fi + ;; + + restart) + $0 stop + sleep 1 + $0 start + ;; + + reload) + echo "${SM_WATCHDOG_NAME} reload" + $0 restart + ;; + + force-reload) + echo "${SM_WATCHDOG_NAME} force-reload" + $0 restart + ;; + + *) + echo "usage: $0 { start | stop | status | restart | reload | force-reload }" + ;; +esac + +exit ${RETVAL} diff --git a/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog.conf b/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog.conf new file mode 100644 index 00000000..8ae37adf --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog.conf @@ -0,0 +1,15 @@ +; +; Copyright (c) 2014 Wind River Systems, Inc. +; +; SPDX-License-Identifier: Apache-2.0 +; +[process] +process = sm-watchdog +pidfile = /var/run/sm-watchdog.pid +script = /etc/init.d/sm-watchdog +style = lsb ; lsb +severity = major ; minor, major, critical +restarts = 3 ; restarts before error assertion +startuptime = 5 ; seconds to wait after process start +interval = 5 ; number of seconds to wait between restarts +debounce = 20 ; number of seconds to wait before degrade clear diff --git a/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog.service b/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog.service new file mode 100644 index 00000000..5fd147a5 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/scripts/sm-watchdog.service @@ -0,0 +1,15 @@ +[Unit] +Description=Service Management Watchdog +After=network-online.target syslog-ng.service config.service +Before=sm.service pmon.service + +[Service] +Type=forking +RemainAfterExit=yes +User=root +ExecStart=/etc/init.d/sm-watchdog start +ExecStop=/etc/init.d/sm-watchdog stop +PIDFile=/var/run/sm-watchdog.pid + +[Install] +WantedBy=multi-user.target diff --git a/service-mgmt/sm-common-1.0.0/src/Makefile b/service-mgmt/sm-common-1.0.0/src/Makefile new file mode 100644 index 00000000..cef8d325 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/Makefile @@ -0,0 +1,83 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +INCLUDES =-I$(STAGING_DIR)/usr/include/glib-2.0 +INCLUDES+=-I$(STAGING_DIR)/usr/lib64/glib-2.0/include -I. + +SRCS=sm_types.c +SRCS+=sm_debug.c +SRCS+=sm_debug_thread.c +SRCS+=sm_trap.c +SRCS+=sm_trap_thread.c +SRCS+=sm_thread_health.c +SRCS+=sm_utils.c +SRCS+=sm_node_utils.c +SRCS+=sm_node_stats.c +SRCS+=sm_selobj.c +SRCS+=sm_time.c +SRCS+=sm_timer.c +SRCS+=sm_netlink.c +SRCS+=sm_hw.c +SRCS+=sm_uuid.c +SRCS+=sm_sha512.c +SRCS+=sm_eru_db.c +SRCS+=sm_util_types.c + +OBJS = $(SRCS:.c=.o) +CCFLAGS= -fPIC -g -O2 -Wall -Werror +EXTRACCFLAGS= -D__STDC_FORMAT_MACROS -DSW_VERSION=\"$(SW_VERSION)\" + +LDLIBS= -lsqlite3 -lglib-2.0 -lgmodule-2.0 -luuid -lrt -lpthread +LDFLAGS = -shared -rdynamic + +build: libsm_common.so libsm_watchdog_nfs.so sm_watchdog sm_eru sm_eru_dump + +.c.o: + $(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) -c $< -o $@ + +libsm_common.so: libsm_common.so.$(VER_MJR) + ln -sf $^ $@ + +libsm_common.so.$(VER_MJR): libsm_common.so.$(VER) + ln -sf $^ $@ + +libsm_common.so.$(VER): ${OBJS} + $(CXX) ${LDFLAGS} $(LDLIBS) -Wl,-soname,libsm_common.so.$(VER_MJR) -o $@ $^ + +libsm_watchdog_nfs.so: libsm_watchdog_nfs.so.$(VER_MJR) + ln -sf $^ $@ + +libsm_watchdog_nfs.so.$(VER_MJR): libsm_watchdog_nfs.so.$(VER) + ln -sf $^ $@ + +libsm_watchdog_nfs.so.$(VER): libsm_common.so.$(VER) + $(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) sm_watchdog_nfs.c ${LDFLAGS} $(LDLIBS) -L./ -lsm_common -Wl,-soname,libsm_watchdog_nfs.so.$(VER_MJR) -o $@ + +sm_watchdog: libsm_common.so + $(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) $(OBJS) sm_watchdog_module.c sm_watchdog_process.c sm_watchdog_main.c $(LDLIBS) -L./ -lsm_common -o sm_watchdog + +sm_eru: libsm_common.so + $(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) $(OBJS) sm_eru_process.c sm_eru_main.c $(LDLIBS) -L./ -lsm_common -o sm_eru + +sm_eru_dump: libsm_common.so + $(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) $(OBJS) sm_eru_dump.c $(LDLIBS) -L./ -lsm_common -o sm_eru_dump + +install_non_bb: + # install of these 3 are in the .spec file so that they can be + # renamed with '-' like they are in the bitbake file. + # + # install -d $(DEST_DIR)$(BIN_DIR) + # install sm_watchdog sm_eru sm_eru_dump $(DEST_DIR)$(BIN_DIR) + install -d $(DEST_DIR)$(LIB_DIR) + install libsm_common.so.${VER} $(DEST_DIR)$(LIB_DIR) + cp -P libsm_common.so libsm_common.so.$(VER_MJR) $(DEST_DIR)$(LIB_DIR) + install -d $(DEST_DIR)$(INC_DIR) + install -m 644 *.h $(DEST_DIR)$(INC_DIR) + install -d $(DEST_DIR)/var/lib/sm/watchdog/modules + install libsm_watchdog_nfs.so.${VER} $(DEST_DIR)/var/lib/sm/watchdog/modules + cp -P libsm_watchdog_nfs.so libsm_watchdog_nfs.so.${VER_MJR} $(DEST_DIR)/var/lib/sm/watchdog/modules + +clean: + rm -f *.o *.so *.so.* diff --git a/service-mgmt/sm-common-1.0.0/src/sm_debug.c b/service-mgmt/sm-common-1.0.0/src/sm_debug.c new file mode 100644 index 00000000..93b52bdb --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_debug.c @@ -0,0 +1,409 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug_thread.h" + +typedef struct +{ + bool inuse; + uint64_t log_seqnum; + char thread_name[SM_THREAD_NAME_MAX_CHAR]; + int thread_id; + char thread_identifier[SM_THREAD_NAME_MAX_CHAR+10]; +} SmDebugThreadInfoT; + +static int _server_fd = -1; +static int _client_fd = -1; +static int _initialized; +static SmDebugLogLevelT _log_level = SM_DEBUG_LOG_LEVEL_INFO; +static SmDebugThreadInfoT _thread_info[SM_THREADS_MAX]; +static pthread_key_t _thread_key; + +#define SCHED_LOGS_MAX 128 + +typedef SmDebugThreadMsgT SmDebugSchedLogSetT[SCHED_LOGS_MAX]; + +static int _sched_log_set = 0; +static int _sched_log_num = 0; +static SmDebugSchedLogSetT _sched_logs[2]; + +// **************************************************************************** +// Debug - Log Level String +// ======================== +const char* sm_debug_log_level_str( SmDebugLogLevelT level ) +{ + switch( level ) + { + case SM_DEBUG_LOG_LEVEL_ERROR: + return( "ERROR" ); + break; + + case SM_DEBUG_LOG_LEVEL_INFO: + return( "INFO" ); + break; + + case SM_DEBUG_LOG_LEVEL_DEBUG: + return( "DEBUG" ); + break; + + case SM_DEBUG_LOG_LEVEL_VERBOSE: + return( "VERBOSE" ); + break; + + default: + return( "???" ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Set Log Level +// ===================== +void sm_debug_set_log_level( SmDebugLogLevelT level ) +{ + _log_level = level; +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Do Log +// ============== +bool sm_debug_do_log( const char* file_name, SmDebugLogLevelT level ) +{ + return( level <= _log_level ); +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Log +// =========== +void sm_debug_log( SmDebugLogTypeT type, const char* format, ... ) +{ + SmDebugThreadInfoT* info = NULL; + SmDebugThreadMsgT msg; + va_list arguments; + + memset( &msg, 0, sizeof(msg) ); + + if( !_initialized ) + { + va_start( arguments, format ); + vsnprintf( msg.u.log.data, sizeof(msg.u.log.data), format, arguments ); + va_end( arguments ); + printf( "%s\n", msg.u.log.data ); + return; + } + + info = (SmDebugThreadInfoT*) pthread_getspecific( _thread_key ); + + if( SM_DEBUG_SCHED_LOG == type ) + { + msg.type = SM_DEBUG_THREAD_MSG_SCHED_LOG; + msg.u.log.seqnum = 0; + + } else { + msg.type = SM_DEBUG_THREAD_MSG_LOG; + + if( NULL != info ) + msg.u.log.seqnum = ++(info->log_seqnum); + else + msg.u.log.seqnum = 0; + } + + clock_gettime( CLOCK_MONOTONIC_RAW, &(msg.u.log.ts_mono) ); + clock_gettime( CLOCK_REALTIME, &(msg.u.log.ts_real) ); + + va_start( arguments, format ); + vsnprintf( msg.u.log.data, sizeof(msg.u.log.data), format, arguments ); + va_end( arguments ); + + if( -1 < _client_fd ) + { + send( _client_fd, &msg, sizeof(msg), 0 ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Scheduler Log +// ===================== +void sm_debug_sched_log( SmDebugLogTypeT type, const char* format, ... ) +{ + SmDebugThreadMsgT* msg = &(_sched_logs[_sched_log_set][_sched_log_num]); + va_list arguments; + + memset( msg, 0, sizeof(SmDebugThreadMsgT) ); + + if( _initialized ) + { + msg->type = SM_DEBUG_THREAD_MSG_SCHED_LOG; + msg->u.log.seqnum = 0; + + clock_gettime( CLOCK_MONOTONIC_RAW, &(msg->u.log.ts_mono) ); + clock_gettime( CLOCK_REALTIME, &(msg->u.log.ts_real) ); + + va_start( arguments, format ); + vsnprintf( msg->u.log.data, sizeof(msg->u.log.data), format, + arguments ); + va_end( arguments ); + + if( _sched_log_num < SCHED_LOGS_MAX ) + ++_sched_log_num; + } +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Scheduler Log Start +// =========================== +void sm_debug_sched_log_start( char* domain ) +{ + if( 0 == _sched_log_set ) + { + _sched_log_set = 1; + } else { + _sched_log_set = 0; + } + + _sched_log_num = 0; + memset( &(_sched_logs[_sched_log_set][0]), 0, sizeof(SmDebugSchedLogSetT) ); +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Scheduler Log Done +// ========================== +void sm_debug_sched_log_done( char* domain ) +{ + if( -1 < _client_fd ) + { + bool changes = false; + SmDebugThreadMsgT* msg_lhs; + SmDebugThreadMsgT* msg_rhs; + + int sched_log_i; + for( sched_log_i=0; SCHED_LOGS_MAX > sched_log_i; ++sched_log_i ) + { + msg_lhs = &(_sched_logs[0][sched_log_i]); + msg_rhs = &(_sched_logs[1][sched_log_i]); + + if( 0 != memcmp( &(msg_lhs->u.log.data[0]), + &(msg_rhs->u.log.data[0]), + SM_DEBUG_THREAD_LOG_MAX_CHARS ) ) + { + changes = true; + break; + } + } + + if( changes ) + { + SmDebugThreadMsgT* msg; + + for( sched_log_i=0; _sched_log_num > sched_log_i; ++sched_log_i ) + { + if( sched_log_i >= SCHED_LOGS_MAX ) + break; + + msg = &(_sched_logs[_sched_log_set][sched_log_i]); + + send( _client_fd, msg, sizeof(SmDebugThreadMsgLogT), 0 ); + } + } else { + sm_debug_log( SM_DEBUG_SCHED_LOG, "%s: no scheduling changes " + "required.", domain ); + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Get Thread Information +// ============================== +const char* sm_debug_get_thread_info( void ) +{ + SmDebugThreadInfoT* info; + + info = (SmDebugThreadInfoT*) pthread_getspecific( _thread_key ); + + if( NULL != info ) + return( info->thread_identifier ); + + return( "unknown" ); +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Set Thread Information +// ============================== +void sm_debug_set_thread_info( void ) +{ + SmDebugThreadInfoT* info; + + int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + info = &(_thread_info[thread_i]); + if( !(info->inuse) ) + { + info->log_seqnum = 0; + pthread_getname_np( pthread_self(), info->thread_name, + sizeof(info->thread_name) ); + info->thread_id = (int) syscall(SYS_gettid); + snprintf( info->thread_identifier, sizeof(info->thread_identifier), + "%s[%i]", info->thread_name, info->thread_id ); + info->inuse = true; + + pthread_setspecific( _thread_key, info ); + break; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Initialize +// ================== +SmErrorT sm_debug_initialize( void ) +{ + int flags; + int sockets[2]; + int buffer_len = 1048576; + int result; + SmErrorT error; + + memset( _thread_info, 0, sizeof(_thread_info) ); + + pthread_key_create( &_thread_key, NULL ); + + sm_debug_set_thread_info(); + + result = socketpair( AF_UNIX, SOCK_DGRAM, 0, sockets ); + if( 0 > result ) + { + printf( "Failed to create debug communication sockets, error=%s.\n", + strerror( errno ) ); + return( SM_FAILED ); + } + + int socket_i; + for( socket_i=0; socket_i < 2; ++socket_i ) + { + flags = fcntl( sockets[socket_i] , F_GETFL, 0 ); + if( 0 > flags ) + { + printf( "Failed to get debug communication socket (%i) flags, " + "error=%s.\n", socket_i, strerror( errno ) ); + return( SM_FAILED ); + } + + result = fcntl( sockets[socket_i], F_SETFL, flags | O_NONBLOCK ); + if( 0 > result ) + { + printf( "Failed to set debug communication socket (%i) to " + "non-blocking, error=%s.\n", socket_i, + strerror( errno ) ); + return( SM_FAILED ); + } + + result = setsockopt( sockets[socket_i], SOL_SOCKET, SO_SNDBUF, + &buffer_len, sizeof(buffer_len) ); + if( 0 > result ) + { + printf( "Failed to set debug communication socket (%i) " + "send buffer length (%i), error=%s.\n", socket_i, + buffer_len, strerror( errno ) ); + return( SM_FAILED ); + } + + result = setsockopt( sockets[socket_i], SOL_SOCKET, SO_RCVBUF, + &buffer_len, sizeof(buffer_len) ); + if( 0 > result ) + { + printf( "Failed to set debug communication socket (%i) " + "receive buffer length (%i), error=%s.\n", socket_i, + buffer_len, strerror( errno ) ); + return( SM_FAILED ); + } + } + + _server_fd = sockets[0]; + _client_fd = sockets[1]; + + error = sm_debug_thread_start( _server_fd ); + if( SM_OKAY != error ) + { + printf( "Failed to start debug thread, error=%s.\n", + sm_error_str( error ) ); + return( error ); + } + + _sched_log_set = 0; + _sched_log_num = 0; + memset( _sched_logs, 0, sizeof(_sched_logs) ); + + _initialized = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Debug - Finalize +// ================ +SmErrorT sm_debug_finalize( void ) +{ + SmErrorT error; + + error = sm_debug_thread_stop(); + if( SM_OKAY != error ) + { + printf( "Failed to stop debug thread, error=%s.\n", + sm_error_str( error ) ); + } + + memset( _thread_info, 0, sizeof(_thread_info) ); + + if( -1 < _server_fd ) + { + close( _server_fd ); + _server_fd = -1; + } + + if( -1 < _client_fd ) + { + close( _client_fd ); + _client_fd = -1; + } + + _sched_log_set = 0; + _sched_log_num = 0; + memset( _sched_logs, 0, sizeof(_sched_logs) ); + + _initialized = false; + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_debug.h b/service-mgmt/sm-common-1.0.0/src/sm_debug.h new file mode 100644 index 00000000..f03e4716 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_debug.h @@ -0,0 +1,131 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DEBUG_H__ +#define __SM_DEBUG_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + SM_DEBUG_LOG, + SM_DEBUG_SCHED_LOG, +} SmDebugLogTypeT; + +typedef enum +{ + SM_DEBUG_LOG_LEVEL_ERROR, + SM_DEBUG_LOG_LEVEL_INFO, + SM_DEBUG_LOG_LEVEL_DEBUG, + SM_DEBUG_LOG_LEVEL_VERBOSE, +} SmDebugLogLevelT; + +// **************************************************************************** +// Debug - Log Level String +// ======================== +extern const char* sm_debug_log_level_str( SmDebugLogLevelT level ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Set Log Level +// ===================== +extern void sm_debug_set_log_level( SmDebugLogLevelT level ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Do Log +// ============== +extern bool sm_debug_do_log( const char* file_name, SmDebugLogLevelT level ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Log +// =========== +extern void sm_debug_log( SmDebugLogTypeT type, const char* format, ... ) +__attribute__ ((format (printf, 2, 3))); +// format string is parameter #2 and follows the printf formatting, +// variable arguments start at parameter #3 +// **************************************************************************** + +// **************************************************************************** +// Debug - Get Thread Information +// ============================== +extern const char* sm_debug_get_thread_info( void ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Set Thread Information +// ============================== +extern void sm_debug_set_thread_info( void ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Scheduler Log +// ===================== +extern void sm_debug_sched_log( SmDebugLogTypeT type, const char* format, ... ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Scheduler Log Start +// =========================== +extern void sm_debug_sched_log_start( char* domain ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Scheduler Log Done +// ========================== +extern void sm_debug_sched_log_done( char* domain ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Initialize +// ================== +extern SmErrorT sm_debug_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Debug - Finalize +// ================ +extern SmErrorT sm_debug_finalize( void ); +// **************************************************************************** + +#define DPRINTF( level, format, args... ) \ + if( sm_debug_do_log( __FILE__, level ) ) \ + sm_debug_log( SM_DEBUG_LOG, "%s: %s: %s(%i): " format, \ + sm_debug_log_level_str( level ), \ + sm_debug_get_thread_info(), \ + __FILE__, __LINE__, ##args ) + +#define DPRINTFE( format, args... ) \ + DPRINTF( SM_DEBUG_LOG_LEVEL_ERROR, format, ##args ) +#define DPRINTFI( format, args... ) \ + DPRINTF( SM_DEBUG_LOG_LEVEL_INFO, format, ##args ) +#define DPRINTFD( format, args... ) \ + DPRINTF( SM_DEBUG_LOG_LEVEL_DEBUG, format, ##args ) +#define DPRINTFV( format, args... ) \ + DPRINTF( SM_DEBUG_LOG_LEVEL_VERBOSE, format, ##args ) + +#define SCHED_LOG_START( domain, format, args... ) \ + sm_debug_sched_log_start( domain ); \ + sm_debug_sched_log( SM_DEBUG_SCHED_LOG, "%s: " format, domain, ##args ) + +#define SCHED_LOG( domain, format, args... ) \ + sm_debug_sched_log( SM_DEBUG_SCHED_LOG, "%s: " format, domain, ##args ) + +#define SCHED_LOG_DONE( domain, format, args... ) \ + sm_debug_sched_log( SM_DEBUG_SCHED_LOG, "%s: " format, domain, ##args ); \ + sm_debug_sched_log_done( domain ) + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DEBUG_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_debug_thread.c b/service-mgmt/sm-common-1.0.0/src/sm_debug_thread.c new file mode 100644 index 00000000..aa96a390 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_debug_thread.c @@ -0,0 +1,340 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_debug_thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_time.h" +#include "sm_selobj.h" +#include "sm_trap.h" + +#define SM_DEBUG_THREAD_NAME "sm_debug" +#define SM_DEBUG_THREAD_TICK_INTERVAL_IN_MS 1000 +#define SM_DEBUG_THREAD_SCHED_LOG_FILE "/var/log/sm-scheduler.log" + +#define SM_SYSLOG( format, args... ) \ + syslog( LOG_LOCAL3 | LOG_DEBUG, format "\n", ##args ) + +#define SM_WRITE_SYSLOG( format, args... ) \ + syslog( LOG_LOCAL3 | LOG_DEBUG, format "\n", ##args ) + +#define SM_WRITE_SCHEDLOG( format, args... ) \ + fprintf( _sched_log, format "\n", ##args ); \ + fflush( _sched_log ) + +static sig_atomic_t _stay_on; +static bool _thread_created = false; +static pthread_t _debug_thread; +static int _server_fd = -1; +static bool _server_fd_registered = false; +static FILE * _sched_log = NULL; + +// **************************************************************************** +// Debug Thread - Dispatch +// ======================= +static void sm_debug_thread_dispatch( int selobj, int64_t user_data ) +{ + int bytes_read; + long ms_expired; + SmTimeT time_prev, time_now; + SmDebugThreadMsgT msg; + char time_str[80]; + char date_str[32]; + struct tm t_real; + + memset( &msg, 0, sizeof(msg) ); + + int retry_count; + for( retry_count = 5; retry_count != 0; --retry_count ) + { + bytes_read = recv( selobj, &msg, sizeof(msg), 0 ); + if( 0 < bytes_read ) + { + break; + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + return; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + SM_SYSLOG( "Failed to receive message, errno=%s.", + strerror( errno ) ); + return; + } + } + + switch( msg.type ) + { + case SM_DEBUG_THREAD_MSG_LOG: + + sm_time_get( &time_prev ); + + SM_WRITE_SYSLOG( "time[%ld.%03ld] log<%"PRIu64"> %s", + (long) msg.u.log.ts_mono.tv_sec, + (long) msg.u.log.ts_mono.tv_nsec/1000000, + msg.u.log.seqnum, msg.u.log.data ); + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + + if( 1000 <= ms_expired ) + SM_SYSLOG( "Syslog logging took %li ms.", ms_expired ); + break; + + case SM_DEBUG_THREAD_MSG_SCHED_LOG: + + sm_time_get( &time_prev ); + + if( NULL == localtime_r( &(msg.u.log.ts_real.tv_sec), &t_real ) ) + { + snprintf( time_str, sizeof(time_str), + "YYYY:MM:DD HH:MM:SS.xxx" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", + &t_real ); + snprintf( time_str, sizeof(time_str), "%s.%03ld", date_str, + msg.u.log.ts_real.tv_nsec/1000000 ); + } + + SM_WRITE_SCHEDLOG( "%s sm: time[%ld.%03ld] %s", time_str, + (long) msg.u.log.ts_mono.tv_sec, + (long) msg.u.log.ts_mono.tv_nsec/1000000, + msg.u.log.data ); + + sm_time_get( &time_now ); + ms_expired = sm_time_delta_in_ms( &time_now, &time_prev ); + + if( 1000 <= ms_expired ) + SM_SYSLOG( "Scheduler logging took %li ms.", ms_expired ); + break; + + default: + SM_SYSLOG( "Unknown message (%i) received.", msg.type ); + return; + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Debug Thread - Initialize Thread +// ================================ +static SmErrorT sm_debug_thread_initialize_thread( void ) +{ + SmErrorT error; + + _server_fd_registered = false; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + SM_SYSLOG( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + if( -1 < _server_fd ) + { + error = sm_selobj_register( _server_fd, sm_debug_thread_dispatch, 0 ); + if( SM_OKAY != error ) + { + SM_SYSLOG( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + _server_fd_registered = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Debug Thread - Finalize Thread +// ============================== +static SmErrorT sm_debug_thread_finalize_thread( void ) +{ + SmErrorT error; + + if( _server_fd_registered ) + { + error = sm_selobj_deregister( _server_fd ); + if( SM_OKAY != error ) + { + SM_SYSLOG( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + _server_fd_registered = false; + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + SM_SYSLOG( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Debug Thread - Main +// =================== +static void* sm_debug_thread_main( void* arguments ) +{ + SmErrorT error; + + pthread_setname_np( pthread_self(), SM_DEBUG_THREAD_NAME ); + sm_trap_set_thread_info(); + + SM_SYSLOG( "Starting" ); + + error = sm_debug_thread_initialize_thread(); + if( SM_OKAY != error ) + { + SM_SYSLOG( "Failed to initialize debug thread, error=%s.", + sm_error_str( error ) ); + pthread_exit( NULL ); + } + + SM_SYSLOG( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_DEBUG_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + SM_SYSLOG( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + } + + SM_SYSLOG( "Shutting down." ); + + error = sm_debug_thread_finalize_thread(); + if( SM_OKAY != error ) + { + SM_SYSLOG( "Failed to finalize debug thread, error=%s.", + sm_error_str( error ) ); + } + + SM_SYSLOG( "Shutdown complete." ); + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Debug Thread - Start +// ==================== +SmErrorT sm_debug_thread_start( int server_fd ) +{ + int result; + + _stay_on = 1; + _thread_created = false; + _server_fd = server_fd; + + openlog( NULL, LOG_NDELAY, LOG_LOCAL3 ); + + _sched_log = fopen( SM_DEBUG_THREAD_SCHED_LOG_FILE, "a" ); + if( NULL == _sched_log ) + { + printf( "Failed to open scheduler log file (%s).\n", + SM_DEBUG_THREAD_SCHED_LOG_FILE ); + return( SM_FAILED ); + } + + result = pthread_create( &_debug_thread, NULL, sm_debug_thread_main, NULL ); + if( 0 != result ) + { + printf( "Failed to start debug thread, error=%s.\n", + strerror(result) ); + return( SM_FAILED ); + } + + _thread_created = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Debug Thread - Stop +// =================== +SmErrorT sm_debug_thread_stop( void ) +{ + _stay_on = 0; + + if( _thread_created ) + { + long ms_expired; + SmTimeT time_prev; + int result; + + sm_time_get( &time_prev ); + + while( true ) + { + result = pthread_tryjoin_np( _debug_thread, NULL ); + if(( 0 != result )&&( EBUSY != result )) + { + if(( ESRCH != result )&&( EINVAL != result )) + { + printf( "Failed to wait for debug thread exit, " + "sending kill signal, error=%s.\n", + strerror(result) ); + pthread_kill( _debug_thread, SIGKILL ); + } + break; + } + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( 5000 <= ms_expired ) + { + printf( "Failed to stop debug thread, sending " + "kill signal.\n" ); + pthread_kill( _debug_thread, SIGKILL ); + break; + } + + usleep( 250000 ); // 250 milliseconds. + } + } + + if( NULL != _sched_log ) + { + fflush( _sched_log ); + fclose( _sched_log ); + _sched_log = NULL; + } + + _server_fd = -1; + _thread_created = false; + + closelog(); + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_debug_thread.h b/service-mgmt/sm-common-1.0.0/src/sm_debug_thread.h new file mode 100644 index 00000000..b6acfcd5 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_debug_thread.h @@ -0,0 +1,59 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DEBUG_THREAD_H__ +#define __SM_DEBUG_THREAD_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + SM_DEBUG_THREAD_MSG_LOG, + SM_DEBUG_THREAD_MSG_SCHED_LOG, +} SmDebugThreadMsgTypeT; + +#define SM_DEBUG_THREAD_LOG_MAX_CHARS 512 + +typedef struct +{ + uint64_t seqnum; + struct timespec ts_mono; + struct timespec ts_real; + char data[SM_DEBUG_THREAD_LOG_MAX_CHARS]; +} SmDebugThreadMsgLogT; + +typedef struct +{ + SmDebugThreadMsgTypeT type; + + union + { + SmDebugThreadMsgLogT log; + } u; +} SmDebugThreadMsgT; + +// **************************************************************************** +// Debug Thread - Start +// ==================== +extern SmErrorT sm_debug_thread_start( int server_fd ); +// **************************************************************************** + +// **************************************************************************** +// Debug Thread - Stop +// =================== +extern SmErrorT sm_debug_thread_stop( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DEBUG_THREAD_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_eru_db.c b/service-mgmt/sm-common-1.0.0/src/sm_eru_db.c new file mode 100644 index 00000000..1b91fa8e --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_eru_db.c @@ -0,0 +1,618 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_eru_db.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" + +#define SM_ERU_DB_FILENAME "/var/lib/sm/sm.eru.v1" +#define SM_ERU_DB_MMAP_INITIALIZED 0xA5A5A5A5 +#define SM_ERU_DB_MAX_RECORDS 4194304 +#define SM_ERU_DB_HEADER_SIZE 8 + +typedef struct +{ + bool initialized; + bool read_only; + int fd; + FILE* fp; + off_t file_size; +} SmEruDBFileInfoT; + +typedef struct +{ + int write_index; + bool wrapped; +} SmEruDatabaseHeaderT; + +static SmEruDBFileInfoT _file_info; +static SmEruDatabaseHeaderT _file_header; + +static uint32_t _1MB_data_block[1048576/sizeof(uint32_t)]; + +// **************************************************************************** +// Event Recorder Unit Database - Read Lock +// ======================================== +static SmErrorT sm_eru_db_read_lock( void ) +{ + struct flock lock; + int result; + + memset( &lock, 0, sizeof(lock) ); + lock.l_type = F_RDLCK; + + int retry_i; + for( retry_i=0; 10 > retry_i; ++retry_i ) + { + result = fcntl( _file_info.fd, F_SETLK, &lock ); + if( 0 == result ) + { + return( SM_OKAY ); + } + + usleep( 50000 ); // 50 milliseconds. + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Write Lock +// ========================================= +static SmErrorT sm_eru_db_write_lock( void ) +{ + struct flock lock; + int result; + + memset( &lock, 0, sizeof(lock) ); + lock.l_type = F_WRLCK; + + int retry_i; + for( retry_i=0; 10 > retry_i; ++retry_i ) + { + result = fcntl( _file_info.fd, F_SETLK, &lock ); + if( 0 == result ) + { + return( SM_OKAY ); + } + + usleep( 50000 ); // 50 milliseconds. + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Unlock +// ===================================== +static void sm_eru_db_unlock( void ) +{ + struct flock lock; + int result; + + memset( &lock, 0, sizeof(lock) ); + lock.l_type = F_UNLCK; + + int retry_i; + for( retry_i=0; 10 > retry_i; ++retry_i ) + { + result = fcntl( _file_info.fd, F_SETLK, &lock ); + if( 0 == result ) + { + return; + } + + usleep( 50000 ); // 50 milliseconds. + } + + abort(); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Total +// ==================================== +int sm_eru_db_total( void ) +{ + if( !_file_info.initialized ) + { + DPRINTFE( "Database is not initialized." ); + return( 0 ); + } + + if( _file_header.wrapped ) + { + return( SM_ERU_DB_MAX_RECORDS ); + } + return( _file_header.write_index ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Get Write Index +// ============================================== +int sm_eru_db_get_write_index( void ) +{ + if( !_file_info.initialized ) + { + DPRINTFE( "Database is not initialized." ); + return( -1 ); + } + + return( _file_header.write_index ); +} + +// **************************************************************************** +// Event Recorder Unit Database - Flush the database +// ================================================= +void sm_eru_db_sync( void ) +{ + if( _file_info.fp != NULL ) + { + fflush( _file_info.fp ); + fsync(fileno(_file_info.fp)); + } +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Read +// =================================== +SmErrorT sm_eru_db_read( int read_index, SmEruDatabaseEntryT* entry ) +{ + SmErrorT error; + + if( !_file_info.initialized ) + { + DPRINTFE( "Database is not initialized." ); + return( SM_NOT_FOUND ); + } + + if(( 0 > read_index )&&( SM_ERU_DB_MAX_RECORDS <= read_index )) + { + DPRINTFE( "Database read index (%i) is invalid.", read_index ); + return( SM_FAILED ); + } + + error = sm_eru_db_read_lock(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get eru database read lock, error=%s.", + sm_error_str(error) ); + return( error ); + } + + fseek(_file_info.fp, (read_index*sizeof(SmEruDatabaseEntryT))+SM_ERU_DB_HEADER_SIZE, SEEK_SET); + fread(entry, 1, sizeof(SmEruDatabaseEntryT), _file_info.fp); + + sm_eru_db_unlock(); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Write +// ==================================== +SmErrorT sm_eru_db_write( SmEruDatabaseEntryT* entry ) +{ + SmErrorT error; + + if( !_file_info.initialized ) + { + DPRINTFE( "Database is not initialized." ); + return( SM_FAILED ); + } + + error = sm_eru_db_write_lock(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get eru database write lock, error=%s.", + sm_error_str(error) ); + return( error ); + } + + clock_gettime( CLOCK_REALTIME, &(entry->ts_real) ); + entry->index = _file_header.write_index; + + fseek(_file_info.fp, (_file_header.write_index*sizeof(SmEruDatabaseEntryT))+SM_ERU_DB_HEADER_SIZE, SEEK_SET); + size_t written = fwrite(entry, 1, sizeof(SmEruDatabaseEntryT), _file_info.fp); + + if( 0 > written ) + { + DPRINTFE( "Failed to write , error=%s.", strerror(errno) ); + sm_eru_db_unlock(); + return( SM_FAILED ); + } + if( written != sizeof(SmEruDatabaseEntryT)) + { + DPRINTFE( "Failed to write, %lu bytes should of been written instead of %lu", sizeof(SmEruDatabaseEntryT), written ); + sm_eru_db_unlock(); + return( SM_FAILED ); + } + + ++(_file_header.write_index); + + if( SM_ERU_DB_MAX_RECORDS <= _file_header.write_index ) + { + DPRINTFD( "Database wrapped." ); + _file_header.wrapped = true; + _file_header.write_index = 0; + } + + // The first 8 bytes of the database contains the write index and the wrapped flag + unsigned char buffer[SM_ERU_DB_HEADER_SIZE]; + memset( &buffer, 0, SM_ERU_DB_HEADER_SIZE); + + memcpy( buffer, &_file_header.write_index, sizeof(int)); + memcpy( buffer+sizeof(int), &_file_header.wrapped, sizeof(bool)); + + fseek(_file_info.fp, 0, SEEK_SET); + fwrite(buffer, 1, SM_ERU_DB_HEADER_SIZE, _file_info.fp); + + sm_eru_db_unlock(); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Display +// ====================================== +void sm_eru_db_display( SmEruDatabaseEntryT* entry, bool want_raw ) +{ + char time_str[80]; + char date_str[32]; + char addr_type_str[32]; + struct tm t_real; + unsigned long long user_time; + unsigned long long nice_time; + unsigned long long total_time; + long double user, nice, sys, idle, iowait, irq, soft_irq, steal; + long double guest, guest_nice; + char ip_str[SM_NETWORK_ADDRESS_MAX_CHAR]; + SmNodeCpuStatsT* cpu = &(entry->u.cpu_stats); + SmNodeMemStatsT* mem = &(entry->u.mem_stats); + SmNodeDiskStatsT* disk = &(entry->u.disk_stats); + SmNodeNetDevStatsT* net = &(entry->u.net_stats); + SmHwQdiscInfoT* qdisc = &(entry->u.tc_stats); + SmHwInterfaceChangeDataT* if_change = &(entry->u.if_change); + SmHwIpChangeDataT* ip_change = &(entry->u.ip_change); + + if( NULL == localtime_r( &(entry->ts_real.tv_sec), &t_real ) ) + { + snprintf( time_str, sizeof(time_str), "YYYY:MM:DD HH:MM:SS.xxx" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + snprintf( time_str, sizeof(time_str), "%s.%03ld", date_str, + entry->ts_real.tv_nsec/1000000 ); + } + + printf( "%10i. %s " , entry->index, time_str ); + + switch( entry->type ) + { + case SM_ERU_DATABASE_ENTRY_TYPE_CPU_STATS: + user_time = cpu->user_cpu_usage - cpu->guest_cpu_usage; + nice_time = cpu->nice_cpu_usage - cpu->guest_nice_cpu_usage; + total_time = user_time + nice_time + cpu->idle_task_cpu_usage + + cpu->iowait_cpu_usage + cpu->system_cpu_usage + + cpu->irq_cpu_usage + cpu->soft_irq_cpu_usage + + cpu->steal_cpu_usage + cpu->guest_cpu_usage + + cpu->guest_nice_cpu_usage; + + if( 0 != total_time ) + { + user = (long double)user_time + /(long double)total_time * 100.0; + nice = (long double)nice_time + /(long double)total_time * 100.0; + sys = (long double)cpu->system_cpu_usage + /(long double)total_time * 100.0; + idle = (long double)cpu->idle_task_cpu_usage + /(long double)total_time * 100.0; + iowait = (long double)cpu->iowait_cpu_usage + /(long double)total_time * 100.0; + irq = (long double)cpu->irq_cpu_usage + /(long double)total_time * 100.0; + soft_irq = (long double)cpu->soft_irq_cpu_usage + /(long double)total_time * 100.0; + steal = (long double)cpu->steal_cpu_usage + /(long double)total_time * 100.0; + guest = (long double)cpu->guest_cpu_usage + /(long double)total_time * 100.0; + guest_nice = (long double)cpu->guest_nice_cpu_usage + /(long double)total_time * 100.0; + + printf( "cpu-stats: %s user: %5.1Lf nice: %5.1Lf sys: %5.1Lf" + " idle: %5.1Lf iowait: %5.1Lf irq: %5.1Lf" + " soft-irq: %5.1Lf steal: %5.1Lf guest-cpu: %5.1Lf" + " guest-nice: %5.1Lf total-interrupts: %llu" + " total-context-switches: %llu" + " total-processes: %llu processes_running: %llu" + " processes_blocked: %llu boot_time_in_secs: %llu\n", + cpu->cpu_name, user, nice, sys, idle, iowait, irq, + soft_irq, steal, guest, guest_nice, + cpu->total_interrupts, cpu->total_context_switches, + cpu->total_processes, cpu->processes_running, + cpu->processes_blocked, cpu->boot_time_in_secs ); + } else { + want_raw = true; + } + + if( want_raw ) + { + printf( "cpu-raw-stats: %s user: %llu nice: %llu sys: %llu" + " idle: %llu iowait: %llu irq: %llu soft-irq: %llu" + " steal: %llu guest-cpu: %llu guest-nice: %llu" + " total-interrupts: %llu total-context-switches: %llu" + " total-processes: %llu processes_running: %llu" + " processes_blocked: %llu boot_time_in_secs: %llu\n", + cpu->cpu_name, cpu->user_cpu_usage, cpu->nice_cpu_usage, + cpu->system_cpu_usage, cpu->idle_task_cpu_usage, + cpu->iowait_cpu_usage, cpu->irq_cpu_usage, + cpu->soft_irq_cpu_usage, cpu->steal_cpu_usage, + cpu->guest_cpu_usage, cpu->guest_nice_cpu_usage, + cpu->total_interrupts, cpu->total_context_switches, + cpu->total_processes, cpu->processes_running, + cpu->processes_blocked, cpu->boot_time_in_secs ); + } + break; + + case SM_ERU_DATABASE_ENTRY_TYPE_MEM_STATS: + printf( "mem-stats: total: %lu free: %lu buffers: %lu" + " cached: %lu swap-cached: %lu swap-total: %lu" + " swap-free: %lu active: %lu inactive: %lu" + " dirty: %lu hugepages-total: %lu" + " hugepages-free: %lu hugepage-size: %lu" + " nfs-uncommited: %lu commited: %lu\n", + mem->total_memory_kB, mem->free_memory_kB, + mem->buffers_kB, mem->cached_kB, mem->swap_cached_kB, + mem->swap_total_kB, mem->swap_free_kB, mem->active_kB, + mem->inactive_kB, mem->dirty_kB, mem->hugepages_total, + mem->hugepages_free, mem->hugepage_size_kB, + mem->nfs_uncommited_kB, mem->commited_memory_kB ); + break; + + case SM_ERU_DATABASE_ENTRY_TYPE_DISK_STATS: + printf( "disk-stats: %s major: %i minor: %i" + " reads-completed: %lu reads-merged: %lu" + " sectors-read: %lu ms-spent-reading: %lu" + " writes-completed: %lu writes-merged: %lu" + " sectors-written: %lu ms-spent-writing: %lu" + " io-inprogress: %lu ms-spent-io: %lu" + " weighted-ms-spent-io: %lu\n", disk->dev_name, + disk->major_num, disk->minor_num, disk->reads_completed, + disk->reads_merged, disk->sectors_read, + disk->ms_spent_reading, disk->writes_completed, + disk->writes_merged, disk->sectors_written, + disk->ms_spent_writing, disk->io_inprogress, + disk->ms_spent_io, disk->weighted_ms_spent_io ); + break; + + case SM_ERU_DATABASE_ENTRY_TYPE_NET_STATS: + printf( "net-stats: %s rx-bytes: %llu rx-packets: %llu" + " rx-errors: %llu rx-dropped: %llu rx-fifo-errors: %llu" + " rx-frame-errors: %llu rx-compressed-packets: %llu" + " rx-multicast-frames: %llu tx-bytes: %llu" + " tx-packets: %llu tx-errors: %llu tx-dropped: %llu" + " tx-fifo-errors: %llu tx-collisions: %llu" + " tx-carrier-loss: %llu tx-compressed-packets: %llu\n", + net->dev_name, net->rx_bytes, net->rx_packets, + net->rx_errors, net->rx_dropped, net->rx_fifo_errors, + net->rx_frame_errors, net->rx_compressed_packets, + net->rx_multicast_frames, net->tx_bytes, net->tx_packets, + net->tx_errors, net->tx_dropped, net->tx_fifo_errors, + net->tx_collisions, net->tx_carrier_loss, + net->tx_compressed_packets ); + break; + + case SM_ERU_DATABASE_ENTRY_TYPE_TC_STATS: + printf( "tc-stats: %s %s %s bytes: %"PRIu64" packets: %"PRIu64 + " qlen: %"PRIu64" backlog: %"PRIu64" drops: %"PRIu64 + " requeues: %"PRIu64" overlimits: %"PRIu64"\n", + qdisc->interface_name, qdisc->queue_type, + qdisc->handle, qdisc->bytes, qdisc->packets, + qdisc->q_length, qdisc->backlog, qdisc->drops, + qdisc->requeues, qdisc->overlimits ); + break; + + case SM_ERU_DATABASE_ENTRY_TYPE_IF_CHANGE: + printf( "if-change: %s type: %s state: %s\n", + if_change->interface_name, + (SM_HW_INTERFACE_CHANGE_TYPE_ADD == if_change->type) + ? "add" : "delete", + sm_interface_state_str(if_change->interface_state) ); + break; + + case SM_ERU_DATABASE_ENTRY_TYPE_IP_CHANGE: + sm_network_address_str( &(ip_change->address), ip_str ); + + if( SM_HW_ADDRESS_TYPE_ADDRESS == ip_change->address_type ) + { + snprintf( addr_type_str, sizeof(addr_type_str), "address" ); + } else if( SM_HW_ADDRESS_TYPE_LOCAL == ip_change->address_type ){ + snprintf( addr_type_str, sizeof(addr_type_str), "local" ); + } else if( SM_HW_ADDRESS_TYPE_BROADCAST == ip_change->address_type ){ + snprintf( addr_type_str, sizeof(addr_type_str), "broadcast" ); + } else if( SM_HW_ADDRESS_TYPE_ANYCAST == ip_change->address_type ){ + snprintf( addr_type_str, sizeof(addr_type_str), "anycast" ); + } else { + snprintf( addr_type_str, sizeof(addr_type_str), "unknown" ); + } + + printf( "ip-change: %s type: %s address: %s/%i address-type=%s\n", + ip_change->interface_name, + (SM_HW_IP_CHANGE_TYPE_ADD == ip_change->type) + ? "add" : "delete", ip_str, ip_change->prefix_len, + addr_type_str ); + break; + + default: + DPRINTFE( "Unknown entry type (%i).", entry->type ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Initialize +// ========================================= +SmErrorT sm_eru_db_initialize( char* filename, bool read_only ) +{ + char db_filename[512] = ""; + struct stat stat_info; + int result; + _file_info.initialized = false; + _file_info.fp = NULL; + _file_header.wrapped = false; + _file_header.write_index = 0; + + if( NULL == filename ) + { + snprintf( db_filename, sizeof(db_filename), "%s", SM_ERU_DB_FILENAME ); + } else { + snprintf( db_filename, sizeof(db_filename), "%s", filename ); + + } + + DPRINTFD( "ERU Database Entry size is %i, total_records=%i.", + (int) sizeof(SmEruDatabaseEntryT), SM_ERU_DB_MAX_RECORDS ); + + if( read_only ) + { + _file_info.fp = fopen (db_filename, "r"); + } else { + _file_info.fp = fopen (db_filename, "r+"); + if (_file_info.fp == NULL) + { + // File does not exist, open for write with file creation + _file_info.fp = fopen (db_filename, "w+"); + } + } + + if( _file_info.fp == NULL ) + { + DPRINTFE( "Failed to open database file (%s), error=%s.", db_filename, + strerror( errno ) ); + return( SM_FAILED ); + } + + _file_info.fd = fileno(_file_info.fp); + + result = fstat( _file_info.fd, &stat_info ); + if( 0 > result ) + { + DPRINTFE( "Failed to get database file stats, error=%s.", + strerror(errno) ); + sm_eru_db_finalize(); + return( SM_FAILED ); + } + + int max_db_size = (sizeof(SmEruDatabaseEntryT) * SM_ERU_DB_MAX_RECORDS ) + SM_ERU_DB_HEADER_SIZE; + + if( (int) stat_info.st_size < max_db_size ) + { + if( read_only ) + { + DPRINTFE( "Database is not sized correctly, expected=%i, " + "actual=%i.", max_db_size, (int) stat_info.st_size ); + sm_eru_db_finalize(); + return( SM_FAILED ); + + } else { + int num_blocks; + + DPRINTFI( "Initializing database." ); + + num_blocks = max_db_size / sizeof(_1MB_data_block) + 1; + memset( _1MB_data_block, 0, sizeof(_1MB_data_block) ); + + int block_i; + for( block_i=0; block_i < num_blocks; ++block_i ) + { + write( _file_info.fd, (void*) _1MB_data_block, + sizeof(_1MB_data_block) ); + } + + result = fstat( _file_info.fd, &stat_info ); + if( 0 > result ) + { + DPRINTFE( "Failed to get database file statistics, error=%s.", + strerror(errno) ); + sm_eru_db_finalize(); + return( SM_FAILED ); + } + + if( (int) stat_info.st_size < (max_db_size) ) + { + DPRINTFE( "Failed to create database, size=%d.", + (int) stat_info.st_size ); + sm_eru_db_finalize(); + return( SM_FAILED ); + } + + _file_info.file_size = stat_info.st_size; + } + } else { + _file_info.file_size = stat_info.st_size; + } + + _file_info.read_only = read_only; + _file_info.initialized = true; + + // Read write index and wrapper flag + unsigned char buffer[SM_ERU_DB_HEADER_SIZE]; + int bytes_read = fread(buffer, 1, SM_ERU_DB_HEADER_SIZE, _file_info.fp); + + if (bytes_read == SM_ERU_DB_HEADER_SIZE) + { + memcpy(&_file_header.write_index, buffer, sizeof(int)); + memcpy(&_file_header.wrapped, buffer+sizeof(int), sizeof(bool)); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Finalize +// ======================================= +SmErrorT sm_eru_db_finalize( void ) +{ + _file_info.initialized = false; + + if( _file_info.fp != NULL ) + { + sm_eru_db_sync(); + fclose(_file_info.fp); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_eru_db.h b/service-mgmt/sm-common-1.0.0/src/sm_eru_db.h new file mode 100644 index 00000000..9f887287 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_eru_db.h @@ -0,0 +1,101 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_ERU_DB_H__ +#define __SM_ERU_DB_H__ + +#include + +#include "sm_types.h" +#include "sm_hw.h" +#include "sm_node_stats.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum +{ + SM_ERU_DATABASE_ENTRY_TYPE_CPU_STATS, + SM_ERU_DATABASE_ENTRY_TYPE_MEM_STATS, + SM_ERU_DATABASE_ENTRY_TYPE_DISK_STATS, + SM_ERU_DATABASE_ENTRY_TYPE_NET_STATS, + SM_ERU_DATABASE_ENTRY_TYPE_TC_STATS, + SM_ERU_DATABASE_ENTRY_TYPE_IF_CHANGE, + SM_ERU_DATABASE_ENTRY_TYPE_IP_CHANGE, + SM_ERU_DATABASE_ENTRY_TYPE_MAX +} SmEruDatabaseEntryType; + +typedef struct +{ + int index; // Filled in on write. + struct timespec ts_real; // Filled in on write. + + SmEruDatabaseEntryType type; + union + { + SmNodeCpuStatsT cpu_stats; + SmNodeMemStatsT mem_stats; + SmNodeDiskStatsT disk_stats; + SmNodeNetDevStatsT net_stats; + SmHwQdiscInfoT tc_stats; + SmHwInterfaceChangeDataT if_change; + SmHwIpChangeDataT ip_change; + } u; +} SmEruDatabaseEntryT; + +// **************************************************************************** +// Event Recorder Unit Database - Total +// ==================================== +extern int sm_eru_db_total( void ); +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Get Write Index +// ============================================== +extern int sm_eru_db_get_write_index( void ); +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Flush the database +// ================================================= +extern void sm_eru_db_sync( void ); +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Read +// =================================== +extern SmErrorT sm_eru_db_read( int read_index, SmEruDatabaseEntryT* entry ); +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Write +// ==================================== +extern SmErrorT sm_eru_db_write( SmEruDatabaseEntryT* entry ); +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Display +// ====================================== +extern void sm_eru_db_display( SmEruDatabaseEntryT* entry, bool want_raw ); +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Initialize +// ========================================= +extern SmErrorT sm_eru_db_initialize( char filename[], bool read_only ); +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Database - Finalize +// ======================================= +extern SmErrorT sm_eru_db_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_ERU_DB_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_eru_dump.c b/service-mgmt/sm-common-1.0.0/src/sm_eru_dump.c new file mode 100644 index 00000000..f56cc0d3 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_eru_dump.c @@ -0,0 +1,321 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#define _XOPEN_SOURCE +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_eru_db.h" + +static struct option _sm_eru_long_options[] = +{ + { "file", required_argument, NULL, 'f'}, + { "type", required_argument, NULL, 't'}, + { "start-time", required_argument, NULL, 's'}, + { "end-time", required_argument, NULL, 'e'}, + { "last", required_argument, NULL, 'l'}, + { "raw", no_argument, NULL, 'r'}, + {0, 0, 0, 0} +}; + +// **************************************************************************** +// Main - Event Recorder Unit Dump +// =============================== +static void usage( void ) +{ + printf( " usage:\n" + " sm-eru-dump [--file ]\n" + " [--type ]\n" + " [--start-time <\"YEAR-MONTH-DAY HH:MM:SS\">]\n" + " [--end-time <\"YEAR-MONTH-DAY HH:MM:SS\">]\n" + " [--last ]\n" + " [--raw]\n" + " [--help]\n" + " --type : type of record to filter on\n" + " --start-time: start time for filter (inclusive)\n" + " --end-time : end time for filter (inclusive)\n" + " --last : display last so many records\n" + " --raw : display raw record data\n" + " --help : print out this help message\n" + "\n" + " eg. sm-eru-dump --start-time \"2014-10-17 22:15:10\"\n" + "\n" ); +} +// **************************************************************************** + +// **************************************************************************** +// Main - Event Recorder Unit Dump +// =============================== +int main( int argc, char *argv[], char *envp[] ) +{ + int c; + int last = -1; + int record_i, record_count, total_records; + char buf[128]; + bool want_raw = false; + bool filter_record_type = false; + bool filter_start_time = false; + bool filter_end_time = false; + struct tm start_tm; + struct tm end_tm; + time_t start_time = 0; + time_t end_time = 0; + int num_record_types = 0; + char* filename = NULL; + char* tz = NULL; + + SmEruDatabaseEntryType record_types[SM_ERU_DATABASE_ENTRY_TYPE_MAX]; + SmEruDatabaseEntryT entry; + SmErrorT error; + + memset( record_types, 0, sizeof(record_types) ); + + tz = getenv( "TZ" ); + setenv( "TZ", "", 1 ); + tzset(); + + while( true ) + { + c = getopt_long( argc, argv, "", _sm_eru_long_options, NULL ); + if( -1 == c ) + { + break; + } + + switch( c ) + { + case 'f': + if( optarg ) + { + filename = (char*) optarg; + } + break; + + case 't': + if( optarg ) + { + if( 0 == strcmp( optarg, "cpu" ) ) + { + filter_record_type = true; + record_types[num_record_types] + = SM_ERU_DATABASE_ENTRY_TYPE_CPU_STATS; + ++num_record_types; + printf( "filter-record-match : cpu-stats\n" ); + + } else if( 0 == strcmp( optarg, "mem" ) ) { + filter_record_type = true; + record_types[num_record_types] + = SM_ERU_DATABASE_ENTRY_TYPE_MEM_STATS; + ++num_record_types; + printf( "filter-record-match : memory-stats\n" ); + + } else if( 0 == strcmp( optarg, "disk" ) ) { + filter_record_type = true; + record_types[num_record_types] + = SM_ERU_DATABASE_ENTRY_TYPE_DISK_STATS; + ++num_record_types; + printf( "filter-record-match : disk-stats\n" ); + + } else if( 0 == strcmp( optarg, "net" ) ) { + filter_record_type = true; + record_types[num_record_types] + = SM_ERU_DATABASE_ENTRY_TYPE_NET_STATS; + ++num_record_types; + printf( "filter-record-match : net-stats\n" ); + + } else if( 0 == strcmp( optarg, "tc" ) ) { + filter_record_type = true; + record_types[num_record_types] + = SM_ERU_DATABASE_ENTRY_TYPE_TC_STATS; + ++num_record_types; + printf( "filter-record-match : tc-stats\n" ); + + } else if( 0 == strcmp( optarg, "if" ) ) { + filter_record_type = true; + record_types[num_record_types] + = SM_ERU_DATABASE_ENTRY_TYPE_IF_CHANGE; + ++num_record_types; + printf( "filter-record-match : if-change\n" ); + + } else if( 0 == strcmp( optarg, "ip" ) ) { + filter_record_type = true; + record_types[num_record_types] + = SM_ERU_DATABASE_ENTRY_TYPE_IP_CHANGE; + ++num_record_types; + printf( "filter-record-match : ip-change\n" ); + } + } + break; + + case 's': + if( optarg ) + { + filter_start_time = true; + if( NULL == strptime( optarg, "%FT%T", &start_tm ) ) + { + strptime( optarg, "%F %T", &start_tm ); + } + start_time = mktime( &start_tm ); + strftime( buf, sizeof(buf), "%FT%T", &start_tm ); + printf( "filter-start-time : %s <= record-time\n", buf ); + } + break; + + case 'e': + if( optarg ) + { + filter_end_time = true; + if( NULL == strptime( optarg, "%FT%T", &end_tm ) ) + { + strptime( optarg, "%F %T", &end_tm ); + } + end_time = mktime( &end_tm ); + strftime( buf, sizeof(buf), "%FT%T", &end_tm ); + printf( "filter-end-time : %s >= record-time\n", buf ); + } + break; + + case 'l': + if( optarg ) + { + last = atoi( optarg ); + printf( "display-last : %i records\n", last ); + } + break; + + case 'r': + printf( "dump-raw-data : true\n" ); + want_raw = true; + break; + + case 'h': + case '?': + usage(); + exit(0); + break; + } + } + + if( tz ) + { + setenv( "TZ", tz, 1 ); + } else { + unsetenv( "TZ" ); + } + tzset(); + + error = sm_eru_db_initialize( filename, true ); + if( SM_OKAY != error ) + { + DPRINTFE( "ERU database initialize failed, error=%s.", + sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + total_records = sm_eru_db_total(); + record_count = total_records; + + printf( "total-records: %i (entry-size=%i bytes)\n", total_records, + (int) sizeof(SmEruDatabaseEntryT) ); + + if(( -1 == last )||( last >= total_records )) + { + record_i = 0; + } else { + int last_record = sm_eru_db_get_write_index(); + if( 0 >= last_record ) + { + record_i = 0; + } else { + record_i = last_record; + record_count = last; + for( ; 0 < last; --last ) + { + --record_i; + if( 0 > record_i ) + { + record_i = total_records-1; + } + } + } + } + + for( ; 0 < record_count; --record_count ) + { + error = sm_eru_db_read( record_i, &entry ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to read record at index (%i), error=%s.", + record_i, sm_error_str( error ) ); + break; + } + + if( filter_record_type ) + { + bool found = false; + + int type_i; + for( type_i=0; num_record_types > type_i; ++type_i ) + { + if( record_types[type_i] == entry.type ) + { + found = true; + break; + } + } + + if( !found ) + { + goto INCREMENT; + } + } + + if( filter_start_time ) + { + double diff = difftime( start_time, entry.ts_real.tv_sec ); + if( diff > 0.0 ) + { + goto INCREMENT; + } + } + + if( filter_end_time ) + { + double diff = difftime( end_time, entry.ts_real.tv_sec ); + if( diff < 0.0 ) + { + goto INCREMENT; + } + } + + sm_eru_db_display( &entry, want_raw ); + +INCREMENT: + ++record_i; + if( total_records <= record_i ) + { + record_i = 0; + } + } + + printf( "total-records: %i (entry-size=%i bytes)\n", total_records, + (int) sizeof(SmEruDatabaseEntryT) ); + + error = sm_eru_db_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "ERU database finalize failed, error=%s.", + sm_error_str( error ) ); + } + + return( EXIT_SUCCESS ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_eru_main.c b/service-mgmt/sm-common-1.0.0/src/sm_eru_main.c new file mode 100644 index 00000000..33208dfe --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_eru_main.c @@ -0,0 +1,49 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_eru_process.h" + +// **************************************************************************** +// Main - Thread +// ============= +int main( int argc, char *argv[], char *envp[] ) +{ + SmErrorT error; + + error = sm_debug_initialize(); + if( SM_OKAY != error ) + { + printf( "Debug initialization failed, error=%s.\n", + sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + error = sm_eru_process_main( argc, argv, envp ); + if( SM_OKAY != error ) + { + printf( "Process failure, error=%s.\n", sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + error = sm_debug_finalize(); + if( SM_OKAY != error ) + { + printf( "Debug finalization failed, error=%s.\n", + sm_error_str( error ) ); + } + + return( EXIT_SUCCESS ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_eru_process.c b/service-mgmt/sm-common-1.0.0/src/sm_eru_process.c new file mode 100644 index 00000000..82433aca --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_eru_process.c @@ -0,0 +1,570 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_eru_process.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_utils.h" +#include "sm_selobj.h" +#include "sm_time.h" +#include "sm_timer.h" +#include "sm_hw.h" +#include "sm_thread_health.h" +#include "sm_node_utils.h" +#include "sm_node_stats.h" +#include "sm_eru_db.h" + +#define SM_ERU_PROCESS_TICK_INTERVAL_IN_MS 1000 +#define SM_ERU_PROCESS_STATS_TIMER_IN_MS 30000 + +static sig_atomic_t _stay_on = 1; +static SmTimerIdT _stats_timer_id = SM_TIMER_ID_INVALID; +static SmEruDatabaseEntryT _cpu_prev_entry; +static char _interfaces[SM_INTERFACE_MAX][SM_INTERFACE_NAME_MAX_CHAR]; + +// **************************************************************************** +// Event Recorder Unit Process - Find Interface +// ============================================ +static int sm_eru_process_find_interface( char interface_name[] ) +{ + int if_i; + for( if_i=0; SM_INTERFACE_MAX > if_i; ++if_i ) + { + if( 0 == strcmp( &(_interfaces[if_i][0]), interface_name ) ) + { + break; + } + } + + return( if_i ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Add Interface +// =========================================== +void sm_eru_process_add_interface( char interface_name[] ) +{ + if( SM_INTERFACE_MAX <= sm_eru_process_find_interface( interface_name ) ) + { + int if_i; + for( if_i=0; SM_INTERFACE_MAX > if_i; ++if_i ) + { + if( '\0' == _interfaces[if_i][0] ) + { + snprintf( &(_interfaces[if_i][0]), SM_INTERFACE_NAME_MAX_CHAR, + "%s", interface_name ); + break; + } + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Load Interfaces +// ============================================= +void sm_eru_process_load_interfaces( void ) +{ + SmErrorT error; + + memset( _interfaces, 0, sizeof(_interfaces) ); + + error = sm_node_utils_get_mgmt_interface( &(_interfaces[0][0]) ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to look up management interface, error=%s.", + sm_error_str(error) ); + } + + error = sm_node_utils_get_oam_interface( &(_interfaces[1][0]) ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to look up oam interface, error=%s.", + sm_error_str(error) ); + } + + error = sm_node_utils_get_infra_interface( &(_interfaces[2][0]) ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to look up infrastructure interface, error=%s.", + sm_error_str(error) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Qdisc Information Callback +// ======================================================== +static void sm_eru_process_qdisc_info_callback( SmHwQdiscInfoT* qdisc ) +{ + int if_i; + + if_i = sm_eru_process_find_interface( qdisc->interface_name ); + if( SM_INTERFACE_MAX > if_i ) + { + SmEruDatabaseEntryT entry; + + memset( &entry, 0, sizeof(SmEruDatabaseEntryT) ); + entry.type = SM_ERU_DATABASE_ENTRY_TYPE_TC_STATS; + memcpy( &(entry.u.tc_stats), qdisc, sizeof(SmHwQdiscInfoT) ); + sm_eru_db_write( &entry ); + } + + // Ensure all the records are written to disk after this callback + sm_eru_db_sync(); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Interface Change Callback +// ======================================================= +static void sm_eru_process_interface_change_callback( + SmHwInterfaceChangeDataT* if_change ) +{ + int if_i; + + if_i = sm_eru_process_find_interface( if_change->interface_name ); + if( SM_INTERFACE_MAX > if_i ) + { + SmEruDatabaseEntryT entry; + + memset( &entry, 0, sizeof(SmEruDatabaseEntryT) ); + entry.type = SM_ERU_DATABASE_ENTRY_TYPE_IF_CHANGE; + memcpy( &(entry.u.if_change), if_change, + sizeof(SmHwInterfaceChangeDataT) ); + sm_eru_db_write( &entry ); + } + + // Ensure all the records are written to disk after this callback + sm_eru_db_sync(); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - IP Change Callback +// ================================================ +static void sm_eru_process_ip_change_callback( SmHwIpChangeDataT* ip_change ) +{ + int if_i; + + if_i = sm_eru_process_find_interface( ip_change->interface_name ); + if( SM_INTERFACE_MAX > if_i ) + { + SmEruDatabaseEntryT entry; + + memset( &entry, 0, sizeof(SmEruDatabaseEntryT) ); + entry.type = SM_ERU_DATABASE_ENTRY_TYPE_IP_CHANGE; + memcpy( &(entry.u.ip_change), ip_change, + sizeof(SmHwIpChangeDataT) ); + sm_eru_db_write( &entry ); + } + + // Ensure all the records are written to disk after this callback + sm_eru_db_sync(); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Statistics +// ======================================== +static bool sm_eru_process_stats( SmTimerIdT timer_id, int64_t user_data ) +{ + SmEruDatabaseEntryT entry; + SmNodeDiskStatsT* disk_stats = &(entry.u.disk_stats); + SmErrorT error; + + sm_eru_process_load_interfaces(); + + // CPU Statistics. + memset( &entry, 0, sizeof(SmEruDatabaseEntryT) ); + entry.type = SM_ERU_DATABASE_ENTRY_TYPE_CPU_STATS; + error = sm_node_stats_get_cpu( "", &(entry.u.cpu_stats) ); + if( SM_OKAY == error ) + { + if( -1 != _cpu_prev_entry.index ) + { + SmEruDatabaseEntryT delta_entry; + + memcpy( &delta_entry, &entry, sizeof(SmEruDatabaseEntryT) ); + + delta_entry.u.cpu_stats.user_cpu_usage + = entry.u.cpu_stats.user_cpu_usage + - _cpu_prev_entry.u.cpu_stats.user_cpu_usage; + delta_entry.u.cpu_stats.nice_cpu_usage + = entry.u.cpu_stats.nice_cpu_usage + - _cpu_prev_entry.u.cpu_stats.nice_cpu_usage; + delta_entry.u.cpu_stats.system_cpu_usage + = entry.u.cpu_stats.system_cpu_usage + - _cpu_prev_entry.u.cpu_stats.system_cpu_usage; + delta_entry.u.cpu_stats.idle_task_cpu_usage + = entry.u.cpu_stats.idle_task_cpu_usage + - _cpu_prev_entry.u.cpu_stats.idle_task_cpu_usage; + delta_entry.u.cpu_stats.iowait_cpu_usage + = entry.u.cpu_stats.iowait_cpu_usage + - _cpu_prev_entry.u.cpu_stats.iowait_cpu_usage; + delta_entry.u.cpu_stats.irq_cpu_usage + = entry.u.cpu_stats.irq_cpu_usage + - _cpu_prev_entry.u.cpu_stats.irq_cpu_usage; + delta_entry.u.cpu_stats.soft_irq_cpu_usage + = entry.u.cpu_stats.soft_irq_cpu_usage + - _cpu_prev_entry.u.cpu_stats.soft_irq_cpu_usage; + delta_entry.u.cpu_stats.steal_cpu_usage + = entry.u.cpu_stats.steal_cpu_usage + - _cpu_prev_entry.u.cpu_stats.steal_cpu_usage; + delta_entry.u.cpu_stats.guest_cpu_usage + = entry.u.cpu_stats.guest_cpu_usage + - _cpu_prev_entry.u.cpu_stats.guest_cpu_usage; + delta_entry.u.cpu_stats.guest_nice_cpu_usage + = entry.u.cpu_stats.guest_nice_cpu_usage + - _cpu_prev_entry.u.cpu_stats.guest_nice_cpu_usage; + + sm_eru_db_write( &delta_entry ); + } + memcpy( &_cpu_prev_entry, &entry, sizeof(_cpu_prev_entry) ); + } + + // Memory Statistics. + memset( &entry, 0, sizeof(SmEruDatabaseEntryT) ); + entry.type = SM_ERU_DATABASE_ENTRY_TYPE_MEM_STATS; + error = sm_node_stats_get_memory( &(entry.u.mem_stats) ); + if( SM_OKAY == error ) + { + sm_eru_db_write( &entry ); + } + + // Disk Statistics + int disk_i; + for( disk_i=0; SM_DISK_MAX > disk_i; ++disk_i ) + { + memset( &entry, 0, sizeof(SmEruDatabaseEntryT) ); + entry.type = SM_ERU_DATABASE_ENTRY_TYPE_DISK_STATS; + error = sm_node_stats_get_disk_by_index( disk_i, disk_stats ); + if( SM_OKAY == error ) + { + if(( 0 != disk_stats->reads_completed )|| + ( 0 != disk_stats->reads_merged )|| + ( 0 != disk_stats->sectors_read )|| + ( 0 != disk_stats->ms_spent_reading )|| + ( 0 != disk_stats->writes_completed )|| + ( 0 != disk_stats->writes_merged )|| + ( 0 != disk_stats->sectors_written )|| + ( 0 != disk_stats->ms_spent_writing )|| + ( 0 != disk_stats->io_inprogress )|| + ( 0 != disk_stats->ms_spent_io )|| + ( 0 != disk_stats->weighted_ms_spent_io )) + { + sm_eru_db_write( &entry ); + } + } + } + + // Net Device Statistics. + int if_i; + for( if_i=0; SM_INTERFACE_MAX > if_i; ++if_i ) + { + if( '\0' != _interfaces[if_i][0] ) + { + memset( &entry, 0, sizeof(SmEruDatabaseEntryT) ); + entry.type = SM_ERU_DATABASE_ENTRY_TYPE_NET_STATS; + error = sm_node_stats_get_netdev( _interfaces[if_i], + &(entry.u.net_stats) ); + if( SM_OKAY == error ) + { + sm_eru_db_write( &entry ); + } + } + } + + // Traffic Class Statistics. + sm_hw_get_all_qdisc_async(); + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Signal Handler +// ============================================ +static void sm_eru_process_signal_handler( int signum ) +{ + switch( signum ) + { + case SIGINT: + case SIGTERM: + case SIGQUIT: + _stay_on = 0; + break; + + case SIGCONT: + DPRINTFD( "Ignoring signal SIGCONT (%i).", signum ); + break; + + default: + DPRINTFD( "Signal (%i) ignored.", signum ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Setup Signal Handler +// ================================================== +static void sm_eru_process_setup_signal_handler( void ) +{ + struct sigaction sa; + + memset( &sa, 0, sizeof(sa) ); + sa.sa_handler = sm_eru_process_signal_handler; + + sigaction( SIGINT, &sa, NULL ); + sigaction( SIGTERM, &sa, NULL ); + sigaction( SIGQUIT, &sa, NULL ); + sigaction( SIGCONT, &sa, NULL ); + + signal( SIGCHLD, SIG_IGN ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Initialize +// ======================================== +static SmErrorT sm_eru_process_initialize( void ) +{ + SmHwCallbacksT callbacks; + SmErrorT error; + + memset( &_cpu_prev_entry, 0, sizeof(_cpu_prev_entry) ); + _cpu_prev_entry.index = -1; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_timer_initialize( SM_ERU_PROCESS_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + memset( &callbacks, 0, sizeof(callbacks) ); + callbacks.qdisc_info = sm_eru_process_qdisc_info_callback; + callbacks.interface_change = sm_eru_process_interface_change_callback; + callbacks.ip_change = sm_eru_process_ip_change_callback; + + error = sm_hw_initialize( &callbacks ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize hardware module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_node_stats_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node stats module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_thread_health_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize thread health module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_eru_db_initialize( NULL, false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize eru database module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_timer_register( "eru stats", + SM_ERU_PROCESS_STATS_TIMER_IN_MS, + sm_eru_process_stats, 0, &_stats_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create stats collection timer, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Finalize +// ====================================== +static SmErrorT sm_eru_process_finalize( void ) +{ + SmErrorT error; + + if( SM_TIMER_ID_INVALID != _stats_timer_id ) + { + error = sm_timer_deregister( _stats_timer_id ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cancel stats collection timer, error=%s.", + sm_error_str( error ) ); + } + + _stats_timer_id = SM_TIMER_ID_INVALID; + } + + error = sm_eru_db_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize eru database module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_thread_health_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize thread health module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_node_stats_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize node stats module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_hw_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize hardware module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize timer module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize selection object module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Event Recorder Unit Process - Main +// ================================== +SmErrorT sm_eru_process_main( int argc, char *argv[], char *envp[] ) +{ + bool thread_health; + SmErrorT error; + + sm_eru_process_setup_signal_handler(); + + DPRINTFI( "Starting" ); + + if( sm_utils_process_running( SM_ERU_PROCESS_PID_FILENAME ) ) + { + DPRINTFI( "Already running an instance of sm-eru." ); + return( SM_OKAY ); + } + + if( !sm_utils_set_pid_file( SM_ERU_PROCESS_PID_FILENAME ) ) + { + DPRINTFE( "Failed to write pid file for sm-eru, error=%s.", + strerror(errno) ); + return( SM_FAILED ); + } + + error = sm_eru_process_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed initialize process, error=%s.", + sm_error_str(error) ); + return( error ); + } + + DPRINTFI( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_ERU_PROCESS_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + + error = sm_thread_health_check( &thread_health ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to check thread health, error=%s.", + sm_error_str(error) ); + break; + } + + if( !thread_health ) + { + DPRINTFE( "Thread health check failed." ); + break; + } + } + + DPRINTFI( "Shutting down." ); + + error = sm_eru_process_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize process, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_eru_process.h b/service-mgmt/sm-common-1.0.0/src/sm_eru_process.h new file mode 100644 index 00000000..3eefd60f --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_eru_process.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_ERU_PROCESS_H__ +#define __SM_ERU_PROCESS_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Event Recorder Unit Process - Main +// ================================== +extern SmErrorT sm_eru_process_main( int argc, char *argv[], char *envp[] ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_ERU_PROCESS_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_hw.c b/service-mgmt/sm-common-1.0.0/src/sm_hw.c new file mode 100644 index 00000000..8abb71ae --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_hw.c @@ -0,0 +1,822 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_hw.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_selobj.h" +#include "sm_netlink.h" + +typedef struct +{ + bool inuse; + pthread_t thread_id; + uint32_t msg_seq; + int ioctl_socket; + int netlink_receive_socket; + SmHwCallbacksT callbacks; +} SmHwThreadInfoT; + +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static SmHwThreadInfoT _threads[SM_THREADS_MAX]; + +// **************************************************************************** +// Hardware - Find Thread Info +// =========================== +static SmHwThreadInfoT* sm_hw_find_thread_info( void ) +{ + pthread_t thread_id = pthread_self(); + + unsigned int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + if( !(_threads[thread_i].inuse) ) + continue; + + if( thread_id == _threads[thread_i].thread_id ) + return( &(_threads[thread_i]) ); + } + + return( NULL ); +} +// **************************************************************************** + +// *************************************************************************** +// Hardware - Get Interface By Network Address +// =========================================== +SmErrorT sm_hw_get_if_by_network_address( SmNetworkAddressT* network_address, + char if_name[] ) +{ + if_name[0] = '\0'; + + if(( SM_NETWORK_TYPE_IPV4 == network_address->type )|| + ( SM_NETWORK_TYPE_IPV4_UDP == network_address->type )) + { + struct ifaddrs *if_addr = NULL; + struct ifaddrs *if_addrs = NULL; + int result; + + result = getifaddrs( &if_addrs ); + if( 0 > result ) + { + DPRINTFE( "Failed to get all interface addresses, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + for( if_addr=if_addrs; NULL != if_addr; if_addr=if_addr->ifa_next ) + { + if( NULL == if_addr->ifa_addr ) + continue; + + if( AF_INET == if_addr->ifa_addr->sa_family ) + { + struct sockaddr_in* ipv4_addr; + ipv4_addr = (struct sockaddr_in*) if_addr->ifa_addr; + + if( ipv4_addr->sin_addr.s_addr + == network_address->u.ipv4.sin.s_addr ) + { + snprintf( if_name, SM_INTERFACE_NAME_MAX_CHAR, "%s", + if_addr->ifa_name ); + return( SM_OKAY ); + } + } + } + + } else if(( SM_NETWORK_TYPE_IPV6 == network_address->type )|| + ( SM_NETWORK_TYPE_IPV6_UDP == network_address->type )) + { + struct ifaddrs *if_addr = NULL; + struct ifaddrs *if_addrs = NULL; + int result; + + result = getifaddrs( &if_addrs ); + if( 0 > result ) + { + DPRINTFE( "Failed to get all interface addresses, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + for( if_addr=if_addrs; NULL != if_addr; if_addr=if_addr->ifa_next ) + { + if( NULL == if_addr->ifa_addr ) + continue; + + if( AF_INET6 == if_addr->ifa_addr->sa_family ) + { + struct sockaddr_in6* ipv6_addr; + ipv6_addr = (struct sockaddr_in6*) if_addr->ifa_addr; + + if( memcmp( &(ipv6_addr->sin6_addr), + &(network_address->u.ipv6.sin6), + sizeof(struct in6_addr) )) + { + snprintf( if_name, SM_INTERFACE_NAME_MAX_CHAR, "%s", + if_addr->ifa_name ); + return( SM_OKAY ); + } + } + } + + } else { + + DPRINTFE( "Unsupported network type (%s).", + sm_network_type_str(network_address->type) ); + return( SM_FAILED ); + } + + return( SM_NOT_FOUND ); +} +// *************************************************************************** + +// *************************************************************************** +// Hardware - Get Interface Index +// ============================== +SmErrorT sm_hw_get_if_index( const char if_name[], int* if_index ) +{ + struct ifreq if_data; + SmHwThreadInfoT* thread_info; + + *if_index = SM_INVALID_INDEX; + + thread_info = sm_hw_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + memset( &if_data, 0, sizeof(if_data) ); + + snprintf( if_data.ifr_name, sizeof(if_data.ifr_name), "%s", if_name ); + + if( 0 <= ioctl( thread_info->ioctl_socket, SIOCGIFINDEX, &if_data ) ) + { + if( 0 != if_data.ifr_ifindex ) + { + *if_index = if_data.ifr_ifindex; + + } else { + DPRINTFD( "Interface index is invalid, if_name=%s.", if_name ); + return( SM_FAILED ); + } + } else { + DPRINTFD( "Failed to get interface index, if_name=%s, error=%s.", + if_name, strerror( errno ) ); + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Hardware - Get Interface Name +// ============================= +SmErrorT sm_hw_get_if_name( int if_index, char if_name[] ) +{ + struct ifreq if_data; + SmHwThreadInfoT* thread_info; + + thread_info = sm_hw_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + memset( &if_data, 0, sizeof(if_data) ); + + if_data.ifr_ifindex = if_index; + + if( 0 <= ioctl( thread_info->ioctl_socket, SIOCGIFNAME, &if_data ) ) + { + snprintf( if_name, SM_INTERFACE_NAME_MAX_CHAR, "%s", if_data.ifr_name ); + + } else { + DPRINTFD( "Failed to get interface name for interface index (%i), " + "error=%s.", if_index, strerror( errno ) ); + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Sm Hardware - Get Interface State +// ================================= +SmErrorT sm_hw_get_if_state( const char if_name[], bool* enabled ) +{ + struct ifreq if_data; + SmHwThreadInfoT* thread_info; + + thread_info = sm_hw_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + memset( &if_data, 0, sizeof(if_data) ); + snprintf( if_data.ifr_name, sizeof(if_data.ifr_name), "%s", if_name ); + + if( 0 <= ioctl( thread_info->ioctl_socket, SIOCGIFFLAGS, &if_data ) ) + { + if( if_data.ifr_flags & IFF_RUNNING ) + { + *enabled = true; + } else { + *enabled = false; + } + } else { + DPRINTFE( "Failed to get interface state for interface (%s), " + "error=%s.", if_name, strerror( errno ) ); + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Sm Hardware - Get All QDisc Asynchronous +// ======================================== +SmErrorT sm_hw_get_all_qdisc_async( void ) +{ + struct nlmsghdr hdr; + struct tcmsg tc; + SmHwThreadInfoT* thread_info; + SmErrorT error; + + thread_info = sm_hw_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + memset( &hdr, 0, sizeof(hdr) ); + hdr.nlmsg_len = NLMSG_LENGTH(sizeof(tc)); + hdr.nlmsg_type = RTM_GETQDISC; + hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + hdr.nlmsg_seq = ++(thread_info->msg_seq); + hdr.nlmsg_pid = getpid(); + + memset( &tc, 0, sizeof(tc) ); + tc.tcm_family = AF_UNSPEC; + + error = sm_netlink_send_request( thread_info->netlink_receive_socket, + &hdr, &tc, sizeof(tc) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to request all qdisc info, error=%s.", + sm_error_str(error) ); + return( error ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// **************************************************************************** +// Hardware - Netlink Interface Message Dispatch +// ============================================= +static void sm_hw_netlink_if_msg_dispatch( SmHwThreadInfoT* thread_info, + struct nlmsghdr* payload ) +{ + bool enabled; + struct ifinfomsg* if_msg; + int if_msg_size; + struct rtattr* if_msg_attr[IFLA_MAX+1]; + struct rtattr* if_msg_attr_tmp = NULL; + SmHwInterfaceChangeDataT if_change_data; + SmErrorT error; + + if_msg = (struct ifinfomsg*) NLMSG_DATA( payload ); + if_msg_size = payload->nlmsg_len - NLMSG_LENGTH( sizeof(struct ifinfomsg) ); + + if( 0 >= if_msg_size ) + { + DPRINTFE( "Netlink message has the wrong length( %i).", if_msg_size ); + return; + } + + if( AF_UNSPEC != if_msg->ifi_family ) + { + DPRINTFE( "Unknown interface address family (%i) received.", + if_msg->ifi_family ); + return; + } + + memset( &if_change_data, 0, sizeof( if_change_data ) ); + + int attr_i; + for( attr_i=0; IFLA_MAX >= attr_i; ++attr_i ) + { + if_msg_attr[attr_i] = NULL; + } + + if_msg_attr_tmp = IFLA_RTA( if_msg ); + + while( RTA_OK( if_msg_attr_tmp, if_msg_size ) ) + { + if( IFLA_MAX >= if_msg_attr_tmp->rta_type ) + { + if_msg_attr[if_msg_attr_tmp->rta_type] = if_msg_attr_tmp; + } + + if_msg_attr_tmp = RTA_NEXT( if_msg_attr_tmp, if_msg_size ); + } + + if( NULL == if_msg_attr[IFLA_IFNAME] ) + { + DPRINTFE( "Missing interface name for interface index %i.", + if_msg->ifi_index ); + return; + } + + snprintf( if_change_data.interface_name, + sizeof(if_change_data.interface_name), "%s", + (char*) RTA_DATA( if_msg_attr[IFLA_IFNAME] ) ); + + error = sm_hw_get_if_state( if_change_data.interface_name, &enabled ); + if(( SM_OKAY != error )&&( SM_NOT_FOUND != error )) + { + DPRINTFE( "Failed to get interface (%s) state information, " + "error=%s.", if_change_data.interface_name, + sm_error_str( error ) ); + return; + } else if( SM_NOT_FOUND == error ) { + if_change_data.type = SM_HW_INTERFACE_CHANGE_TYPE_DELETE; + if_change_data.interface_state = SM_INTERFACE_STATE_UNKNOWN; + } else { + if_change_data.type = SM_HW_INTERFACE_CHANGE_TYPE_ADD; + + if( enabled ) + { + if_change_data.interface_state = SM_INTERFACE_STATE_ENABLED; + } else { + if_change_data.interface_state = SM_INTERFACE_STATE_DISABLED; + } + } + + if( NULL != thread_info->callbacks.interface_change ) + { + thread_info->callbacks.interface_change( &if_change_data ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Hardware - Netlink IP Message Dispatch +// ====================================== +static void sm_hw_netlink_ip_msg_dispatch( SmHwThreadInfoT* thread_info, + struct nlmsghdr* payload ) +{ + int len; + struct ifaddrmsg* if_addr_msg; + struct rtattr* rta; + SmHwIpChangeDataT ip_info; + SmErrorT error; + + memset( &ip_info, 0, sizeof(SmHwIpChangeDataT) ); + + if( RTM_DELADDR == payload->nlmsg_type ) + { + ip_info.type = SM_HW_IP_CHANGE_TYPE_DELETE; + } else { + ip_info.type = SM_HW_IP_CHANGE_TYPE_ADD; + } + + if_addr_msg = (struct ifaddrmsg *) NLMSG_DATA( payload ); + len = IFA_PAYLOAD( payload ); + + error = sm_hw_get_if_name( if_addr_msg->ifa_index, + ip_info.interface_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to look up interface name, ifindex=%i, " + "error=%s.", (int) if_addr_msg->ifa_index, + sm_error_str(error) ); + return; + } + + DPRINTFD( "Interface %s (%i).", ip_info.interface_name, + if_addr_msg->ifa_index ); + + ip_info.prefix_len = if_addr_msg->ifa_prefixlen; + + for( rta = (struct rtattr *) IFA_RTA( if_addr_msg ); + RTA_OK( rta, len ); rta = RTA_NEXT( rta, len ) ) + { + if(( IFA_ADDRESS == rta->rta_type )||( IFA_LOCAL == rta->rta_type )|| + ( IFA_BROADCAST == rta->rta_type || IFA_ANYCAST == rta->rta_type )) + { + char ip_str[SM_NETWORK_ADDRESS_MAX_CHAR]; + + if( IFA_ADDRESS == rta->rta_type ) + { + ip_info.address_type = SM_HW_ADDRESS_TYPE_ADDRESS; + } else if( IFA_LOCAL == rta->rta_type ){ + ip_info.address_type = SM_HW_ADDRESS_TYPE_LOCAL; + } else if( IFA_BROADCAST == rta->rta_type ){ + ip_info.address_type = SM_HW_ADDRESS_TYPE_BROADCAST; + } else if( IFA_ANYCAST == rta->rta_type ){ + ip_info.address_type = SM_HW_ADDRESS_TYPE_ANYCAST; + } else { + ip_info.address_type = SM_HW_ADDRESS_TYPE_UNKNOWN; + } + + if( AF_INET == if_addr_msg->ifa_family ) + { + ip_info.address.type = SM_NETWORK_TYPE_IPV4; + ip_info.address.u.ipv4.sin + = *((struct in_addr*) RTA_DATA( rta )); + sm_network_address_str( &(ip_info.address), ip_str ); + DPRINTFD( "IPv4 address=%s/%i.", ip_str, ip_info.prefix_len ); + + if( NULL != thread_info->callbacks.ip_change ) + { + thread_info->callbacks.ip_change( &ip_info ); + } + } else if( AF_INET6 == if_addr_msg->ifa_family ) { + ip_info.address.type = SM_NETWORK_TYPE_IPV6; + memcpy( &(ip_info.address.u.ipv6.sin6), + (struct in6_addr*) RTA_DATA( rta ), + sizeof(struct in6_addr) ); + sm_network_address_str( &(ip_info.address), ip_str ); + DPRINTFD( "IPv6 address=%s/%i.", ip_str, ip_info.prefix_len ); + + if( NULL != thread_info->callbacks.ip_change ) + { + thread_info->callbacks.ip_change( &ip_info ); + } + } + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Hardware - Netlink QDisc Message Dispatch +// ========================================= +static void sm_hw_netlink_qdisc_msg_dispatch( SmHwThreadInfoT* thread_info, + struct nlmsghdr* payload ) +{ + struct tcmsg* tc = (struct tcmsg*) NLMSG_DATA(payload); + struct rtattr* tb[TCA_MAX+1]; + struct rtattr* rta; + int len; + SmHwQdiscInfoT qdisc_info; + SmErrorT error; + + memset( &qdisc_info, 0, sizeof(qdisc_info) ); + + error = sm_hw_get_if_name( tc->tcm_ifindex, qdisc_info.interface_name ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to look up interface name, ifindex=%i, error=%s.", + (int) tc->tcm_ifindex, sm_error_str(error) ); + return; + } + + len = payload->nlmsg_len - NLMSG_LENGTH(sizeof(struct tcmsg)); + if( 0 > len ) + { + DPRINTFE( "Invalid length detected." ); + return; + } + + memset( tb, 0, sizeof(tb) ); + + for( rta = TCA_RTA(tc); RTA_OK(rta, len); rta = RTA_NEXT(rta, len) ) + { + if( TCA_MAX >= rta->rta_type ) + { + tb[rta->rta_type] = rta; + } + } + + if( NULL == tb[TCA_KIND] ) + { + DPRINTFE( "Kind of qdisc not set." ); + return; + } + + snprintf( qdisc_info.queue_type, sizeof(qdisc_info.queue_type), + "%s", (const char *)RTA_DATA(tb[TCA_KIND]) ); + + snprintf( qdisc_info.handle, sizeof(qdisc_info.handle), + "%x:", tc->tcm_handle >> 16 ); + + if( tb[TCA_STATS2] ) + { + struct rtattr* tb_stats[TCA_STATS_MAX+1]; + + len = RTA_PAYLOAD(tb[TCA_STATS2]); + + for( rta = (struct rtattr*) RTA_DATA(tb[TCA_STATS2]); + RTA_OK(rta, len); rta = RTA_NEXT(rta, len) ) + { + if( TCA_STATS_MAX >= rta->rta_type ) + { + tb_stats[rta->rta_type] = rta; + } + } + + if( tb_stats[TCA_STATS_BASIC] ) + { + struct gnet_stats_basic basic_stats; + memset( &basic_stats, 0, sizeof(basic_stats) ); + + if( RTA_PAYLOAD(tb_stats[TCA_STATS_BASIC]) > sizeof(basic_stats) ) + { + memcpy( &basic_stats, RTA_DATA(tb_stats[TCA_STATS_BASIC]), + sizeof(basic_stats) ); + } else { + memcpy( &basic_stats, RTA_DATA(tb_stats[TCA_STATS_BASIC]), + RTA_PAYLOAD(tb_stats[TCA_STATS_BASIC]) ); + } + + qdisc_info.bytes = basic_stats.bytes; + qdisc_info.packets = basic_stats.packets; + } + + if( tb_stats[TCA_STATS_QUEUE] ) + { + struct gnet_stats_queue queue_stats; + memset( &queue_stats, 0, sizeof(queue_stats) ); + + if( RTA_PAYLOAD(tb_stats[TCA_STATS_QUEUE]) > sizeof(queue_stats) ) + { + memcpy( &queue_stats, RTA_DATA(tb_stats[TCA_STATS_QUEUE]), + sizeof(queue_stats) ); + } else { + memcpy( &queue_stats, RTA_DATA(tb_stats[TCA_STATS_QUEUE]), + RTA_PAYLOAD(tb_stats[TCA_STATS_QUEUE]) ); + } + + qdisc_info.q_length = queue_stats.qlen; + qdisc_info.backlog = queue_stats.backlog; + qdisc_info.drops = queue_stats.drops; + qdisc_info.requeues = queue_stats.requeues; + qdisc_info.overlimits = queue_stats.overlimits; + } + } + + if( NULL != thread_info->callbacks.qdisc_info ) + { + thread_info->callbacks.qdisc_info( &qdisc_info ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Hardware - Netlink Message Dispatch +// =================================== +static void sm_hw_netlink_msg_dispatch( int socket_fd, + struct sockaddr_nl* address, struct nlmsghdr* payload, + void* invocation_data ) +{ + SmHwThreadInfoT* thread_info = (SmHwThreadInfoT*) invocation_data; + + switch( payload->nlmsg_type ) + { + case RTM_NEWLINK: + case RTM_DELLINK: + case RTM_GETLINK: + sm_hw_netlink_if_msg_dispatch( thread_info, payload ); + break; + + case RTM_NEWADDR: + case RTM_GETADDR: + case RTM_DELADDR: + sm_hw_netlink_ip_msg_dispatch( thread_info, payload ); + break; + + case RTM_NEWQDISC: + case RTM_GETQDISC: + sm_hw_netlink_qdisc_msg_dispatch( thread_info, payload ); + break; + + case RTM_DELQDISC: + DPRINTFD( "Ignoring delete qdisc notification." ); + break; + + default: + DPRINTFI( "Ignoring netlink notification (%i).", + (int) payload->nlmsg_type ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Hardware - Netlink Dispatch +// =========================== +static void sm_hw_netlink_dispatch( int selobj, int64_t user_data ) +{ + SmHwThreadInfoT* thread_info; + SmErrorT error; + + thread_info = sm_hw_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return; + } + + error = sm_netlink_receive( selobj, sm_hw_netlink_msg_dispatch, + thread_info ); + if(( SM_OKAY != error )&&( SM_NO_MSG != error )) + { + DPRINTFE( "Failed to receive netlink message, error=%s.", + sm_error_str( error ) ); + return; + } +} +// *************************************************************************** + +// *************************************************************************** +// Hardware - Initialize +// ===================== +SmErrorT sm_hw_initialize( SmHwCallbacksT* callbacks ) +{ + int flags; + SmHwThreadInfoT* thread_info = NULL; + SmErrorT error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + unsigned int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + if( !(_threads[thread_i].inuse) ) + { + thread_info = &(_threads[thread_i]); + break; + } + } + + if( NULL == thread_info ) + { + DPRINTFE( "Failed to allocate thread information." ); + goto ERROR; + } + + memset( thread_info, 0, sizeof(SmHwThreadInfoT) ); + + thread_info->ioctl_socket = socket( PF_PACKET, SOCK_DGRAM, 0 ); + if( 0 > thread_info->ioctl_socket ) + { + DPRINTFE( "Unable to open a ioctl socket, errno=%s.", + strerror( errno ) ); + goto ERROR; + } + + flags = fcntl( thread_info->ioctl_socket, F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get ioctl socket flags, error=%s.", + strerror( errno ) ); + close( thread_info->ioctl_socket ); + thread_info->ioctl_socket = -1; + goto ERROR; + } + + if( 0 > fcntl( thread_info->ioctl_socket, F_SETFL, flags | O_NONBLOCK ) ) + { + DPRINTFE( "Failed to set ioctl socket flags, error=%s.", + strerror( errno ) ); + close( thread_info->ioctl_socket ); + thread_info->ioctl_socket = -1; + goto ERROR; + } + + if( NULL != callbacks ) + { + error = sm_netlink_open( &(thread_info->netlink_receive_socket), + RTMGRP_LINK | RTMGRP_IPV4_IFADDR | + RTMGRP_IPV6_IFADDR | RTMGRP_TC ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open netlink receive socket, error=%s.", + sm_error_str( error ) ); + close( thread_info->ioctl_socket ); + thread_info->ioctl_socket = -1; + goto ERROR; + } + + error = sm_selobj_register( thread_info->netlink_receive_socket, + sm_hw_netlink_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register netlink receive selection object, " + "error=%s.", sm_error_str( error ) ); + close( thread_info->ioctl_socket ); + thread_info->ioctl_socket = -1; + sm_netlink_close( thread_info->netlink_receive_socket ); + thread_info->netlink_receive_socket = -1; + goto ERROR; + } + + memcpy( &(thread_info->callbacks), callbacks, sizeof(SmHwCallbacksT) ); + } + + thread_info->thread_id = pthread_self(); + thread_info->inuse = true; + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); + +ERROR: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_FAILED ); +} +// *************************************************************************** + +// *************************************************************************** +// Hardware - Finalize +// =================== +SmErrorT sm_hw_finalize( void ) +{ + SmHwThreadInfoT* thread_info; + SmErrorT error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + thread_info = sm_hw_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + goto DONE; + } + + if( -1 < thread_info->netlink_receive_socket ) + { + error = sm_selobj_deregister( thread_info->netlink_receive_socket ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister netlink receive selection object, " + "error=%s.", sm_error_str( error ) ); + } + + sm_netlink_close( thread_info->netlink_receive_socket ); + thread_info->netlink_receive_socket = -1; + } + + if( -1 < thread_info->ioctl_socket ) + { + close( thread_info->ioctl_socket ); + thread_info->ioctl_socket = -1; + } + +DONE: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( SM_OKAY ); +} +// *************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_hw.h b/service-mgmt/sm-common-1.0.0/src/sm_hw.h new file mode 100644 index 00000000..eac07461 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_hw.h @@ -0,0 +1,133 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_HW_H__ +#define __SM_HW_H__ + +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_HW_QDISC_TYPE_MAX_CHAR 32 +#define SM_HW_QDISC_HANDLE_MAX_CHAR 32 + +typedef struct +{ + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + char queue_type[SM_HW_QDISC_TYPE_MAX_CHAR]; + char handle[SM_HW_QDISC_HANDLE_MAX_CHAR]; + uint64_t bytes; + uint64_t packets; + uint64_t q_length; + uint64_t backlog; + uint64_t drops; + uint64_t requeues; + uint64_t overlimits; +} SmHwQdiscInfoT; + +typedef enum +{ + SM_HW_INTERFACE_CHANGE_TYPE_UNKNOWN, + SM_HW_INTERFACE_CHANGE_TYPE_ADD, + SM_HW_INTERFACE_CHANGE_TYPE_DELETE, +} SmHwInterfaceChangeTypeT; + +typedef struct +{ + SmHwInterfaceChangeTypeT type; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmInterfaceStateT interface_state; +} SmHwInterfaceChangeDataT; + +typedef enum +{ + SM_HW_IP_CHANGE_TYPE_UNKNOWN, + SM_HW_IP_CHANGE_TYPE_ADD, + SM_HW_IP_CHANGE_TYPE_DELETE, +} SmHwIpChangeTypeT; + +typedef enum +{ + SM_HW_ADDRESS_TYPE_UNKNOWN, + SM_HW_ADDRESS_TYPE_ADDRESS, + SM_HW_ADDRESS_TYPE_LOCAL, + SM_HW_ADDRESS_TYPE_BROADCAST, + SM_HW_ADDRESS_TYPE_ANYCAST, +} SmHwAddressTypeT; + +typedef struct +{ + SmHwIpChangeTypeT type; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmHwAddressTypeT address_type; + SmNetworkAddressT address; + int prefix_len; +} SmHwIpChangeDataT; + +typedef void (*SmHwQdiscInfoCallbackT) (SmHwQdiscInfoT* data); +typedef void (*SmHwInterfaceChangeCallbackT) (SmHwInterfaceChangeDataT* data ); +typedef void (*SmHwIpChangeCallbackT) (SmHwIpChangeDataT* data); + +typedef struct +{ + SmHwQdiscInfoCallbackT qdisc_info; + SmHwInterfaceChangeCallbackT interface_change; + SmHwIpChangeCallbackT ip_change; +} SmHwCallbacksT; + +// *************************************************************************** +// Hardware - Get Interface By Network Address +// =========================================== +extern SmErrorT sm_hw_get_if_by_network_address( + SmNetworkAddressT* network_address, char if_name[] ); +// *************************************************************************** + +// *************************************************************************** +// Hardware - Get Interface Index +// ============================== +extern SmErrorT sm_hw_get_if_index( const char if_name[], int* if_index ); +// *************************************************************************** + +// *************************************************************************** +// Hardware - Get Interface Name +// ============================= +extern SmErrorT sm_hw_get_if_name( int if_index, char if_name[] ); +// *************************************************************************** + +// *************************************************************************** +// Sm Hardware - Get Interface State +// ================================= +extern SmErrorT sm_hw_get_if_state( const char if_name[], bool* enabled ); +// *************************************************************************** + +// *************************************************************************** +// Sm Hardware - Get All QDisc Asynchronous +// ======================================== +extern SmErrorT sm_hw_get_all_qdisc_async( void ); +// *************************************************************************** + +// *************************************************************************** +// Hardware - Initialize +// ===================== +extern SmErrorT sm_hw_initialize( SmHwCallbacksT* callbacks ); +// *************************************************************************** + +// *************************************************************************** +// Hardware - Finalize +// =================== +extern SmErrorT sm_hw_finalize( void ); +// *************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_HW_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_limits.h b/service-mgmt/sm-common-1.0.0/src/sm_limits.h new file mode 100644 index 00000000..528b09e0 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_limits.h @@ -0,0 +1,181 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_LIMITS_H__ +#define __SM_LIMITS_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// Process Limits. +#define SM_PROCESS_NAME_MAX_CHAR 32 +#define SM_PROCESS_MAX_RECURSIVE_CALL_DEPTH 4 + +// Thread Limits. +#define SM_THREADS_MAX 8 +#define SM_THREAD_NAME_MAX_CHAR 32 +#define SM_THREAD_SELECT_OBJS_MAX 64 + +// Log Limits. +#define SM_LOGS_MAX 2048 +#define SM_LOG_DOMAINS_MAX 8 +#define SM_LOG_DOMAIN_NAME_MAX_CHAR 32 +#define SM_LOG_SERVICE_GROUP_NAME_MAX_CHAR 32 +#define SM_LOG_ENTITY_NAME_MAX_CHAR 64 +#define SM_LOG_ENTITY_STATE_MAX_CHAR 32 +#define SM_LOG_ENTITY_STATUS_MAX_CHAR 32 +#define SM_LOG_ENTITY_CONDITION_MAX_CHAR 32 +#define SM_LOG_REASON_TEXT_MAX_CHAR 256 + +// Alarm Limits. +#define SM_ALARMS_MAX 64 +#define SM_ALARM_DOMAINS_MAX 8 +#define SM_ALARM_DOMAIN_NAME_MAX_CHAR 32 +#define SM_ALARM_ENTITY_NAME_MAX_CHAR 32 +#define SM_ALARM_ENTITY_STATE_MAX_CHAR 32 +#define SM_ALARM_ENTITY_STATUS_MAX_CHAR 32 +#define SM_ALARM_ENTITY_CONDITION_MAX_CHAR 32 +#define SM_ALARM_PROPOSED_REPAIR_ACTION_MAX_CHAR 256 +#define SM_ALARM_SPECIFIC_PROBLEM_TEXT_MAX_CHAR 256 +#define SM_ALARM_ADDITIONAL_TEXT_MAX_CHAR 256 + +// ISO8601 -Representation of Dates and Times Limits. +#define SM_ISO8601_DATE_TIME_MAX_CHAR 64 + +// Database Limits. +#define SM_DB_DISTINCT_STATEMENT_MAX_CHAR 512 +#define SM_DB_QUERY_STATEMENT_MAX_CHAR 1024 + +// SQL Limits. +#define SM_SQL_STATEMENT_MAX_CHAR 2048 + +// Node Limits. +#define SM_NODE_MAX 16 +#define SM_NODE_NAME_MAX_CHAR 32 +#define SM_NODE_ADMIN_STATE_MAX_CHAR 32 +#define SM_NODE_OPERATIONAL_STATE_MAX_CHAR 32 +#define SM_NODE_AVAIL_STATUS_MAX_CHAR 32 +#define SM_NODE_READY_STATE_MAX_CHAR 32 +#define SM_NODE_TYPE_MAX_CHAR 64 +#define SM_NODE_SUB_FUNCTIONS_MAX_CHAR 256 + +// Disk Limits. +#define SM_DISK_MAX 64 + +// Interface Limits. +#define SM_INTERFACE_MAX 4 +#define SM_INTERFACE_PEER_MAX (SM_NODE_MAX*SM_INTERFACE_MAX) +#define SM_INTERFACE_NAME_MAX_CHAR 32 +#define SM_INTERFACE_STATE_MAX_CHAR 32 + +// Network Address Limits. +#define SM_NETWORK_TYPE_MAX_CHAR 32 +#define SM_NETWORK_ADDRESS_MAX_CHAR 256 + +// Authentication Limits. +#define SM_AUTHENTICATION_TYPE_MAX_CHAR 32 +#define SM_AUTHENTICATION_KEY_MAX_CHAR 128 +#define SM_AUTHENTICATION_VECTOR_MAX_CHAR 64 + +// Orchestration Limits. +#define SM_ORCHESTRATION_MAX_CHAR 32 + +// Designation Limits. +#define SM_DESIGNATION_MAX_CHAR 32 + +// Path Limits. +#define SM_PATH_TYPE_MAX_CHAR 32 + +// System mode limits +#define SM_SYSTEM_MODE_MAX_CHAR 32 + +// System type limits +#define SM_SYSTEM_TYPE_MAX_CHAR 32 + +// Service Domain Limits. +#define SM_SERVICE_DOMAIN_PROVISIONED_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_NAME_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_INTERFACE_NAME_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_PREEMPT_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_STATE_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_SCHED_STATE_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_SCHED_LIST_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_INTERFACE_PROVISIONED_MAX_CHAR 32 + +// Service Domain Member Limits. +#define SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_MEMBER_PROVISIONED_MAX_CHAR 32 + +// Service Domain Neighbor Limits. +#define SM_SERVICE_DOMAIN_NEIGHBOR_STATE_MAX_CHAR 32 +#define SM_SERVICE_DOMAIN_NEIGHBOR_EXCHANGE_MASTER_MAX_CHAR 32 + +// Service Group Limits. +#define SM_SERVICE_GROUP_PROVISIONED_MAX_CHAR 32 +#define SM_SERVICE_GROUP_NAME_MAX_CHAR 32 +#define SM_SERVICE_GROUP_AUTO_RECOVER_MAX_CHAR 32 +#define SM_SERVICE_GROUP_CORE_MAX_CHAR 32 +#define SM_SERVICE_GROUP_STATE_MAX_CHAR 32 +#define SM_SERVICE_GROUP_STATUS_MAX_CHAR 32 +#define SM_SERVICE_GROUP_CONDITION_MAX_CHAR 32 +#define SM_SERVICE_GROUP_ACTION_MAX_CHAR 32 +#define SM_SERVICE_GROUP_AGGREGATE_NAME_MAX_CHAR 32 +#define SM_SERVICE_GROUP_REASON_TEXT_MAX_CHAR 256 +#define SM_SERVICE_GROUP_FATAL_ERROR_REBOOT_MAX_CHAR 32 + +// Configuration limits +#define SM_CONFIGURATION_KEY_MAX_CHAR 32 +#define SM_CONFIGURATION_VALUE_MAX_CHAR 32 + +// Service Group Member Limits. +#define SM_SERVICE_GROUP_MEMBER_PROVISIONED_MAX_CHAR 32 + +// Service Limits. +#define SM_SERVICE_PROVISIONED_MAX_CHAR 32 +#define SM_SERVICE_NAME_MAX_CHAR 32 +#define SM_SERVICE_ADMIN_STATE_MAX_CHAR 32 +#define SM_SERVICE_STATE_MAX_CHAR 32 +#define SM_SERVICE_STATUS_MAX_CHAR 32 +#define SM_SERVICE_CONDITION_MAX_CHAR 32 +#define SM_SERVICE_SEVERITY_MAX_CHAR 32 +#define SM_SERVICE_PID_FILE_MAX_CHAR 256 + +// Service Heartbeat Limits. +#define SM_SERVICE_HEARTBEAT_PROVISIONED_MAX_CHAR 32 +#define SM_SERVICE_HEARTBEAT_NAME_MAX_CHAR 32 +#define SM_SERVICE_HEARTBEAT_TYPE_MAX_CHAR 32 +#define SM_SERVICE_HEARTBEAT_ADDRESS_MAX_CHAR 256 +#define SM_SERVICE_HEARTBEAT_MESSAGE_MAX_CHAR 256 +#define SM_SERVICE_HEARTBEAT_STATE_MAX_CHAR 32 + +// Service Dependency Limits. +#define SM_SERVICE_DEPENDENCY_PROVISIONED_MAX_CHAR 32 +#define SM_SERVICE_DEPENDENCY_MAX_CHAR 32 + +// Service Instance Limits. +#define SM_SERVICE_INSTANCE_NAME_MAX_CHAR 32 +#define SM_SERVICE_INSTANCE_PARAMS_MAX_CHAR 1024 + +// Service Action Limits. +#define SM_SERVICE_ACTION_NAME_MAX_CHAR 32 +#define SM_SERVICE_ACTION_PLUGIN_EXEC_MAX_CHAR 256 +#define SM_SERVICE_ACTION_PLUGIN_TYPE_MAX_CHAR 32 +#define SM_SERVICE_ACTION_PLUGIN_CLASS_MAX_CHAR 32 +#define SM_SERVICE_ACTION_PLUGIN_NAME_MAX_CHAR 80 +#define SM_SERVICE_ACTION_PLUGIN_COMMAND_MAX_CHAR 80 +#define SM_SERVICE_ACTION_PLUGIN_PARAMS_MAX_CHAR 1024 +#define SM_SERVICE_ACTION_PLUGIN_EXIT_CODE_MAX_CHAR 10 + +// Service Action Result Limits. +#define SM_SERVICE_ACTION_RESULT_MAX_CHAR 32 +#define SM_SERVICE_ACTION_RESULT_REASON_TEXT_MAX_CHAR 256 + +#ifdef __cplusplus +} +#endif + +#endif // __SM_LIMITS_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_list.h b/service-mgmt/sm-common-1.0.0/src/sm_list.h new file mode 100644 index 00000000..2e5c9e3c --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_list.h @@ -0,0 +1,147 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_LIST_H__ +#define __SM_LIST_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef GList SmListT; + +typedef GCompareFunc SmListCompareFunctionT; + +#define SM_POINTER_TO_INT( pointer ) GPOINTER_TO_INT( pointer ) +#define SM_INT_TO_POINTER( integer ) GINT_TO_POINTER( integer ) + +#define SM_POINTER_TO_UINT( pointer ) GPOINTER_TO_UINT( pointer ) +#define SM_UINT_TO_POINTER( integer ) GUINT_TO_POINTER( integer ) + +typedef gpointer SmListEntryDataPtrT; + +// **************************************************************************** +// List - Length +// ============= +#define SM_LIST_LENGTH( list ) \ + g_list_length( list ) +// **************************************************************************** + +// **************************************************************************** +// List - For-Each +// =============== +#define SM_LIST_FOREACH( list, entry, var ) \ + for( entry = g_list_first(list), \ + var = ((NULL == entry) ? NULL : entry->data); \ + NULL != entry; \ + entry = g_list_next(entry), \ + var = ((NULL == entry) ? NULL : entry->data) ) +// **************************************************************************** + +// **************************************************************************** +// List - For-Each Safe +// ==================== +#define SM_LIST_FOREACH_SAFE( list, entry, next, var ) \ + for( entry = g_list_first(list), \ + next = ((NULL == entry) ? NULL : g_list_next(entry)), \ + var = ((NULL == entry) ? NULL : entry->data); \ + NULL != entry; \ + entry = next, \ + next = ((NULL == entry) ? NULL : g_list_next(entry)), \ + var = ((NULL == entry) ? NULL : entry->data) ) +// **************************************************************************** + +// **************************************************************************** +// List - Sort +// =========== +#define SM_LIST_SORT( list, compare_function ) \ + list = g_list_sort( list, compare_function ) +// **************************************************************************** + +// **************************************************************************** +// List - First +// ============ +#define SM_LIST_FIRST( list, entry, var ) \ + entry = g_list_first( list ), \ + var = ((NULL == entry) ? NULL : entry->data); +// **************************************************************************** + +// **************************************************************************** +// List - Last +// =========== +#define SM_LIST_LAST( list, entry, var ) \ + entry = g_list_last( list ), \ + var = ((NULL == entry) ? NULL : entry->data); +// **************************************************************************** + +// **************************************************************************** +// List - Prepend +// ============== +#define SM_LIST_PREPEND( list, entry ) \ + if( NULL == g_list_find( list, entry ) ) \ + list = g_list_prepend( list, entry ); +// **************************************************************************** + +// **************************************************************************** +// List - Append +// ============= +#define SM_LIST_APPEND( list, entry ) \ + if( NULL == g_list_find( list, entry ) ) \ + list = g_list_append( list, entry ); +// **************************************************************************** + +// **************************************************************************** +// List - Remove +// ============= +#define SM_LIST_REMOVE( list, entry ) \ + list = g_list_remove( list, entry ); +// **************************************************************************** + +// **************************************************************************** +// List - Delete +// ============= +#define SM_LIST_DELETE( list, entry ) \ + list = g_list_delete_link( list, entry ); +// **************************************************************************** + +// **************************************************************************** +// List - Cleanup +// ============== +#define SM_LIST_CLEANUP( list ) \ + g_list_free( list ); \ + list = NULL; +// **************************************************************************** + +// **************************************************************************** +// List - Cleanup All +// ================== +#define SM_LIST_CLEANUP_ALL( list ) \ + if( NULL != list ) \ + { \ + g_list_foreach( list, (GFunc)g_free, NULL ); \ + g_list_free( list ); \ + list = NULL; \ + } +// **************************************************************************** + +// **************************************************************************** +// List - Cleanup All With Entry Cleanup +// ===================================== +#define SM_LIST_CLEANUP_ALL_WITH_ENTRY_CLEANUP( list, cleanup_entry_callback ) \ + if( NULL != list ) \ + { \ + g_list_foreach( list, (GFunc)cleanup_entry_callback, NULL ); \ + g_list_free( list ); \ + list = NULL; \ + } +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_LIST_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_netlink.c b/service-mgmt/sm-common-1.0.0/src/sm_netlink.c new file mode 100644 index 00000000..86cde789 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_netlink.c @@ -0,0 +1,436 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_netlink.h" + +#include "sm_types.h" +#include "sm_debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SM_NETLINK_TX_MSG_MAX_LEN 2048 +#define SM_NETLINK_RX_MSG_MAX_LEN 4096 + +#define SM_NETLINK_MAX_SOCKET_SIZE 2097152 + +static char _tx_buffer[SM_NETLINK_TX_MSG_MAX_LEN] __attribute__((aligned)); +static char _rx_buffer[SM_NETLINK_RX_MSG_MAX_LEN] __attribute__((aligned)); + +// *************************************************************************** +// Netlink - Get Tx Buffer +// ======================= +void* sm_netlink_get_tx_buffer( void ) +{ + memset( _tx_buffer, 0, sizeof(_tx_buffer) ); + return( &(_tx_buffer[0]) ); +} +// *************************************************************************** + +// *************************************************************************** +// Netlink - Set Blocking +// ====================== +static SmErrorT sm_netlink_set_blocking( int socket_fd, bool block ) +{ + int flags; + + flags = fcntl( socket_fd, F_GETFL, 0 ); + if( 0 > flags ) + { + DPRINTFE( "Failed to get flags, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + if( block ) + { + flags &= ~O_NONBLOCK; + } else { + flags |= O_NONBLOCK; + } + + if( 0 > fcntl( socket_fd, F_SETFL, flags ) ) + { + DPRINTFE( "Failed to set flags, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Netlink - Add Attribute +// ======================= +void sm_netlink_add_attribute( struct nlmsghdr* payload, int type, + void* data, int data_length ) +{ + struct rtattr* rta; + int len = RTA_LENGTH( data_length ); + + rta = (struct rtattr*) + (((char*) payload) + NLMSG_ALIGN( payload->nlmsg_len )); + rta->rta_type = type; + rta->rta_len = len; + memcpy( RTA_DATA( rta ), data, data_length ); + payload->nlmsg_len = NLMSG_ALIGN( payload->nlmsg_len ) + len; +} +// *************************************************************************** + +// *************************************************************************** +// Netlink - Send +// ============== +SmErrorT sm_netlink_send( int socket_fd, struct nlmsghdr* payload ) +{ + struct sockaddr_nl address; + struct iovec io_vec; + struct msghdr msg_hdr; + + memset( &address, 0, sizeof(address) ); + address.nl_family = AF_NETLINK; + address.nl_pad = 0; // unused + address.nl_pid = 0; // kernel + address.nl_groups = 0; // kernel notifications + + memset( &io_vec, 0, sizeof(io_vec) ); + io_vec.iov_base = (void*) payload; + io_vec.iov_len = payload->nlmsg_len; + + memset( &msg_hdr, 0, sizeof(msg_hdr) ); + msg_hdr.msg_name = &address; + msg_hdr.msg_namelen = sizeof(address); + msg_hdr.msg_iov = &io_vec; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_control = NULL; + msg_hdr.msg_controllen = 0; + msg_hdr.msg_flags = 0; + + if( 0 > sendmsg( socket_fd, &msg_hdr, 0 ) ) + { + DPRINTFE( "Send failed, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Netlink - Send Request +// ====================== +SmErrorT sm_netlink_send_request( int socket_fd, struct nlmsghdr* payload, + void* request, int request_len ) +{ + struct sockaddr_nl address; + struct iovec io_vec[2]; + struct msghdr msg_hdr; + + memset( &address, 0, sizeof(address) ); + address.nl_family = AF_NETLINK; + address.nl_pad = 0; // unused + address.nl_pid = 0; // kernel + address.nl_groups = 0; // kernel notifications + + memset( &io_vec, 0, sizeof(io_vec) ); + io_vec[0].iov_base = (void*) payload; + io_vec[0].iov_len = payload->nlmsg_len; + io_vec[1].iov_base = (void*) request; + io_vec[1].iov_len = request_len; + + memset( &msg_hdr, 0, sizeof(msg_hdr) ); + msg_hdr.msg_name = &address; + msg_hdr.msg_namelen = sizeof(address); + msg_hdr.msg_iov = &(io_vec[0]); + msg_hdr.msg_iovlen = 2; + msg_hdr.msg_control = NULL; + msg_hdr.msg_controllen = 0; + msg_hdr.msg_flags = 0; + + if( 0 > sendmsg( socket_fd, &msg_hdr, 0 ) ) + { + DPRINTFE( "Send failed, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Netlink - Receive +// ================= +SmErrorT sm_netlink_receive( int socket_fd, SmNetlinkCallbackT callback, + void* invocation_data ) +{ + struct sockaddr_nl address; + struct msghdr msg_hdr; + struct iovec io_vec; + struct nlmsghdr* payload; + + int retry_i; + for( retry_i = 10; 0 != retry_i; --retry_i ) + { + memset( &address, 0, sizeof(struct sockaddr_nl) ); + + address.nl_family = AF_NETLINK; + address.nl_pad = 0; + address.nl_pid = 0; + address.nl_groups = 0; + + memset( &io_vec, 0, sizeof(io_vec) ); + memset( &msg_hdr, 0, sizeof(msg_hdr) ); + memset( _rx_buffer, 0, sizeof(_rx_buffer) ); + + io_vec.iov_base = _rx_buffer; + io_vec.iov_len = sizeof(_rx_buffer); + + msg_hdr.msg_name = (void *) &address; + msg_hdr.msg_namelen = sizeof(address); + msg_hdr.msg_iov = &io_vec; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_control = NULL; + msg_hdr.msg_controllen = 0; + msg_hdr.msg_flags = 0; + + unsigned int length = recvmsg( socket_fd, &msg_hdr, 0 ); + if( 0 > length ) + { + if( EINTR == errno ) + { + DPRINTFD( "Message receive interrupted, retry=%d, " + "errno=%s.", retry_i, strerror( errno ) ); + continue; + + } else if( EAGAIN == errno ) { + DPRINTFD( "Message receive error, error=%s", strerror( errno ) ); + return( SM_NO_MSG ); + } + + DPRINTFE( "Message receive error, errno=%s.", strerror(errno) ); + return( SM_FAILED ); + + } else if( 0 == length ) { + DPRINTFD( "No messages received." ); + return( SM_NO_MSG ); + } + + DPRINTFD( "Netlink message received." ); + + for( payload = (struct nlmsghdr*) _rx_buffer; + NLMSG_OK( payload, length ); + payload = NLMSG_NEXT( payload, length ) + ) + { + if( NLMSG_ERROR == payload->nlmsg_type ) + { + struct nlmsgerr* err_msg; + err_msg = (struct nlmsgerr*) NLMSG_DATA( payload ); + + if( 0 == err_msg->error ) + { + if( payload->nlmsg_flags & NLM_F_MULTI ) + { + // Multi part message need to continue. + continue; + } + + DPRINTFD( "Netlink ack received." ); + return( SM_OKAY ); + } + + if(( -EEXIST == err_msg->error )&& + (( RTM_NEWROUTE == err_msg->msg.nlmsg_type )|| + ( RTM_NEWADDR == err_msg->msg.nlmsg_type ))) + { + DPRINTFD( "Netlink error message received, msg_pid=%i, " + "msg_type=%i, msg_seq_num=%i, errno=%s.", + err_msg->msg.nlmsg_pid, err_msg->msg.nlmsg_type, + err_msg->msg.nlmsg_seq, + strerror( err_msg->error ) ); + return( SM_OKAY ); + } + + DPRINTFE( "Netlink error message received, msg_pid=%i, " + "msg_type=%i, msg_seq_num=%i, errno=%s.", + err_msg->msg.nlmsg_pid, err_msg->msg.nlmsg_type, + err_msg->msg.nlmsg_seq, strerror( err_msg->error ) ); + return( SM_FAILED ); + } + + if( NLMSG_OVERRUN == payload->nlmsg_type ) + { + DPRINTFE( "Netlink overrun message received." ); + return( SM_FAILED ); + } + + if( NLMSG_NOOP == payload->nlmsg_type ) + { + DPRINTFE( "Netlink no-op message received." ); + return( SM_NO_MSG ); + } + + if( NLMSG_DONE == payload->nlmsg_type ) + { + DPRINTFD( "Netlink done message received." ); + return( SM_OKAY ); + } + + if( NULL != callback ) + { + callback( socket_fd, &address, payload, invocation_data ); + } + } + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Netlink - Command +// ================= +SmErrorT sm_netlink_command( int socket_fd, struct nlmsghdr* payload, + SmNetlinkCallbackT callback, void* invocation_data ) +{ + struct sockaddr_nl address; + struct iovec io_vec; + struct msghdr msg_hdr; + SmErrorT error, error2; + + memset( &address, 0, sizeof(address) ); + address.nl_family = AF_NETLINK; + address.nl_pad = 0; // unused + address.nl_pid = 0; // kernel + address.nl_groups = 0; // kernel notifications + + memset( &io_vec, 0, sizeof(io_vec) ); + io_vec.iov_base = (void*) payload; + io_vec.iov_len = payload->nlmsg_len; + + memset( &msg_hdr, 0, sizeof(msg_hdr) ); + msg_hdr.msg_name = &address; + msg_hdr.msg_namelen = sizeof(address); + msg_hdr.msg_iov = &io_vec; + msg_hdr.msg_iovlen = 1; + msg_hdr.msg_control = NULL; + msg_hdr.msg_controllen = 0; + msg_hdr.msg_flags = 0; + + payload->nlmsg_flags |= NLM_F_ACK; + + if( 0 > sendmsg( socket_fd, &msg_hdr, 0 ) ) + { + DPRINTFE( "Send failed, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + error = sm_netlink_set_blocking( socket_fd, true ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set socket to blocking." ); + return( error ); + } + + error = sm_netlink_receive( socket_fd, callback, invocation_data ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to receive response, error=%s.", + sm_error_str( error ) ); + } + + error2 = sm_netlink_set_blocking( socket_fd, false ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to set socket to non-blocking, error=%s.", + sm_error_str( error2 ) ); + } + + return( error ); +} +// *************************************************************************** + +// **************************************************************************** +// Netlink - Open +// ============== +SmErrorT sm_netlink_open( int* socket_fd, unsigned long groups ) +{ + int fd; + int socket_size = SM_NETLINK_MAX_SOCKET_SIZE; + SmErrorT error; + + *socket_fd = -1; + + // Open a netlink socket for sending messages. + fd = socket( AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE ); + if( 0 > fd ) + { + DPRINTFE( "Unable to open socket, errno=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + // Make sure the netlink socket is non-blocking. + error = sm_netlink_set_blocking( fd, false ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set socket to non-blocking." ); + close( fd ); + return( SM_FAILED ); + } + + // Set netlink socket buffer size. + if( 0 > setsockopt( fd, SOL_SOCKET, SO_RCVBUF, &socket_size, + sizeof(socket_size) ) ) + { + DPRINTFE( "Cannot set buffer size: error=%s.", strerror( errno ) ); + close( fd ); + return( SM_FAILED ); + } + + // Bind the netlink socket to our address information. + if( 0 != groups ) + { + struct sockaddr_nl address; + + memset( &address, 0, sizeof(address) ); + + address.nl_family = AF_NETLINK; + address.nl_pad = 0; + address.nl_pid = getpid(); + address.nl_groups = groups; + + if( 0 > bind( fd, (struct sockaddr*) &address, sizeof(address) ) ) + { + DPRINTFE( "Unable to bind address, errno=%s.", strerror( errno ) ); + close( fd ); + return( SM_FAILED ); + } + } + + *socket_fd = fd; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Netlink - Close +// =============== +SmErrorT sm_netlink_close( int socket_fd ) +{ + if( -1 < socket_fd ) + { + close( socket_fd ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_netlink.h b/service-mgmt/sm-common-1.0.0/src/sm_netlink.h new file mode 100644 index 00000000..dc6e962b --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_netlink.h @@ -0,0 +1,77 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NETLINK_H__ +#define __SM_NETLINK_H__ + +#include +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmNetlinkCallbackT) (int socket_fd, struct sockaddr_nl* address, + struct nlmsghdr* payload, void* invocation_data ); + +// *************************************************************************** +// Netlink - Get Tx Buffer +// ======================= +extern void* sm_netlink_get_tx_buffer( void ); +// *************************************************************************** + +// *************************************************************************** +// Netlink - Add Attribute +// ======================= +extern void sm_netlink_add_attribute( struct nlmsghdr* payload, int type, + void* data, int data_length ); +// *************************************************************************** + +// *************************************************************************** +// Netlink - Send +// ============== +extern SmErrorT sm_netlink_send( int socket_fd, struct nlmsghdr* payload ); +// *************************************************************************** + +// *************************************************************************** +// Netlink - Send Request +// ====================== +extern SmErrorT sm_netlink_send_request( int socket_fd, + struct nlmsghdr* payload, void* request, int request_len ); +// *************************************************************************** + +// *************************************************************************** +// Netlink - Receive +// ================= +extern SmErrorT sm_netlink_receive( int socket_fd, SmNetlinkCallbackT callback, + void* invocation_data ); +// *************************************************************************** + +// *************************************************************************** +// Netlink - Command +// ================= +extern SmErrorT sm_netlink_command( int socket_fd, struct nlmsghdr* payload, + SmNetlinkCallbackT callback, void* invocation_data ); +// *************************************************************************** + +// **************************************************************************** +// Netlink - Open +// ============== +extern SmErrorT sm_netlink_open( int* socket_fd, unsigned long groups ); +// **************************************************************************** + +// **************************************************************************** +// Netlink - Close +// =============== +extern SmErrorT sm_netlink_close( int socket_fd ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NETLINK_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_node_stats.c b/service-mgmt/sm-common-1.0.0/src/sm_node_stats.c new file mode 100644 index 00000000..4d6375b3 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_node_stats.c @@ -0,0 +1,445 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_node_stats.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" + +#define SM_NODE_STATS_PROC_STAT "/proc/stat" +#define SM_NODE_STATS_PROC_MEMINFO "/proc/meminfo" +#define SM_NODE_STATS_PROC_DISKSTATS "/proc/diskstats" +#define SM_NODE_STATS_PROC_NET_DEV "/proc/net/dev" + +static long _user_hz = 0; + +// **************************************************************************** +// Node Statistics - Get CPU +// ========================= +SmErrorT sm_node_stats_get_cpu( const char cpu_name[], SmNodeCpuStatsT* stats ) +{ + char line[512]; + FILE* fp; + + memset( stats, 0, sizeof(SmNodeCpuStatsT) ); + + if( 0 == _user_hz ) + { + DPRINTFE( "User hertz is not defined." ); + return( SM_FAILED ); + } + + if( '\0' == cpu_name[0] ) + { + snprintf( stats->cpu_name, sizeof(stats->cpu_name), "all" ); + } else { + snprintf( stats->cpu_name, sizeof(stats->cpu_name), "%s", cpu_name ); + } + + fp = fopen( SM_NODE_STATS_PROC_STAT, "r" ); + if( NULL == fp ) + { + DPRINTFE( "Failed to get cpu statistics from %s.", + SM_NODE_STATS_PROC_STAT ); + return( SM_NOT_FOUND ); + } + + while( NULL != fgets( line, sizeof(line), fp ) ) + { + if((( '\0' == cpu_name[0] )&&( 0 == strncmp( line, "cpu ", 4 ) ))|| + ( 0 == strncmp( line, cpu_name, 4 ) )) + { + sscanf( line+5, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", + &(stats->user_cpu_usage), + &(stats->nice_cpu_usage), + &(stats->system_cpu_usage), + &(stats->idle_task_cpu_usage), + &(stats->iowait_cpu_usage), + &(stats->irq_cpu_usage), + &(stats->soft_irq_cpu_usage), + &(stats->steal_cpu_usage), + &(stats->guest_cpu_usage), + &(stats->guest_nice_cpu_usage) ); + + } else if( 0 == strncmp( line, "intr ", 5 ) ) { + sscanf( line+5, "%llu", &(stats->total_interrupts) ); + + } else if( 0 == strncmp( line, "ctxt ", 5 ) ) { + sscanf( line+5, "%llu", &(stats->total_context_switches) ); + + } else if( 0 == strncmp( line, "processes ", 10 ) ) { + sscanf( line+10, "%llu", &(stats->total_processes) ); + + } else if( 0 == strncmp( line, "procs_running ", 14 ) ) { + sscanf( line+14, "%llu", &(stats->processes_running) ); + + } else if( 0 == strncmp( line, "procs_blocked ", 14 ) ) { + sscanf( line+14, "%llu", &(stats->processes_blocked) ); + + } else if( 0 == strncmp( line, "btime ", 6 ) ) { + sscanf( line+6, "%llu", &(stats->boot_time_in_secs) ); + } + } + + fclose( fp ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Memory +// ============================ +SmErrorT sm_node_stats_get_memory( SmNodeMemStatsT* stats ) +{ + char line[512]; + FILE* fp; + + memset( stats, 0, sizeof(SmNodeMemStatsT) ); + + fp = fopen( SM_NODE_STATS_PROC_MEMINFO, "r" ); + if( NULL == fp ) + { + DPRINTFE( "Failed to get memory statistics from %s.", + SM_NODE_STATS_PROC_MEMINFO ); + return( SM_NOT_FOUND ); + } + + while( NULL != fgets( line, sizeof(line), fp ) ) + { + if( 0 == strncmp( line, "MemTotal:", 9 ) ) + { + sscanf( line+9, "%lu", &(stats->total_memory_kB) ); + + } else if( 0 == strncmp( line, "MemFree:", 8 ) ) { + sscanf( line+8, "%lu", &(stats->free_memory_kB) ); + + } else if( 0 == strncmp( line, "Buffers:", 8 ) ) { + sscanf( line+8, "%lu", &(stats->buffers_kB) ); + + } else if( 0 == strncmp( line, "Cached:", 7 ) ) { + sscanf( line+7, "%lu", &(stats->cached_kB) ); + + } else if( 0 == strncmp( line, "SwapCached:", 11 ) ) { + sscanf( line+11, "%lu", &(stats->swap_cached_kB) ); + + } else if( 0 == strncmp( line, "SwapTotal:", 10 ) ) { + sscanf( line+10, "%lu", &(stats->swap_total_kB) ); + + } else if( 0 == strncmp( line, "SwapFree:", 9 ) ) { + sscanf( line+9, "%lu", &(stats->swap_free_kB) ); + + } else if( 0 == strncmp( line, "Active:", 7 ) ) { + sscanf( line+7, "%lu", &(stats->active_kB) ); + + } else if( 0 == strncmp( line, "Inactive:", 9 ) ) { + sscanf( line+9, "%lu", &(stats->inactive_kB) ); + + } else if( 0 == strncmp( line, "Dirty:", 6 ) ) { + sscanf( line+6, "%lu", &(stats->dirty_kB) ); + + } else if( 0 == strncmp( line, "HugePages_Total:", 16 ) ) { + sscanf( line+16, "%lu", &(stats->hugepages_total) ); + + } else if( 0 == strncmp( line, "HugePages_Free:", 15 ) ) { + sscanf( line+15, "%lu", &(stats->hugepages_free) ); + + } else if( 0 == strncmp( line, "Hugepagesize:", 13 ) ) { + sscanf( line+13, "%lu", &(stats->hugepage_size_kB) ); + + } else if( 0 == strncmp( line, "NFS_Unstable:", 13 ) ) { + sscanf( line+13, "%lu", &(stats->nfs_uncommited_kB) ); + + } else if( 0 == strncmp( line, "Committed_AS:", 13 ) ) { + sscanf( line+13, "%lu", &(stats->commited_memory_kB) ); + } + } + + fclose( fp ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Disk +// ========================== +SmErrorT sm_node_stats_get_disk( const char dev_name[], + SmNodeDiskStatsT* stats ) +{ + int n_scanned; + char line[512]; + FILE* fp; + + memset( stats, 0, sizeof(SmNodeDiskStatsT) ); + + fp = fopen( SM_NODE_STATS_PROC_DISKSTATS, "r" ); + if( NULL == fp ) + { + DPRINTFE( "Failed to get disk statistics for %s from %s.", + dev_name, SM_NODE_STATS_PROC_DISKSTATS ); + return( SM_NOT_FOUND ); + } + + while( NULL != fgets( line, sizeof(line), fp ) ) + { + n_scanned = sscanf( line, "%u %u %s " + "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &(stats->major_num), &(stats->minor_num), + stats->dev_name, + &(stats->reads_completed), + &(stats->reads_merged), + &(stats->sectors_read), + &(stats->ms_spent_reading), + &(stats->writes_completed), + &(stats->writes_merged), + &(stats->sectors_written), + &(stats->ms_spent_writing), + &(stats->io_inprogress), + &(stats->ms_spent_io), + &(stats->weighted_ms_spent_io) ); + if( 14 == n_scanned ) + { + if( 0 == strcmp( dev_name, stats->dev_name ) ) + { + DPRINTFD( "Disk (%s) stats read.", dev_name ); + break; + } + } + + memset( stats, 0, sizeof(SmNodeDiskStatsT) ); + } + + fclose( fp ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Disk By Index +// =================================== +SmErrorT sm_node_stats_get_disk_by_index( unsigned int index, + SmNodeDiskStatsT* stats ) +{ + unsigned int current_index = 0; + int n_scanned; + char line[512]; + FILE* fp; + + memset( stats, 0, sizeof(SmNodeDiskStatsT) ); + + fp = fopen( SM_NODE_STATS_PROC_DISKSTATS, "r" ); + if( NULL == fp ) + { + DPRINTFE( "Failed to get disk statistics from %s.", + SM_NODE_STATS_PROC_DISKSTATS ); + return( SM_NOT_FOUND ); + } + + while( NULL != fgets( line, sizeof(line), fp ) ) + { + if( current_index == index ) + { + n_scanned = sscanf( line, "%u %u %s " + "%lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu", + &(stats->major_num), &(stats->minor_num), + stats->dev_name, + &(stats->reads_completed), + &(stats->reads_merged), + &(stats->sectors_read), + &(stats->ms_spent_reading), + &(stats->writes_completed), + &(stats->writes_merged), + &(stats->sectors_written), + &(stats->ms_spent_writing), + &(stats->io_inprogress), + &(stats->ms_spent_io), + &(stats->weighted_ms_spent_io) ); + if( 14 == n_scanned ) + { + break; + } + + memset( stats, 0, sizeof(SmNodeDiskStatsT) ); + } + + ++current_index; + } + + fclose( fp ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Network Device +// ==================================== +SmErrorT sm_node_stats_get_netdev( const char dev_name[], + SmNodeNetDevStatsT* stats ) +{ + int stats_start = 0; + char line[512]; + char if_name[512]; + char dev_name_with_colon[512]; + FILE* fp; + + memset( stats, 0, sizeof(SmNodeNetDevStatsT) ); + + snprintf( stats->dev_name, sizeof(stats->dev_name), "%s", dev_name ); + + snprintf( dev_name_with_colon, sizeof(dev_name_with_colon), "%s:", + dev_name ); + + fp = fopen( SM_NODE_STATS_PROC_NET_DEV, "r" ); + if( NULL == fp ) + { + DPRINTFE( "Failed to get network device statistics for %s from %s.", + dev_name, SM_NODE_STATS_PROC_NET_DEV ); + return( SM_NOT_FOUND ); + } + + while( NULL != fgets( line, sizeof(line), fp ) ) + { + stats_start = strcspn( line, ":" ); + sscanf( line, "%s:", if_name ); + if( 0 == strncmp( if_name, dev_name_with_colon, strlen(if_name) ) ) + { + sscanf( line+stats_start+2, + "%llu %llu %llu %llu %llu %llu %llu %llu " + "%llu %llu %llu %llu %llu %llu %llu %llu", + &(stats->rx_bytes), + &(stats->rx_packets), + &(stats->rx_errors), + &(stats->rx_dropped), + &(stats->rx_fifo_errors), + &(stats->rx_frame_errors), + &(stats->rx_compressed_packets), + &(stats->rx_multicast_frames), + &(stats->tx_bytes), + &(stats->tx_packets), + &(stats->tx_errors), + &(stats->tx_dropped), + &(stats->tx_fifo_errors), + &(stats->tx_collisions), + &(stats->tx_carrier_loss), + &(stats->tx_compressed_packets) ); + } + } + + fclose( fp ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Process Status +// ==================================== +SmErrorT sm_node_stats_get_process_status( int pid, + SmNodeProcessStatusT* status ) +{ + unsigned long long ms; + unsigned long long ns; + char filename[80]; + char line[512]; + FILE* fp; + + memset( status, 0, sizeof(SmNodeProcessStatusT) ); + + // Process Stat Information + snprintf( filename, sizeof(filename), "/proc/%i/stat", pid ); + + fp = fopen( filename, "r" ); + if( NULL == fp ) + { + // Could be a short lived process. + DPRINTFD( "Failed to get process (%i) status.", pid ); + return( SM_NOT_FOUND ); + } + + while( NULL != fgets( line, sizeof(line), fp ) ) + { + sscanf( line, "%d %s %c %d %d", + &(status->pid), status->name, &(status->state), + &(status->ppid), &(status->pgrp) ); + } + + fclose( fp ); + + // Process Scheduler Information + snprintf( filename, sizeof(filename), "/proc/%i/sched", pid ); + + fp = fopen( filename, "r" ); + if( NULL == fp ) + { + // Could be a short lived process. + DPRINTFD( "Failed to get process (%i) status.", pid ); + return( SM_NOT_FOUND ); + } + + while( NULL != fgets( line, sizeof(line), fp ) ) + { + if( 0 == strncmp( "se.statistics.block_start", line, 25 ) ) + { + sscanf( line, "se.statistics.block_start : %llu.%llu", + &ms, &ns ); + status->block_start_ns = (ms * 1000000) + ns; + continue; + } + + if( 0 == strncmp( "nr_switches", line, 11 ) ) + { + sscanf( line, "nr_switches : %llu", &(status->nr_switches) ); + continue; + } + + if( 0 == strncmp( "nr_voluntary_switches", line, 21 ) ) + { + sscanf( line, "nr_voluntary_switches : %llu", + &(status->nr_voluntary_switches) ); + continue; + } + + if( 0 == strncmp( "nr_involuntary_switches", line, 23 ) ) + { + sscanf( line, "nr_involuntary_switches : %llu", + &(status->nr_involuntary_switches) ); + continue; + } + } + + fclose( fp ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Initialize +// ============================ +SmErrorT sm_node_stats_initialize( void ) +{ + _user_hz = sysconf(_SC_CLK_TCK); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Finalize +// ========================== +SmErrorT sm_node_stats_finalize( void ) +{ + _user_hz = 0; + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_node_stats.h b/service-mgmt/sm-common-1.0.0/src/sm_node_stats.h new file mode 100644 index 00000000..534a0045 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_node_stats.h @@ -0,0 +1,180 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NODE_STATS_H__ +#define __SM_NODE_STATS_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_NODE_STATS_CPU_NAME_MAX_LEN 128 +#define SM_NODE_STATS_DEV_NAME_MAX_LEN 128 +#define SM_NODE_STATS_NET_DEV_NAME_MAX_LEN 128 +#define SM_NODE_STATS_PROCESS_NAME_MAX_LEN 128 +#define SM_NODE_STATS_PROCESS_STATE_MAX_LEN 32 + +typedef struct +{ + char cpu_name[SM_NODE_STATS_CPU_NAME_MAX_LEN]; + unsigned long long user_cpu_usage; + unsigned long long nice_cpu_usage; + unsigned long long system_cpu_usage; + unsigned long long idle_task_cpu_usage; + unsigned long long iowait_cpu_usage; + unsigned long long irq_cpu_usage; + unsigned long long soft_irq_cpu_usage; + unsigned long long steal_cpu_usage; + unsigned long long guest_cpu_usage; + unsigned long long guest_nice_cpu_usage; + unsigned long long total_interrupts; // across all cpus + unsigned long long total_context_switches; // across all cpus + unsigned long long total_processes; // across all cpus + unsigned long long processes_running; // across all cpus + unsigned long long processes_blocked; // across all cpus + unsigned long long boot_time_in_secs; // since unix epoch +} SmNodeCpuStatsT; + +typedef struct +{ + unsigned long total_memory_kB; + unsigned long free_memory_kB; + unsigned long buffers_kB; + unsigned long cached_kB; + unsigned long swap_cached_kB; + unsigned long swap_total_kB; + unsigned long swap_free_kB; + unsigned long active_kB; + unsigned long inactive_kB; + unsigned long dirty_kB; + unsigned long hugepages_total; + unsigned long hugepages_free; + unsigned long hugepage_size_kB; + unsigned long nfs_uncommited_kB; + unsigned long commited_memory_kB; +} SmNodeMemStatsT; + +typedef struct +{ + unsigned int major_num; + unsigned int minor_num; + char dev_name[SM_NODE_STATS_DEV_NAME_MAX_LEN]; + unsigned long reads_completed; + unsigned long reads_merged; + unsigned long sectors_read; + unsigned long ms_spent_reading; + unsigned long writes_completed; + unsigned long writes_merged; + unsigned long sectors_written; + unsigned long ms_spent_writing; + unsigned long io_inprogress; + unsigned long ms_spent_io; + unsigned long weighted_ms_spent_io; +} SmNodeDiskStatsT; + +typedef struct +{ + char dev_name[SM_NODE_STATS_NET_DEV_NAME_MAX_LEN]; + unsigned long long rx_bytes; + unsigned long long rx_packets; + unsigned long long rx_errors; + unsigned long long rx_dropped; + unsigned long long rx_fifo_errors; + unsigned long long rx_frame_errors; + unsigned long long rx_compressed_packets; + unsigned long long rx_multicast_frames; + unsigned long long tx_bytes; + unsigned long long tx_packets; + unsigned long long tx_errors; + unsigned long long tx_dropped; + unsigned long long tx_fifo_errors; + unsigned long long tx_collisions; + unsigned long long tx_carrier_loss; + unsigned long long tx_compressed_packets; +} SmNodeNetDevStatsT; + +typedef struct +{ + int pid; + char name[SM_NODE_STATS_PROCESS_NAME_MAX_LEN]; + // RSDZTW + // R is running, + // S is sleeping in an interruptible wait, + // D is waiting in uninterruptible disk sleep, + // Z is zombie, + // T is traced or stopped (on a signal), + // W is paging. + char state; // RSDZTW + int ppid; + int pgrp; + + unsigned long long block_start_ns; + unsigned long long nr_switches; + unsigned long long nr_voluntary_switches; + unsigned long long nr_involuntary_switches; +} SmNodeProcessStatusT; + +// **************************************************************************** +// Node Statistics - Get CPU +// ========================= +extern SmErrorT sm_node_stats_get_cpu( const char cpu_name[], + SmNodeCpuStatsT* stats ); +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Memory +// ============================ +extern SmErrorT sm_node_stats_get_memory( SmNodeMemStatsT* stats ); +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Disk +// ========================== +extern SmErrorT sm_node_stats_get_disk( const char dev_name[], + SmNodeDiskStatsT* stats ); +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Disk By Index +// =================================== +extern SmErrorT sm_node_stats_get_disk_by_index( unsigned int index, + SmNodeDiskStatsT* stats ); +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Network Device +// ==================================== +extern SmErrorT sm_node_stats_get_netdev( const char dev_name[], + SmNodeNetDevStatsT* stats ); +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Get Process Status +// ==================================== +extern SmErrorT sm_node_stats_get_process_status( int pid, + SmNodeProcessStatusT* status ); +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Initialize +// ============================ +extern SmErrorT sm_node_stats_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Node Statistics - Finalize +// ========================== +extern SmErrorT sm_node_stats_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NODE_STATS_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_node_utils.c b/service-mgmt/sm-common-1.0.0/src/sm_node_utils.c new file mode 100644 index 00000000..e006d5b5 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_node_utils.c @@ -0,0 +1,545 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_node_utils.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" + +#define SM_NODE_GO_ENABLE_FILE "/var/run/goenabled" +#define SM_NODE_GO_ENABLE_FILE_SIMPLEX "/var/run/.goenabled" +#define SM_NODE_UNHEALTHY_FILE "/var/run/.sm_node_unhealthy" +#define SM_NODE_CONFIG_COMPLETE_FILE "/etc/platform/.initial_config_complete" +#define SM_NODE_PLATFORM_CONFIG_FILE "/etc/platform/platform.conf" + +static bool _failover_disabled = false; + +static SmErrorT _sm_node_utils_get_system_mode_str( char system_mode[] ); +static SmErrorT _sm_node_utils_get_system_type_str( char system_type[] ); + +typedef enum +{ + IsUnknown, + IsTrue, + IsFalse +}ThreeValuedT; + +static ThreeValuedT _is_aio = IsUnknown; +static ThreeValuedT _is_aio_simplex = IsUnknown; +static ThreeValuedT _is_aio_duplex = IsUnknown; + +// **************************************************************************** +// Node Utilities - Read Platform Config +// ===================================== +static SmErrorT sm_node_utils_read_platform_config( const char key[], + char value[], int value_size ) +{ + FILE* fp; + char format[1024]; + char line[1024]; + char val[1024]; + + value[0] = '\0'; + + fp = fopen( SM_NODE_PLATFORM_CONFIG_FILE, "r" ); + if( NULL == fp ) + { + DPRINTFE( "Failed to open file (%s).", SM_NODE_PLATFORM_CONFIG_FILE ); + return( SM_FAILED ); + } + + snprintf( format, sizeof(format), "%s=%%%ds", (char*) key, + (int) sizeof(val)-1 ); + + while( NULL != fgets( line, sizeof(line), fp ) ) + { + if( 1 == sscanf( line, format, val ) ) + { + val[sizeof(val)-1] = '\0'; + snprintf( value, value_size, "%s", val ); + break; + } + } + + fclose( fp ); + + if( '\0' == value[0] ) + { + return( SM_NOT_FOUND ); + } + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Node Type +// ============================== +static SmErrorT sm_node_utils_get_node_type( char node_type[] ) +{ + return( sm_node_utils_read_platform_config( "nodetype", node_type, + SM_NODE_TYPE_MAX_CHAR ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Sub-Functions +// ================================== +static SmErrorT sm_node_utils_get_sub_functions( char sub_functions[] ) +{ + return( sm_node_utils_read_platform_config( "subfunction", sub_functions, + SM_NODE_SUB_FUNCTIONS_MAX_CHAR ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Node Type Is Controller +// ======================================== +SmErrorT sm_node_utils_node_type_is_controller( bool* is_controller ) +{ + char node_type[SM_NODE_TYPE_MAX_CHAR+1] = ""; + SmErrorT error; + + *is_controller = false; + + error = sm_node_utils_get_node_type( node_type ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get node type, error=%s.", + sm_error_str(error) ); + return( error ); + } + + if( 0 == strcmp( "controller", node_type ) ) + { + *is_controller = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - system Is AIO +// ======================================== +SmErrorT sm_node_utils_is_aio( bool* is_aio ) +{ + if( IsUnknown == _is_aio ) + { + char system_type[SM_SYSTEM_TYPE_MAX_CHAR]; + SmErrorT error; + error = _sm_node_utils_get_system_type_str(system_type); + if( SM_OKAY != error) + { + return error; + } + if( strcmp("All-in-one", system_type) == 0 ) + { + _is_aio = IsTrue; + }else + { + _is_aio = IsFalse; + } + *is_aio = ( IsTrue == _is_aio ); + } + else + { + *is_aio = ( IsTrue == _is_aio ); + } + + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Sub-Functions Has Compute +// ========================================== +SmErrorT sm_node_utils_sub_function_has_compute( bool* has_compute ) +{ + char sub_functions[SM_NODE_SUB_FUNCTIONS_MAX_CHAR+1] = ""; + SmErrorT error; + + *has_compute = false; + + error = sm_node_utils_get_sub_functions( sub_functions ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to get sub-functions, error=%s.", + sm_error_str(error) ); + return( error ); + } + + if( NULL != strstr( sub_functions, "compute" ) ) + { + *has_compute = true; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Management Interface +// ========================================= +SmErrorT sm_node_utils_get_mgmt_interface( char interface_name[] ) +{ + return( sm_node_utils_read_platform_config( "management_interface", + interface_name, + SM_INTERFACE_NAME_MAX_CHAR ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get OAM Interface +// ================================== +SmErrorT sm_node_utils_get_oam_interface( char interface_name[] ) +{ + return( sm_node_utils_read_platform_config( "oam_interface", + interface_name, + SM_INTERFACE_NAME_MAX_CHAR ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Infrastructure Interface +// ============================================= +SmErrorT sm_node_utils_get_infra_interface( char interface_name[] ) +{ + return( sm_node_utils_read_platform_config( "infrastructure_interface", + interface_name, + SM_INTERFACE_NAME_MAX_CHAR ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get system mode string +// ============================================= +static SmErrorT _sm_node_utils_get_system_mode_str( char system_mode[] ) +{ + SmErrorT error = sm_node_utils_read_platform_config( "system_mode", + system_mode, + SM_SYSTEM_MODE_MAX_CHAR); + + if( SM_NOT_FOUND == error ) + { + system_mode[0] = '\0'; + error = SM_OKAY; + } + return error; +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get system type string +// ============================================= +static SmErrorT _sm_node_utils_get_system_type_str( char system_type[] ) +{ + SmErrorT error = sm_node_utils_read_platform_config( "system_type", + system_type, + SM_SYSTEM_TYPE_MAX_CHAR); + + if( SM_NOT_FOUND == error ) + { + system_type[0] = '\0'; + error = SM_OKAY; + } + return error; + +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get system mode string +// ============================================= +SmSystemModeT sm_node_utils_get_system_mode() +{ + char system_mode[SM_SYSTEM_MODE_MAX_CHAR]; + char system_type[SM_SYSTEM_TYPE_MAX_CHAR]; + + if ( SM_OKAY == _sm_node_utils_get_system_type_str(system_type) && + SM_OKAY == _sm_node_utils_get_system_mode_str(system_mode) ) + { + if ( 0 == strcmp("All-in-one", system_type) ) + { + if ( 0 == strcmp(SM_CPE_MODE_SIMPLEX, system_mode) ) + { + return SM_SYSTEM_MODE_CPE_SIMPLEX; + } + else if ( 0 == strcmp(SM_CPE_MODE_DUPLEX, system_mode) ) + { + return SM_SYSTEM_MODE_CPE_DUPLEX; + } + else if ( 0 == strcmp(SM_CPE_MODE_DUPLEX_DIRECT, system_mode) ) + { + return SM_SYSTEM_MODE_CPE_DUPLEX_DC; + } + } else if ( 0 == strcmp("Standard", system_type) ) { + return SM_SYSTEM_MODE_STANDARD; + } + } + return SM_SYSTEM_MODE_UNKNOWN; +} + +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Uptime +// =========================== +SmErrorT sm_node_utils_get_uptime( long* uptime ) +{ + struct sysinfo info; + int result; + + result = sysinfo( &info ); + if( 0 > result ) + { + DPRINTFE( "Failed to get system uptime, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + *uptime = info.uptime; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Host Name +// ============================== +SmErrorT sm_node_utils_get_hostname( char node_name[] ) +{ + char hostname[SM_NODE_NAME_MAX_CHAR]; + + if( 0 > gethostname( hostname, sizeof(hostname) ) ) + { + DPRINTFE( "Failed to get node name, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + snprintf( node_name, SM_NODE_NAME_MAX_CHAR, "%s", hostname ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Configuration Complete +// ======================================= +SmErrorT sm_node_utils_config_complete( bool* complete ) +{ + *complete = false; + + if( 0 > access( SM_NODE_CONFIG_COMPLETE_FILE, F_OK ) ) + { + if( ENOENT == errno ) + { + DPRINTFD( "Config-Complete file (%s) not available, error=%s.", + SM_NODE_CONFIG_COMPLETE_FILE, strerror( errno ) ); + return( SM_OKAY ); + + } else { + DPRINTFE( "Config-Complete file (%s) access failed, error=%s.", + SM_NODE_CONFIG_COMPLETE_FILE, strerror( errno ) ); + return( SM_FAILED ); + } + } + + *complete = true; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Enabled +// ======================== +SmErrorT sm_node_utils_enabled( bool* enabled, char reason_text[] ) +{ + *enabled = false; + reason_text[0] = '\0'; + + bool is_aio_simplex = false; + SmErrorT error = sm_node_utils_is_aio_simplex(&is_aio_simplex); + if(SM_OKAY != error) + { + DPRINTFE("Failed to get system mode, error %s", + sm_error_str(error)); + return error; + } + + if( (!is_aio_simplex && (0 > access( SM_NODE_GO_ENABLE_FILE, F_OK ))) || + (is_aio_simplex && (0 > access( SM_NODE_GO_ENABLE_FILE_SIMPLEX, F_OK ))) ) + { + if( ENOENT == errno ) + { + DPRINTFD( "Go-Enable file (%s) not available, error=%s.", + SM_NODE_GO_ENABLE_FILE, strerror( errno ) ); + + snprintf( reason_text, SM_LOG_REASON_TEXT_MAX_CHAR, + "node not ready, go-enable not set" ); + + return( SM_OKAY ); + + } else { + DPRINTFE( "Go-Enable file (%s) access failed, error=%s.", + SM_NODE_GO_ENABLE_FILE, strerror( errno ) ); + return( SM_FAILED ); + } + } + + if( 0 > access( SM_NODE_CONFIG_COMPLETE_FILE, F_OK ) ) + { + if( ENOENT == errno ) + { + DPRINTFD( "Config-Complete file (%s) not available, error=%s.", + SM_NODE_CONFIG_COMPLETE_FILE, strerror( errno ) ); + + snprintf( reason_text, SM_LOG_REASON_TEXT_MAX_CHAR, + "node not ready, config-complete not set" ); + + return( SM_OKAY ); + + } else { + DPRINTFE( "Config-Complete file (%s) access failed, error=%s.", + SM_NODE_CONFIG_COMPLETE_FILE, strerror( errno ) ); + return( SM_FAILED ); + } + } + + if( 0 == access( SM_NODE_UNHEALTHY_FILE, F_OK ) ) + { + DPRINTFI( "Node unhealthy file (%s) set.", SM_NODE_UNHEALTHY_FILE ); + + snprintf( reason_text, SM_LOG_REASON_TEXT_MAX_CHAR, + "node not ready, node unhealthy set" ); + + return( SM_OKAY ); + + } else { + if( ENOENT != errno ) + { + DPRINTFE( "Node unhealthy file (%s) access failed, error=%s.", + SM_NODE_UNHEALTHY_FILE, strerror( errno ) ); + return( SM_FAILED ); + } + } + + if(_failover_disabled) + { + DPRINTFI( "Failover disabled" ); + snprintf( reason_text, SM_LOG_REASON_TEXT_MAX_CHAR, + "Failover action to disable node" ); + return( SM_OKAY ); + } + + *enabled = true; + snprintf( reason_text, SM_LOG_REASON_TEXT_MAX_CHAR, "node ready" ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Set Failover +// ============================== +bool sm_node_utils_set_failover( bool to_disable ) +{ + bool old_value = _failover_disabled; + if(to_disable) + { + DPRINTFI("disable system for failover"); + } + _failover_disabled = to_disable; + return old_value; +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Set Unhealthy +// ============================== +SmErrorT sm_node_utils_set_unhealthy( void ) +{ + int fd = open( SM_NODE_UNHEALTHY_FILE, + O_RDWR | O_CREAT, S_IRUSR | S_IRGRP | S_IROTH); + if( 0 > fd ) + { + DPRINTFE( "Failed to create file (%s), error=%s.", + SM_NODE_UNHEALTHY_FILE, strerror(errno) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - System Is AIO Simplex +// ====================================== +SmErrorT sm_node_utils_is_aio_simplex( bool* is_aio_simplex ) +{ + if( IsUnknown == _is_aio_simplex ) + { + SmSystemModeT system_mode = sm_node_utils_get_system_mode(); + if( SM_SYSTEM_MODE_CPE_SIMPLEX == system_mode ) + { + _is_aio_simplex = IsTrue; + }else + { + _is_aio_simplex = IsFalse; + } + } + + *is_aio_simplex = ( IsTrue == _is_aio_simplex ); + return SM_OKAY; +} +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - System is AIO Duplex +// ===================================== +SmErrorT sm_node_utils_is_aio_duplex( bool* is_aio_duplex ) +{ + if( IsUnknown == _is_aio_duplex ) + { + SmErrorT error; + bool is_aio = false; + error = sm_node_utils_is_aio( &is_aio ); + if( SM_OKAY != error) + { + return error; + } + + if ( !is_aio ) + { + *is_aio_duplex = false; + return SM_OKAY; + }else + { + SmSystemModeT system_mode = sm_node_utils_get_system_mode(); + if(( SM_SYSTEM_MODE_CPE_DUPLEX == system_mode ) || + ( SM_SYSTEM_MODE_CPE_DUPLEX_DC == system_mode )) + { + _is_aio_duplex = IsTrue; + }else + { + _is_aio_duplex = IsFalse; + } + } + } + + *is_aio_duplex = ( IsTrue == _is_aio_duplex ); + return SM_OKAY; +} + diff --git a/service-mgmt/sm-common-1.0.0/src/sm_node_utils.h b/service-mgmt/sm-common-1.0.0/src/sm_node_utils.h new file mode 100644 index 00000000..16fb34f8 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_node_utils.h @@ -0,0 +1,111 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_NODE_UTILS_H__ +#define __SM_NODE_UTILS_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Node Utilities - Node Type Is Controller +// ======================================== +extern SmErrorT sm_node_utils_node_type_is_controller( bool* is_controller ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - System Is AIO +// ======================================== +extern SmErrorT sm_node_utils_is_aio( bool* is_aio ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Sub-Functions Has Compute +// ========================================== +extern SmErrorT sm_node_utils_sub_function_has_compute( bool* has_compute ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Management Interface +// ========================================= +extern SmErrorT sm_node_utils_get_mgmt_interface( char interface_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get OAM Interface +// ================================== +extern SmErrorT sm_node_utils_get_oam_interface( char interface_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Infrastructure Interface +// ============================================= +extern SmErrorT sm_node_utils_get_infra_interface( char interface_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get system mode +// ============================================= +SmSystemModeT sm_node_utils_get_system_mode(); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Uptime +// =========================== +extern SmErrorT sm_node_utils_get_uptime( long* uptime ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Get Host Name +// ============================== +extern SmErrorT sm_node_utils_get_hostname( char node_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Configuration Complete +// ======================================= +extern SmErrorT sm_node_utils_config_complete( bool* complete ); +// **************************************************************************** +// +// **************************************************************************** +// Node Utilities - Enabled +// ======================== +extern SmErrorT sm_node_utils_enabled( bool* enabled, char reason_text[] ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Set Unhealthy +// ============================== +extern SmErrorT sm_node_utils_set_unhealthy( void ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - System Is AIO Simplex +// ======================================= +extern SmErrorT sm_node_utils_is_aio_simplex( bool* is_aio_simplex ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - System is AIO Duplex +// ===================================== +extern SmErrorT sm_node_utils_is_aio_duplex( bool* is_aio_duplex ); +// **************************************************************************** + +// **************************************************************************** +// Node Utilities - Set Failover +// ============================== +extern bool sm_node_utils_set_failover( bool to_disable ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_NODE_UTILS_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_selobj.c b/service-mgmt/sm-common-1.0.0/src/sm_selobj.c new file mode 100644 index 00000000..1ae10e27 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_selobj.c @@ -0,0 +1,325 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_selobj.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_list.h" + +#define SM_SEL_OBJ_ENTRY_VALID 0xFDFDFDFD + +typedef struct +{ + uint32_t valid; + int selobj; + SmSelObjCallbackT callback; + int64_t user_data; +} SmSelObjSelectEntryT; + +typedef struct +{ + bool inuse; + pthread_t thread_id; + int last_selobj; + fd_set selobjs_set; + SmSelObjSelectEntryT selobjs[SM_THREAD_SELECT_OBJS_MAX]; +} SmSelObjThreadInfoT; + +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static SmSelObjThreadInfoT _threads[SM_THREADS_MAX]; + +// **************************************************************************** +// Selection Object - Find Thread Info +// =================================== +static SmSelObjThreadInfoT* sm_selobj_find_thread_info( void ) +{ + pthread_t thread_id = pthread_self(); + + unsigned int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + if( !(_threads[thread_i].inuse) ) + continue; + + if( thread_id == _threads[thread_i].thread_id ) + return( &(_threads[thread_i]) ); + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Find Selection Object +// ======================================== +static SmSelObjSelectEntryT* sm_selobj_find( SmSelObjThreadInfoT* thread_info, + int selobj ) +{ + SmSelObjSelectEntryT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_THREAD_SELECT_OBJS_MAX > entry_i; ++entry_i ) + { + entry = (SmSelObjSelectEntryT*) &(thread_info->selobjs[entry_i]); + + if( SM_SEL_OBJ_ENTRY_VALID == entry->valid ) + { + if( selobj == entry->selobj ) + { + return( entry ); + } + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Register +// =========================== +SmErrorT sm_selobj_register( int selobj, SmSelObjCallbackT callback, + int64_t user_data ) +{ + SmSelObjThreadInfoT* thread_info; + SmSelObjSelectEntryT* entry; + + thread_info = sm_selobj_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + entry = sm_selobj_find( thread_info, selobj ); + if( NULL == entry ) + { + unsigned int entry_i; + for( entry_i=0; SM_THREAD_SELECT_OBJS_MAX > entry_i; ++entry_i ) + { + entry = (SmSelObjSelectEntryT*) &(thread_info->selobjs[entry_i]); + if( SM_SEL_OBJ_ENTRY_VALID != entry->valid ) + { + entry->valid = SM_SEL_OBJ_ENTRY_VALID; + entry->selobj = selobj; + entry->callback = callback; + entry->user_data = user_data; + FD_SET( selobj, &(thread_info->selobjs_set) ); + if( selobj > thread_info->last_selobj ) + { + thread_info->last_selobj = selobj; + } + break; + } + } + } else { + entry->callback = callback; + entry->user_data = user_data; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Deregister +// ============================= +SmErrorT sm_selobj_deregister( int selobj ) +{ + SmSelObjThreadInfoT* thread_info; + SmSelObjSelectEntryT* entry; + + thread_info = sm_selobj_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + entry = sm_selobj_find( thread_info, selobj ); + if( NULL != entry ) + { + memset( entry, 0, sizeof(SmSelObjSelectEntryT) ); + FD_CLR( selobj, &(thread_info->selobjs_set) ); + thread_info->last_selobj = 0; + + unsigned int entry_i; + for( entry_i=0; SM_THREAD_SELECT_OBJS_MAX > entry_i; ++entry_i ) + { + entry = (SmSelObjSelectEntryT*) &(thread_info->selobjs[entry_i]); + + if( SM_SEL_OBJ_ENTRY_VALID == entry->valid ) + { + if( entry->selobj > thread_info->last_selobj ) + { + thread_info->last_selobj = entry->selobj; + } + } + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Dispatch +// =========================== +SmErrorT sm_selobj_dispatch( unsigned int timeout_in_ms ) +{ + SmSelObjThreadInfoT* thread_info; + SmSelObjSelectEntryT* entry; + int num_fds; + fd_set fds; + struct timeval tv; + int result; + + thread_info = sm_selobj_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + num_fds = thread_info->last_selobj; + fds = thread_info->selobjs_set; + + tv.tv_sec = timeout_in_ms / 1000; + tv.tv_usec = (timeout_in_ms % 1000) * 1000; + + result = select( num_fds+1, &fds, NULL, NULL, &tv ); + if( 0 > result ) + { + if( errno == EINTR ) + { + DPRINTFD( "Interrupted by a signal." ); + return( SM_OKAY ); + } else { + DPRINTFE( "Select failed, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + } else if( 0 == result ) { + DPRINTFD( "Nothing selected." ); + return( SM_OKAY ); + } + + unsigned int entry_i; + for( entry_i=0; SM_THREAD_SELECT_OBJS_MAX > entry_i; ++entry_i ) + { + entry = (SmSelObjSelectEntryT*) &(thread_info->selobjs[entry_i]); + + if( SM_SEL_OBJ_ENTRY_VALID != entry->valid ) + continue; + + if( FD_ISSET( entry->selobj, &fds ) ) + { + if( NULL != entry->callback ) + { + entry->callback( entry->selobj, entry->user_data ); + } + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Initialize +// ============================= +SmErrorT sm_selobj_initialize( void ) +{ + SmSelObjThreadInfoT* thread_info = NULL; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + unsigned int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + if( !(_threads[thread_i].inuse) ) + { + thread_info = &(_threads[thread_i]); + break; + } + } + + if( NULL == thread_info ) + { + DPRINTFE( "Failed to allocate thread information." ); + goto ERROR; + } + + memset( thread_info, 0, sizeof(SmSelObjThreadInfoT) ); + + thread_info->inuse = true; + thread_info->thread_id = pthread_self(); + FD_ZERO( &(thread_info->selobjs_set) ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( SM_OKAY ); + +ERROR: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Finalize +// =========================== +SmErrorT sm_selobj_finalize( void ) +{ + SmSelObjThreadInfoT* thread_info; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + thread_info = sm_selobj_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_OKAY ); + } + + memset( thread_info, 0, sizeof(SmSelObjThreadInfoT) ); + FD_ZERO( &(thread_info->selobjs_set) ); + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_selobj.h b/service-mgmt/sm-common-1.0.0/src/sm_selobj.h new file mode 100644 index 00000000..b4b81d85 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_selobj.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// The following module is thread safe. +// +#ifndef __SM_SELOBJ_H__ +#define __SM_SELOBJ_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*SmSelObjCallbackT) (int selobj, int64_t user_data); + +// **************************************************************************** +// Selection Object - Register +// =========================== +extern SmErrorT sm_selobj_register( int selobj, SmSelObjCallbackT callback, + int64_t user_data ); +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Deregister +// ============================= +extern SmErrorT sm_selobj_deregister( int selobj ); +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Dispatch +// =========================== +extern SmErrorT sm_selobj_dispatch( unsigned int timeout_in_ms ); +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Initialize +// ============================= +extern SmErrorT sm_selobj_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Selection Object - Finalize +// =========================== +extern SmErrorT sm_selobj_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SELOBJ_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_sha512.c b/service-mgmt/sm-common-1.0.0/src/sm_sha512.c new file mode 100644 index 00000000..80e71dbf --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_sha512.c @@ -0,0 +1,289 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_sha512.h" + +#include +#include +#include +#include + +#define ROR64(value, bits) (((value) >> (bits)) | ((value) << (64 - (bits)))) + +#define MIN(x, y) (((x)<(y))?(x):(y)) + +#define LOAD64H(x, y) \ + { x = (((uint64_t)((y)[0] & 255))<<56)|(((uint64_t)((y)[1] & 255))<<48) | \ + (((uint64_t)((y)[2] & 255))<<40)|(((uint64_t)((y)[3] & 255))<<32) | \ + (((uint64_t)((y)[4] & 255))<<24)|(((uint64_t)((y)[5] & 255))<<16) | \ + (((uint64_t)((y)[6] & 255))<<8)|(((uint64_t)((y)[7] & 255))); } + +#define STORE64H(x, y) \ + { (y)[0] = (uint8_t)(((x)>>56)&255); (y)[1] = (uint8_t)(((x)>>48)&255); \ + (y)[2] = (uint8_t)(((x)>>40)&255); (y)[3] = (uint8_t)(((x)>>32)&255); \ + (y)[4] = (uint8_t)(((x)>>24)&255); (y)[5] = (uint8_t)(((x)>>16)&255); \ + (y)[6] = (uint8_t)(((x)>>8)&255); (y)[7] = (uint8_t)((x)&255); } + +// Various logical functions +#define CH( x, y, z ) (z ^ (x & (y ^ z))) +#define MAJ(x, y, z ) (((x | y) & z) | (x & y)) +#define S( x, n ) ROR64( x, n ) +#define R( x, n ) (((x)&0xFFFFFFFFFFFFFFFFULL)>>((uint64_t)n)) +#define SIGMA0( x ) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) +#define SIGMA1( x ) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) +#define GAMMA0( x ) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) +#define GAMMA1( x ) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) + +#define SHA512_ROUND( a, b, c, d, e, f, g, h, i ) \ + t0 = h + SIGMA1(e) + CH(e, f, g) + K[i] + W[i]; \ + t1 = SIGMA0(a) + MAJ(a, b, c); \ + d += t0; \ + h = t0 + t1; + +#define BLOCK_SIZE 128 + +// The K array +static const uint64_t K[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +// **************************************************************************** +// SHA512 - Transform Function +// =========================== +static void sm_sha512_transform_function( SmSha512ContextT* context, + uint8_t* buffer ) +{ + uint64_t S[8]; + uint64_t W[80]; + uint64_t t0; + uint64_t t1; + int i; + + // Copy state into S. + for( i=0; 8 > i; ++i ) + { + S[i] = context->state[i]; + } + + // Copy the state into 1024-bits into W[0..15]. + for( i=0; 16 > i; ++i ) + { + LOAD64H(W[i], buffer + (8*i)); + } + + // Fill W[16..79]. + for( i=16; 80 > i; ++i ) + { + W[i] = GAMMA1(W[i - 2]) + W[i - 7] + GAMMA0(W[i - 15]) + W[i - 16]; + } + + // Compress. + for( i=0; 80 > i; i+=8 ) + { + SHA512_ROUND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); + SHA512_ROUND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); + SHA512_ROUND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); + SHA512_ROUND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); + SHA512_ROUND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); + SHA512_ROUND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); + SHA512_ROUND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); + SHA512_ROUND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); + } + + // Feedback. + for( i=0; 8 > i; ++i ) + { + context->state[i] = context->state[i] + S[i]; + } +} +// **************************************************************************** + +// **************************************************************************** +// SHA512 - Initialize +// =================== +void sm_sha512_initialize( SmSha512ContextT* context ) +{ + context->current_length = 0; + context->length = 0; + context->state[0] = 0x6a09e667f3bcc908ULL; + context->state[1] = 0xbb67ae8584caa73bULL; + context->state[2] = 0x3c6ef372fe94f82bULL; + context->state[3] = 0xa54ff53a5f1d36f1ULL; + context->state[4] = 0x510e527fade682d1ULL; + context->state[5] = 0x9b05688c2b3e6c1fULL; + context->state[6] = 0x1f83d9abfb41bd6bULL; + context->state[7] = 0x5be0cd19137e2179ULL; +} +// **************************************************************************** + +// **************************************************************************** +// SHA512 - Update +// =============== +void sm_sha512_update( SmSha512ContextT* context, void* buffer, + uint32_t buffer_size ) +{ + uint32_t n; + + if( context->current_length > sizeof(context->buffer) ) + { + return; + } + + while( 0 < buffer_size ) + { + if(( 0 == context->current_length )&&( BLOCK_SIZE <= buffer_size )) + { + sm_sha512_transform_function( context, (uint8_t*) buffer ); + context->length += BLOCK_SIZE * 8; + buffer = (uint8_t*) buffer + BLOCK_SIZE; + buffer_size -= BLOCK_SIZE; + } else { + n = MIN( buffer_size, (BLOCK_SIZE - context->current_length) ); + memcpy( context->buffer + context->current_length, buffer, + (size_t) n ); + context->current_length += n; + buffer = (uint8_t*) buffer + n; + buffer_size -= n; + if( context->current_length == BLOCK_SIZE ) + { + sm_sha512_transform_function( context, context->buffer ); + context->length += (8 * BLOCK_SIZE); + context->current_length = 0; + } + } + } +} +// **************************************************************************** + +// **************************************************************************** +// SHA512 - Finalize +// ================= +void sm_sha512_finalize( SmSha512ContextT* context, SmSha512HashT* hash ) +{ + if( context->current_length >= sizeof(context->buffer) ) + { + return; + } + + // Increase the length of the message. + context->length += context->current_length * 8ULL; + + // Append the '1' bit. + context->buffer[(context->current_length)++] = (uint8_t) 0x80; + + // If the length is currently above 112 bytes we append zeros + // then compress. Then we can fall back to padding zeros and length + // encoding like normal. + if( 112 < context->current_length ) + { + while( 128 > context->current_length ) + { + context->buffer[(context->current_length)++] = (uint8_t) 0; + } + sm_sha512_transform_function( context, context->buffer ); + context->current_length = 0; + } + + // Pad up to 120 bytes of zeros. + // Note: that from 112 to 120 is the 64 MSB of the length. + // Assume that you won't hash > 2^64 bits of data... + while( 120 > context->current_length ) + { + context->buffer[(context->current_length)++] = (uint8_t) 0; + } + + // Store length. + STORE64H( context->length, context->buffer+120 ); + sm_sha512_transform_function( context, context->buffer ); + + // Copy output. + int i; + for( i=0; 8 > i; ++i ) + { + STORE64H( context->state[i], hash->bytes+(8*i) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// SHA512 - Hash String +// ==================== +void sm_sha512_hash_str( char hash_str[], SmSha512HashT* hash ) +{ + int i; + for( i=0; SM_SHA512_HASH_SIZE > i; ++i ) + { + snprintf( hash_str+(i*2), SM_SHA512_HASH_STR_SIZE-(i*2), "%02x", + hash->bytes[i] ); + } +} +// **************************************************************************** + +// **************************************************************************** +// SHA512 - HMAC +// ============= +void sm_sha512_hmac( void* buffer, uint32_t buffer_size, void* key, + uint32_t key_size, SmSha512HashT* hash ) +{ + int byte_i; + SmSha512ContextT context; + uint8_t key_ipad[BLOCK_SIZE]; + uint8_t key_opad[BLOCK_SIZE]; + SmSha512HashT key_hash; + + if( BLOCK_SIZE < key_size ) + { + SmSha512ContextT key_context; + sm_sha512_initialize( &key_context ); + sm_sha512_update( &key_context, key, key_size ); + sm_sha512_finalize( &key_context, &key_hash ); + key = &(key_hash.bytes[0]); + key_size = SM_SHA512_HASH_SIZE; + } + + // First Pass (inner hash). + memset( key_ipad, 0, sizeof(key_ipad) ); + memcpy( key_ipad, key, key_size ); + + for( byte_i=0; BLOCK_SIZE > byte_i; ++byte_i ) + key_ipad[byte_i] ^= 0x36; + + sm_sha512_initialize( &context ); + sm_sha512_update( &context, key_ipad, sizeof(key_ipad) ); + sm_sha512_update( &context, buffer, buffer_size ); + sm_sha512_finalize( &context, hash ); + + // Second Pass (outer hash). + memset( key_opad, 0, sizeof(key_opad) ); + memcpy( key_opad, key, key_size ); + + for( byte_i=0; BLOCK_SIZE > byte_i; ++byte_i ) + key_opad[byte_i] ^= 0x5C; + + sm_sha512_initialize( &context ); + sm_sha512_update( &context, key_opad, sizeof(key_opad) ); + sm_sha512_update( &context, &(hash->bytes[0]), SM_SHA512_HASH_SIZE ); + sm_sha512_finalize( &context, hash ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_sha512.h b/service-mgmt/sm-common-1.0.0/src/sm_sha512.h new file mode 100644 index 00000000..da4e1841 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_sha512.h @@ -0,0 +1,67 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_SHA512_H__ +#define __SM_SHA512_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + uint64_t length; + uint64_t state[8]; + uint32_t current_length; + uint8_t buffer[128]; +} SmSha512ContextT; + +#define SM_SHA512_HASH_SIZE 64 +#define SM_SHA512_HASH_STR_SIZE ((SM_SHA512_HASH_SIZE*2)+1) + +typedef struct +{ + uint8_t bytes[SM_SHA512_HASH_SIZE]; +} SmSha512HashT; + +// **************************************************************************** +// SHA512 - Initialize +// =================== +extern void sm_sha512_initialize( SmSha512ContextT* context ); +// **************************************************************************** + +// **************************************************************************** +// SHA512 - Update +// =============== +extern void sm_sha512_update( SmSha512ContextT* context, void* buffer, + uint32_t buffer_size ); +// **************************************************************************** + +// **************************************************************************** +// SHA512 - Finalize +// ================= +extern void sm_sha512_finalize( SmSha512ContextT* context, SmSha512HashT* digest ); +// **************************************************************************** + +// **************************************************************************** +// SHA512 - Hash String +// ==================== +extern void sm_sha512_hash_str( char hash_str[], SmSha512HashT* hash ); +// **************************************************************************** + +// **************************************************************************** +// SHA512 - HMAC +// ============= +extern void sm_sha512_hmac( void* buffer, uint32_t buffer_size, + void* key, uint32_t key_size, SmSha512HashT* digest ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_SHA512_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_thread_health.c b/service-mgmt/sm-common-1.0.0/src/sm_thread_health.c new file mode 100644 index 00000000..b593b975 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_thread_health.c @@ -0,0 +1,230 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_thread_health.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_time.h" + +#define SM_THREAD_HEALTH_CHECK_INTERVAL_IN_MS 1000 + +typedef struct +{ + bool inuse; + char thread_name[SM_THREAD_NAME_MAX_CHAR]; + long warn_after_elapsed_ms; + long fail_after_elapsed_ms; + SmTimeT last_health_update; +} SmThreadHealthT; + +static SmThreadHealthT _threads[SM_THREADS_MAX]; +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; + +// **************************************************************************** +// Thread Health - Register +// ======================== +SmErrorT sm_thread_health_register( const char thread_name[], + long warn_after_elapsed_ms, long fail_after_elapsed_ms ) +{ + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + SmThreadHealthT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_THREADS_MAX > entry_i; ++entry_i ) + { + entry = &(_threads[entry_i]); + + if( !(entry->inuse) ) + { + entry->inuse = true; + snprintf( entry->thread_name, sizeof(entry->thread_name), "%s", + thread_name ); + entry->warn_after_elapsed_ms = warn_after_elapsed_ms; + entry->fail_after_elapsed_ms = fail_after_elapsed_ms; + sm_time_get( &(entry->last_health_update) ); + break; + } + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Deregister +// ========================== +SmErrorT sm_thread_health_deregister( const char thread_name[] ) +{ + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + SmThreadHealthT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_THREADS_MAX > entry_i; ++entry_i ) + { + entry = &(_threads[entry_i]); + + if( entry->inuse ) + { + if( 0 == strcmp( thread_name, entry->thread_name ) ) + { + memset( entry, 0, sizeof(SmThreadHealthT) ); + break; + } + } + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Update +// ====================== +SmErrorT sm_thread_health_update( const char thread_name[] ) +{ + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + SmThreadHealthT* entry; + + unsigned int entry_i; + for( entry_i=0; SM_THREADS_MAX > entry_i; ++entry_i ) + { + entry = &(_threads[entry_i]); + + if( entry->inuse ) + { + if( 0 == strcmp( thread_name, entry->thread_name ) ) + { + sm_time_get( &(entry->last_health_update) ); + break; + } + } + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Check +// ===================== +SmErrorT sm_thread_health_check( bool* healthy ) +{ + static SmTimeT last_check = {0}; + + long ms_elapsed; + SmThreadHealthT* entry; + + *healthy = true; + + ms_elapsed = sm_time_get_elapsed_ms( &last_check ); + + if( SM_THREAD_HEALTH_CHECK_INTERVAL_IN_MS > ms_elapsed ) + { + DPRINTFD( "Not enough time has elapsed to do thread health check." ); + return( SM_OKAY ); + } + + sm_time_get( &last_check ); + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + unsigned int entry_i; + for( entry_i=0; SM_THREADS_MAX > entry_i; ++entry_i ) + { + entry = &(_threads[entry_i]); + + if( !(entry->inuse) ) + continue; + + ms_elapsed = sm_time_get_elapsed_ms( &(entry->last_health_update) ); + if( ms_elapsed >= entry->fail_after_elapsed_ms ) + { + *healthy = false; + DPRINTFI( "FAILED: thread (%s) delayed for %li ms, maximum delay " + "%li ms.", entry->thread_name, ms_elapsed, + entry->fail_after_elapsed_ms ); + + } else if( ms_elapsed >= entry->warn_after_elapsed_ms ) { + DPRINTFI( "WARNING: thread (%s) delayed for %li", + entry->thread_name, ms_elapsed ); + } else { + DPRINTFD( "Thread (%s) healthy, ms_elapsed=%li.", + entry->thread_name, ms_elapsed ); + } + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Initialize +// ========================== +SmErrorT sm_thread_health_initialize( void ) +{ + memset( _threads, 0, sizeof(_threads) ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Finalize +// ======================== +SmErrorT sm_thread_health_finalize( void ) +{ + memset( _threads, 0, sizeof(_threads) ); + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_thread_health.h b/service-mgmt/sm-common-1.0.0/src/sm_thread_health.h new file mode 100644 index 00000000..a380c813 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_thread_health.h @@ -0,0 +1,58 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_THREAD_HEALTH_H__ +#define __SM_THREAD_HEALTH_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Thread Health - Register +// ======================== +extern SmErrorT sm_thread_health_register( const char thread_name[], + long warn_after_elapsed_ms, long fail_after_elapsed_ms ); +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Deregister +// ========================== +extern SmErrorT sm_thread_health_deregister( const char thread_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Update +// ====================== +extern SmErrorT sm_thread_health_update( const char thread_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Check +// ===================== +extern SmErrorT sm_thread_health_check( bool* healthy ); +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Initialize +// ========================== +extern SmErrorT sm_thread_health_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Thread Health - Finalize +// ======================== +extern SmErrorT sm_thread_health_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_THREAD_HEALTH_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_time.c b/service-mgmt/sm-common-1.0.0/src/sm_time.c new file mode 100644 index 00000000..d9600f05 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_time.c @@ -0,0 +1,110 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_time.h" +#include + +#include "sm_debug.h" + +#define MS_TO_NSEC 1000000 +#define SEC_TO_NSEC 1000000000 +static SmTimeT _monotonic_time_offset = {0}; + +// **************************************************************************** +// Time - Get +// ========== +void sm_time_get( SmTimeT* time ) +{ + clock_gettime( CLOCK_MONOTONIC_RAW, time ); +} +// **************************************************************************** + +// **************************************************************************** +// Time - Get Elapsed Milliseconds +// =============================== +long sm_time_get_elapsed_ms( SmTimeT* time ) +{ + SmTimeT now; + + clock_gettime( CLOCK_MONOTONIC_RAW, &now ); + + if( NULL == time ) + { + return( (now.tv_sec*1000) + (now.tv_nsec/MS_TO_NSEC) ); + + } else { + return( sm_time_delta_in_ms( &now, time ) ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Time - Delta in Milliseconds +// ============================ +long sm_time_delta_in_ms( SmTimeT* end, SmTimeT* start ) +{ + long start_in_ms = (start->tv_sec*1000) + (start->tv_nsec/MS_TO_NSEC); + long end_in_ms = (end->tv_sec*1000) + (end->tv_nsec/MS_TO_NSEC); + + return( end_in_ms - start_in_ms ); +} +// **************************************************************************** + +// **************************************************************************** +// Time - Convert Milliseconds +// =========================== +void sm_time_convert_ms( long ms, SmTimeT* time ) +{ + time->tv_sec = ms / 1000; + time->tv_nsec = (ms % 1000) * MS_TO_NSEC; +} +// **************************************************************************** + + +// **************************************************************************** +// Time - format realtime +// =========================== +char* sm_time_format_realtime( SmTimeT *time, char *buffer, int buffer_len ) +{ + struct tm t; + localtime_r(&time->tv_sec, &t); + char temp[20]; + strftime(temp, sizeof(temp), "%FT%X", &t); + + snprintf (buffer, buffer_len, "%s.%03d\n", temp, (int)(time->tv_nsec/MS_TO_NSEC)); + return buffer; +} +// **************************************************************************** + +// **************************************************************************** +// Time - format monotonic time +// =========================== +char* sm_time_format_monotonic_time( SmTimeT *time, char *buffer, int buffer_len ) +{ + if( 0 == _monotonic_time_offset.tv_sec && 0 == _monotonic_time_offset.tv_nsec) + { + SmTimeT monotonic_time; + clock_gettime( CLOCK_MONOTONIC_RAW, &monotonic_time ); + clock_gettime( CLOCK_REALTIME, &_monotonic_time_offset); + _monotonic_time_offset.tv_sec -= monotonic_time.tv_sec; + _monotonic_time_offset.tv_nsec -= monotonic_time.tv_nsec; + if(_monotonic_time_offset.tv_nsec < 0 ) + { + _monotonic_time_offset.tv_sec --; + _monotonic_time_offset.tv_nsec += SEC_TO_NSEC; + } + } + + SmTimeT realtime = _monotonic_time_offset; + realtime.tv_sec += time->tv_sec; + realtime.tv_nsec += time->tv_nsec; + if(realtime.tv_nsec > SEC_TO_NSEC) + { + realtime.tv_nsec -= SEC_TO_NSEC; + realtime.tv_sec ++; + } + return sm_time_format_realtime( &realtime, buffer, buffer_len ); +} +// **************************************************************************** \ No newline at end of file diff --git a/service-mgmt/sm-common-1.0.0/src/sm_time.h b/service-mgmt/sm-common-1.0.0/src/sm_time.h new file mode 100644 index 00000000..2b2d50ff --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_time.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// The following module is thread safe. +// +#ifndef __SM_TIME_H__ +#define __SM_TIME_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct timespec SmTimeT; +typedef char SmRealTimeStrT[24]; + +// **************************************************************************** +// Time - Get +// ========== +extern void sm_time_get( SmTimeT* time ); +// **************************************************************************** + +// **************************************************************************** +// Time - Get Elapsed Milliseconds +// =============================== +extern long sm_time_get_elapsed_ms( SmTimeT* time ); +// **************************************************************************** + +// **************************************************************************** +// Time - Delta in Milliseconds +// ============================ +extern long sm_time_delta_in_ms( SmTimeT* end, SmTimeT* start ); +// **************************************************************************** + +// **************************************************************************** +// Time - Convert Milliseconds +// =========================== +extern void sm_time_convert_ms( long ms, SmTimeT* time ); +// **************************************************************************** + +// **************************************************************************** +// Time - format realtime +// =========================== +char* sm_time_format_realtime( SmTimeT *time, char *buffer, int buffer_len ); +// **************************************************************************** + +// **************************************************************************** +// Time - format monotonic time +// =========================== +char* sm_time_format_monotonic_time( SmTimeT *time, char *buffer, int buffer_len ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_TIMER_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_timer.c b/service-mgmt/sm-common-1.0.0/src/sm_timer.c new file mode 100644 index 00000000..7c84e005 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_timer.c @@ -0,0 +1,646 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_timer.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_time.h" +#include "sm_debug.h" +#include "sm_selobj.h" + +#define SM_TIMER_ENTRY_INUSE 0xFDFDFDFD +#define SM_MAX_TIMERS 512 +#define SM_MAX_TIMERS_PER_TICK 8 +#define SM_MIN_TICK_IN_MS 25 +#define SM_MAX_TICK_INTERVALS 2 +#define SM_SCHEDULING_ON_TIME_DEBOUNCE_IN_MS 1000 + +typedef struct +{ + uint32_t inuse; + char timer_name[40]; + long timer_run_time_in_ms; +} SmTimerHistoryEntryT; + +typedef struct +{ + uint32_t inuse; + uint64_t timer_instance; + char timer_name[40]; + SmTimerIdT timer_id; + unsigned int ms_interval; + SmTimeT arm_timestamp; + SmTimerCallbackT callback; + int64_t user_data; + SmTimeT last_fired; + uint32_t total_fired; +} SmTimerEntryT; + +typedef struct +{ + bool inuse; + pthread_t thread_id; + char thread_name[SM_THREAD_NAME_MAX_CHAR]; + int tick_timer_fd; + bool scheduling_on_time; + SmTimeT sched_timestamp; + SmTimeT delay_timestamp; + uint64_t timer_instance; + unsigned int tick_interval_in_ms; + unsigned int last_timer_dispatched; + SmTimerEntryT timers[SM_MAX_TIMERS]; +} SmTimerThreadInfoT; + +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static SmTimerThreadInfoT _threads[SM_THREADS_MAX]; + +// **************************************************************************** +// Timer - Find Thread Info +// ======================== +static SmTimerThreadInfoT* sm_timer_find_thread_info( void ) +{ + pthread_t thread_id = pthread_self(); + + unsigned int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + if( !(_threads[thread_i].inuse) ) + continue; + + if( thread_id == _threads[thread_i].thread_id ) + return( &(_threads[thread_i]) ); + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Register +// ================ +SmErrorT sm_timer_register( const char name[], unsigned int ms, + SmTimerCallbackT callback, int64_t user_data, SmTimerIdT* timer_id ) +{ + SmTimerEntryT* timer_entry; + SmTimerThreadInfoT* thread_info; + + *timer_id = SM_TIMER_ID_INVALID; + + thread_info = sm_timer_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + unsigned int timer_i; + for( timer_i=0; SM_MAX_TIMERS > timer_i; ++timer_i ) + { + timer_entry = &(thread_info->timers[timer_i]); + + if( SM_TIMER_ENTRY_INUSE == timer_entry->inuse ) + continue; + + memset( timer_entry, 0, sizeof(SmTimerEntryT) ); + + timer_entry->inuse = SM_TIMER_ENTRY_INUSE; + timer_entry->timer_instance = ++thread_info->timer_instance; + snprintf( timer_entry->timer_name, sizeof(timer_entry->timer_name), + "%s", name ); + timer_entry->timer_id = timer_i; + timer_entry->ms_interval = ms; + sm_time_get( &timer_entry->arm_timestamp ); + timer_entry->callback = callback; + timer_entry->user_data = user_data; + timer_entry->last_fired.tv_sec = timer_entry->last_fired.tv_nsec = 0; + timer_entry->total_fired = 0; + break; + } + + if( SM_MAX_TIMERS <= timer_i ) + { + DPRINTFE( "No space available to create timer (%s), exiting...", + name ); + abort(); + } + + *timer_id = timer_i; + + DPRINTFD( "Created timer (name=%s, id=%i).", timer_entry->timer_name, + timer_entry->timer_id ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Deregister +// ================== +SmErrorT sm_timer_deregister( SmTimerIdT timer_id ) +{ + SmTimerEntryT* timer_entry = NULL; + SmTimerThreadInfoT* thread_info; + + if(( SM_TIMER_ID_INVALID == timer_id )|| + ( SM_MAX_TIMERS <= timer_id )) + { + return( SM_OKAY ); + } + + thread_info = sm_timer_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( SM_FAILED ); + } + + timer_entry = &(thread_info->timers[timer_id]); + timer_entry->inuse = 0; + timer_entry->timer_instance = 0; + timer_entry->user_data = 0; + + DPRINTFD( "Cancelled timer (name=%s, id=%i).", timer_entry->timer_name, + timer_entry->timer_id ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Schedule +// ================ +static SmErrorT sm_timer_schedule( SmTimerThreadInfoT* thread_info ) +{ + SmTimerEntryT* timer_entry; + struct itimerspec tick_time; + unsigned int interval_in_ms = thread_info->tick_interval_in_ms; + long ms_expired, ms_remaining; + int timerfd_rc; + + unsigned int timer_i; + for( timer_i=0; SM_MAX_TIMERS > timer_i; ++timer_i ) + { + timer_entry = &(thread_info->timers[timer_i]); + + if( SM_TIMER_ENTRY_INUSE == timer_entry->inuse ) + { + ms_expired = sm_time_get_elapsed_ms( &timer_entry->arm_timestamp ); + + if( ms_expired < timer_entry->ms_interval ) + { + ms_remaining = timer_entry->ms_interval - ms_expired; + if( ms_remaining < interval_in_ms ) + { + interval_in_ms = ms_remaining; + } + } else { + interval_in_ms = SM_MIN_TICK_IN_MS; + break; + } + } + } + + if( SM_MIN_TICK_IN_MS > interval_in_ms ) + { + interval_in_ms = SM_MIN_TICK_IN_MS; + } + + DPRINTFD( "Scheduling tick timer in %d ms.", interval_in_ms ); + + tick_time.it_value.tv_sec = interval_in_ms / 1000;; + tick_time.it_value.tv_nsec = (interval_in_ms % 1000) * 1000000; + tick_time.it_interval.tv_sec = tick_time.it_value.tv_sec; + tick_time.it_interval.tv_nsec = tick_time.it_value.tv_nsec; + + timerfd_rc = timerfd_settime( thread_info->tick_timer_fd, 0, &tick_time, + NULL ); + if( 0 > timerfd_rc ) + { + DPRINTFE( "Failed to arm timer, error=%s.", strerror( errno ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Dispatch +// ================ +static void sm_timer_dispatch( int selobj, int64_t user_data ) +{ + int retries; + long ms_expired; + SmTimeT time_prev, timer_prev; + unsigned int total_timers_fired = 0; + uint64_t num_expires = 0; + ssize_t s; + SmTimerEntryT* timer_entry; + SmTimerThreadInfoT* thread_info; + SmTimerHistoryEntryT history[SM_MAX_TIMERS_PER_TICK]; + SmErrorT error; + + memset( history, 0, sizeof(history) ); + + for( retries=0; 5 > retries; ++retries ) + { + errno = 0; + s = read( selobj, &num_expires, sizeof(uint64_t) ); + if(( -1 == s )&&( EINTR == errno )) + continue; + break; + } + + if( sizeof(uint64_t) != s ) + { + DPRINTFE( "Failed to read the number of timer expires." ); + return; + } + + thread_info = sm_timer_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return; + } + + ms_expired = sm_time_get_elapsed_ms( &thread_info->sched_timestamp ); + if( ms_expired >= (thread_info->tick_interval_in_ms*SM_MAX_TICK_INTERVALS) ) + { + if( thread_info->scheduling_on_time ) + { + DPRINTFI( "Not scheduling on time, elapsed=%li ms.", ms_expired ); + thread_info->scheduling_on_time = false; + } + + sm_time_get( &thread_info->delay_timestamp ); + + } else { + if( !thread_info->scheduling_on_time ) + { + ms_expired = sm_time_get_elapsed_ms( &thread_info->delay_timestamp ); + if( SM_SCHEDULING_ON_TIME_DEBOUNCE_IN_MS < ms_expired ) + { + DPRINTFI( "Now scheduling on time." ); + thread_info->scheduling_on_time = true; + } + } + } + + sm_time_get( &time_prev ); + + unsigned int timer_i; + for( timer_i=thread_info->last_timer_dispatched; + SM_MAX_TIMERS > timer_i; ++timer_i ) + { + timer_entry = &(thread_info->timers[timer_i]); + + if( SM_TIMER_ENTRY_INUSE == timer_entry->inuse ) + { + ms_expired = sm_time_get_elapsed_ms( &timer_entry->arm_timestamp ); + + if( ms_expired >= timer_entry->ms_interval ) + { + bool rearm; + uint64_t timer_instance = timer_entry->timer_instance; + SmTimerHistoryEntryT* history_entry; + + history_entry = &(history[total_timers_fired]); + + history_entry->inuse = SM_TIMER_ENTRY_INUSE; + snprintf( history_entry->timer_name, + sizeof(history_entry->timer_name), + "%s", timer_entry->timer_name ); + + DPRINTFD( "Timer %s fire, ms_interval=%d, ms_expired=%li.", + timer_entry->timer_name, timer_entry->ms_interval, + ms_expired ); + sm_time_get( &timer_prev ); + rearm = timer_entry->callback( timer_entry->timer_id, + timer_entry->user_data ); + clock_gettime( CLOCK_REALTIME, &timer_entry->last_fired ); + timer_entry->total_fired ++; + ms_expired = sm_time_get_elapsed_ms( &timer_prev ); + history_entry->timer_run_time_in_ms = ms_expired; + DPRINTFD( "Timer %s took %li ms.", history_entry->timer_name, + history_entry->timer_run_time_in_ms ); + + if( timer_instance == timer_entry->timer_instance ) + { + if( rearm ) + { + sm_time_get( &timer_entry->arm_timestamp ); + DPRINTFD( "Timer (%i) rearmed.", timer_entry->timer_id ); + } else { + timer_entry->inuse = 0; + DPRINTFD( "Timer (%i) removed.", timer_entry->timer_id ); + } + } else { + DPRINTFD( "Timer (%i) instance changed since callback, " + "rearm=%d.", timer_entry->timer_id, (int) rearm ); + } + + if( SM_MAX_TIMERS_PER_TICK <= ++total_timers_fired ) + { + DPRINTFD( "Maximum timers per tick (%d) reached.", + SM_MAX_TIMERS_PER_TICK ); + break; + } + } + } + } + + if( SM_MAX_TIMERS <= timer_i ) + { + thread_info->last_timer_dispatched = 0; + } else { + thread_info->last_timer_dispatched = timer_i; + } + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( ms_expired >= (thread_info->tick_interval_in_ms*SM_MAX_TICK_INTERVALS) ) + { + unsigned int timer_i; + for( timer_i=0; SM_MAX_TIMERS_PER_TICK > timer_i; ++timer_i ) + { + SmTimerHistoryEntryT* history_entry = &(history[timer_i]); + + if( SM_TIMER_ENTRY_INUSE == history_entry->inuse ) + { + DPRINTFI( "Timer %s took %li ms.", history_entry->timer_name, + history_entry->timer_run_time_in_ms ); + } + } + + thread_info->scheduling_on_time = false; + sm_time_get( &thread_info->delay_timestamp ); + + DPRINTFI( "Not scheduling on time, timer callbacks are taking too " + "long to execute, elapsed_time=%li ms.", ms_expired ); + } else { + unsigned int timer_i; + for( timer_i=0; SM_MAX_TIMERS_PER_TICK > timer_i; ++timer_i ) + { + SmTimerHistoryEntryT* history_entry = &(history[timer_i]); + + if( SM_TIMER_ENTRY_INUSE == history_entry->inuse ) + { + DPRINTFD( "Timer %s took %li ms.", history_entry->timer_name, + history_entry->timer_run_time_in_ms ); + } + } + + DPRINTFD( "Timer callbacks took %li ms.", ms_expired ); + } + + error = sm_timer_schedule( thread_info ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to schedule timers, error=%s.", + sm_error_str( error ) ); + } + + sm_time_get( &thread_info->sched_timestamp ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Scheduling On Time +// ========================== +bool sm_timer_scheduling_on_time( void ) +{ + SmTimerThreadInfoT* thread_info; + + thread_info = sm_timer_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( true ); + } + + return( thread_info->scheduling_on_time ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Scheduling On Time In Period +// ==================================== +bool sm_timer_scheduling_on_time_in_period( unsigned int period_in_ms ) +{ + long ms_expired; + SmTimerThreadInfoT* thread_info; + + thread_info = sm_timer_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + return( true ); + } + + ms_expired = sm_time_get_elapsed_ms( &thread_info->delay_timestamp ); + return( period_in_ms < ms_expired ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Dump Data +// ================= +void sm_timer_dump_data( FILE* log ) +{ + SmTimerEntryT* timer_entry; + SmTimerThreadInfoT* thread_info; + char buffer[24]; + + fprintf( log, "--------------------------------------------------------------------\n" ); + int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + thread_info = &(_threads[thread_i]); + + if( !(thread_info->inuse) ) + continue; + + fprintf( log, "TIMER DATA for %s\n", thread_info->thread_name ); + fprintf( log, " scheduling_on_time......%s\n", thread_info->scheduling_on_time ? "yes" : "no" ); + fprintf( log, " tick_interval_in_ms.....%u\n", thread_info->tick_interval_in_ms ); + + unsigned int timer_i; + for( timer_i=0; SM_MAX_TIMERS > timer_i; ++timer_i ) + { + timer_entry = &(thread_info->timers[timer_i]); + + if( SM_TIMER_ENTRY_INUSE == timer_entry->inuse ) + { + fprintf( log, " timer (name=%s, id=%i)\n", timer_entry->timer_name, + timer_entry->timer_id ); + fprintf( log, " instance..........%"PRIu64"\n", timer_entry->timer_instance ); + fprintf( log, " ms_interval.......%i\n", timer_entry->ms_interval ); + fprintf( log, " user_data.........%"PRIi64"\n", timer_entry->user_data ); + sm_time_format_monotonic_time(&timer_entry->arm_timestamp, buffer, sizeof(buffer)); + fprintf( log, " timer created at .%s\n", buffer ); + sm_time_format_realtime(&timer_entry->last_fired, buffer, sizeof(buffer)); + fprintf( log, " last fired at ....%s\n", buffer ); + fprintf( log, " total fired ......%d\n", timer_entry->total_fired ); + } + } + fprintf( log, "\n" ); + } + fprintf( log, "--------------------------------------------------------------------\n" ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Initialize +// ================== +SmErrorT sm_timer_initialize( unsigned int tick_interval_in_ms ) +{ + SmTimerThreadInfoT* thread_info = NULL; + SmErrorT error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + unsigned int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + if( !(_threads[thread_i].inuse) ) + { + thread_info = &(_threads[thread_i]); + break; + } + } + + if( NULL == thread_info ) + { + DPRINTFE( "Failed to allocate thread information." ); + goto ERROR; + } + + memset( thread_info, 0, sizeof(SmTimerThreadInfoT) ); + + thread_info->thread_id = pthread_self(); + pthread_getname_np( pthread_self(), thread_info->thread_name, + sizeof(thread_info->thread_name) ); + + memset( thread_info->timers, 0 , sizeof(thread_info->timers) ); + + thread_info->tick_timer_fd = timerfd_create( CLOCK_MONOTONIC, + TFD_NONBLOCK | TFD_CLOEXEC ); + + if( 0 > thread_info->tick_timer_fd ) + { + DPRINTFE( "Failed to create tick timer, error=%s.", + strerror( errno ) ); + goto ERROR; + } + + error = sm_selobj_register( thread_info->tick_timer_fd, + sm_timer_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + close( thread_info->tick_timer_fd ); + thread_info->tick_timer_fd = -1; + goto ERROR; + } + + thread_info->scheduling_on_time = true; + sm_time_get( &thread_info->sched_timestamp ); + thread_info->timer_instance = 0; + thread_info->tick_interval_in_ms = tick_interval_in_ms; + thread_info->last_timer_dispatched = 0; + thread_info->inuse = true; + + error = sm_timer_schedule( thread_info ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to schedule timers, error=%s.", + sm_error_str( error ) ); + close( thread_info->tick_timer_fd ); + thread_info->tick_timer_fd = -1; + goto ERROR; + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_OKAY ); + +ERROR: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return( SM_FAILED ); + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Timer - Finalize +// ================ +SmErrorT sm_timer_finalize( void ) +{ + SmTimerThreadInfoT* thread_info; + SmErrorT error; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return( SM_FAILED ); + } + + thread_info = sm_timer_find_thread_info(); + if( NULL == thread_info ) + { + DPRINTFE( "Failed to find thread information." ); + goto DONE; + } + + memset( thread_info->timers, 0 , sizeof(thread_info->timers) ); + + if( 0 <= thread_info->tick_timer_fd ) + { + error = sm_selobj_deregister( thread_info->tick_timer_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + close( thread_info->tick_timer_fd ); + } + +DONE: + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_timer.h b/service-mgmt/sm-common-1.0.0/src/sm_timer.h new file mode 100644 index 00000000..6de3eef8 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_timer.h @@ -0,0 +1,74 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +// The following module is thread safe. +// +#ifndef __SM_TIMER_H__ +#define __SM_TIMER_H__ + +#include +#include +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_TIMER_ID_INVALID -1 + +typedef int SmTimerIdT; + +typedef bool (*SmTimerCallbackT) (SmTimerIdT timer_id, int64_t user_data ); + +// **************************************************************************** +// Timer - Register +// ================ +extern SmErrorT sm_timer_register( const char name[], unsigned int ms, + SmTimerCallbackT callback, int64_t user_data, SmTimerIdT* timer_id ); +// **************************************************************************** + +// **************************************************************************** +// Timer - Deregister +// ================== +extern SmErrorT sm_timer_deregister( SmTimerIdT timer_id ); +// **************************************************************************** + +// **************************************************************************** +// Timer - Scheduling On Time +// ========================== +extern bool sm_timer_scheduling_on_time( void ); +// **************************************************************************** + +// **************************************************************************** +// Timer - Scheduling On Time In Period +// ==================================== +extern bool sm_timer_scheduling_on_time_in_period( unsigned int period_in_ms ); +// **************************************************************************** + +// **************************************************************************** +// Timer - Dump Data +// ================= +extern void sm_timer_dump_data( FILE* log ); +// **************************************************************************** + +// **************************************************************************** +// Timer - Initialize +// ================== +extern SmErrorT sm_timer_initialize( unsigned int tick_timer_in_ms ); +// **************************************************************************** + +// **************************************************************************** +// Timer - Finalize +// ================ +extern SmErrorT sm_timer_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_TIMER_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_trap.c b/service-mgmt/sm-common-1.0.0/src/sm_trap.c new file mode 100644 index 00000000..82c094a0 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_trap.c @@ -0,0 +1,332 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_trap.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_trap_thread.h" + +typedef struct +{ + bool inuse; + int thread_id; + char thread_name[SM_THREAD_NAME_MAX_CHAR]; +} SmTrapThreadInfoT; + +static int _trap_fd = -1; +static int _process_id; +static char _process_name[SM_PROCESS_NAME_MAX_CHAR]; +static SmTrapThreadInfoT _threads[SM_THREADS_MAX]; +static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_spinlock_t _thread_spinlock; + +// *************************************************************************** +// Trap - Find Thread Info +// ======================== +static SmTrapThreadInfoT* sm_trap_find_thread_info( int thread_id ) +{ + unsigned int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + if( !(_threads[thread_i].inuse) ) + continue; + + if( thread_id == _threads[thread_i].thread_id ) + return( &(_threads[thread_i]) ); + } + + return( NULL ); +} +// *************************************************************************** + +// *************************************************************************** +// Trap - Send Message +// =================== +static void sm_trap_send_msg( void* msg, int msg_size ) +{ + int result; + + int retry_i; + for( retry_i = 5; retry_i != 0; --retry_i ) + { + result = write( _trap_fd, msg, msg_size ); + if(( 0 > result )&&( EINTR == errno )) + { + continue; + } + break; + } +} +// *************************************************************************** + +// *************************************************************************** +// Trap - Signal Handler +// ===================== +static void sm_trap_signal_handler( int signum, siginfo_t* siginfo, + void* context ) +{ + ucontext_t* ucontext = (ucontext_t*) context; + uint32_t msg_marker; + SmTrapThreadMsgT msg; + SmTrapThreadInfoT* info; + int result; + + result = pthread_spin_trylock( &_thread_spinlock ); + if( EBUSY == result ) + { + // Yield to lower priority threads that first called this + // signal handler. + sigset_t signal_mask; + sigemptyset( &signal_mask ); + pselect( 0, NULL, NULL, NULL, NULL, &signal_mask ); + } + + memset( &msg, 0, sizeof(msg) ); + + clock_gettime( CLOCK_REALTIME, &(msg.ts_real) ); + + msg.process_id = _process_id; + snprintf( msg.process_name, sizeof(msg.process_name), "%s", + _process_name ); + + msg.thread_id = (int) syscall( SYS_gettid ); + + info = sm_trap_find_thread_info( msg.thread_id ); + if( NULL != info ) + { + snprintf( msg.thread_name, sizeof(msg.thread_name), "%s", + info->thread_name ); + } + + msg.si_address = siginfo->si_addr; + msg.si_num = siginfo->si_signo; + msg.si_code = siginfo->si_code; + msg.si_errno = siginfo->si_errno; + + memcpy( &(msg.user_context), ucontext, sizeof(ucontext_t) ); + + msg.address_trace_count = backtrace( &(msg.address_trace[0]), + SM_TRAP_MAX_ADDRESS_TRACE ); + + // Send message start marker. + msg_marker = SM_TRAP_THREAD_MSG_START_MARKER; + sm_trap_send_msg( &msg_marker, sizeof(msg_marker) ); + + // Send the process information across. + sm_trap_send_msg( &msg, sizeof(msg) ); + + // Send the function names across. + backtrace_symbols_fd( msg.address_trace, msg.address_trace_count, + _trap_fd ); + + // Send message end marker. + msg_marker = SM_TRAP_THREAD_MSG_END_MARKER; + sm_trap_send_msg( &msg_marker, sizeof(msg_marker) ); + + close( _trap_fd ); + + // Core dump produced if enabled. + _exit( EXIT_SUCCESS ); +} +// **************************************************************************** + +// *************************************************************************** +// Trap - Set Thread Information +// ============================= +void sm_trap_set_thread_info( void ) +{ + int thread_id; + SmTrapThreadInfoT* info; + + if( 0 != pthread_mutex_lock( &_mutex ) ) + { + DPRINTFE( "Failed to capture mutex." ); + return; + } + + thread_id = (int) syscall( SYS_gettid ); + + info = sm_trap_find_thread_info( thread_id ); + if( NULL == info ) + { + int thread_i; + for( thread_i=0; SM_THREADS_MAX > thread_i; ++thread_i ) + { + info = &(_threads[thread_i]); + + if( !(info->inuse) ) + { + info->thread_id = thread_id; + pthread_getname_np( pthread_self(), info->thread_name, + sizeof(info->thread_name) ); + info->inuse = true; + break; + } + } + } + + if( 0 != pthread_mutex_unlock( &_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + return; + } +} +// *************************************************************************** + +// *************************************************************************** +// Trap - Initialize +// ================= +SmErrorT sm_trap_initialize( const char process_name[] ) +{ + int fd_i; + int flags; + int result; + int trap_fds[2] = {-1, -1}; + struct sigaction sa; + void* dummy_trace[1]; + int dummy_trace_count; + SmErrorT error = SM_FAILED; + + _process_id = (int) getpid(); + snprintf( _process_name, sizeof(_process_name), "%s", process_name ); + + // Force load the backtrace function symbols, need to avoid malloc + // in the trap exception handler. + dummy_trace_count = backtrace( dummy_trace, 1 ); + backtrace_symbols_fd( dummy_trace, dummy_trace_count, -1 ); + + result = pipe( trap_fds ); + if( 0 > result ) + { + printf( "Failed to open a pipe to trap thread, error=%s.\n", + strerror( errno ) ); + error = SM_FAILED; + goto ERROR; + } + + for( fd_i=0; 2 > fd_i; ++fd_i ) + { + // Set to non-blocking. + flags = fcntl( trap_fds[fd_i], F_GETFL, 0 ); + if( 0 > flags ) + { + printf( "Failed to get flags, error=%s.\n", strerror( errno ) ); + error = SM_FAILED; + goto ERROR; + } + + result = fcntl( trap_fds[fd_i], F_SETFL, flags | O_NONBLOCK ); + if( 0 > result ) + { + printf( "Failed to set flags, error=%s.\n", strerror( errno ) ); + error = SM_FAILED; + goto ERROR; + } + + // Close on exec. + flags = fcntl( trap_fds[fd_i], F_GETFD, 0 ); + if( 0 > flags ) + { + printf( "Failed to get flags, error=%s.\n", strerror( errno ) ); + error = SM_FAILED; + goto ERROR; + } + + result = fcntl( trap_fds[fd_i], F_SETFD, flags | FD_CLOEXEC ); + if( 0 > result ) + { + printf( "Failed to set flags, error=%s.\n", strerror( errno ) ); + error = SM_FAILED; + goto ERROR; + } + } + + error = sm_trap_thread_start( trap_fds[0] ); + if( SM_OKAY != error ) + { + printf( "Failed to start trap thread, error=%s.\n", + sm_error_str( error ) ); + goto ERROR; + } + + result = pthread_spin_init( &_thread_spinlock, 0 ); + if( 0 != result ) + { + printf( "Failed initialize thread spin lock, error=%s.\n", + strerror( errno ) ); + error = SM_FAILED; + goto ERROR; + } + + close( trap_fds[0] ); // close the read end + _trap_fd = trap_fds[1]; // save write end + + memset( &sa, 0, sizeof(sa) ); + sigfillset( &sa.sa_mask ); + sa.sa_sigaction = sm_trap_signal_handler; + sa.sa_flags = SA_SIGINFO; + + sigaction( SIGSEGV, &sa, NULL ); + sigaction( SIGILL, &sa, NULL ); + sigaction( SIGFPE, &sa, NULL ); + sigaction( SIGBUS, &sa, NULL ); + sigaction( SIGABRT, &sa, NULL ); + + return( SM_OKAY ); + +ERROR: + for( fd_i=0; 2 > fd_i; ++fd_i ) + { + if( -1 != trap_fds[fd_i] ) + { + close( trap_fds[fd_i] ); + trap_fds[fd_i] = -1; + } + } + return( error ); +} +// *************************************************************************** + +// *************************************************************************** +// Trap - Finalize +// =============== +SmErrorT sm_trap_finalize( void ) +{ + SmErrorT error; + + error = sm_trap_thread_stop(); + if( SM_OKAY != error ) + { + printf( "Failed to stop trap thread, error=%s.\n", + sm_error_str( error ) ); + } + + if( -1 != _trap_fd ) + { + close( _trap_fd ); + _trap_fd = -1; + } + + return( SM_OKAY ); +} +// *************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_trap.h b/service-mgmt/sm-common-1.0.0/src/sm_trap.h new file mode 100644 index 00000000..533f0caa --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_trap.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_TRAP_H__ +#define __SM_TRAP_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// *************************************************************************** +// Trap - Set Thread Information +// ============================= +extern void sm_trap_set_thread_info( void ); +// *************************************************************************** + +// *************************************************************************** +// Trap - Initialize +// ================= +extern SmErrorT sm_trap_initialize( const char process_name[] ); +// *************************************************************************** + +// *************************************************************************** +// Trap - Finalize +// =============== +extern SmErrorT sm_trap_finalize( void ); +// *************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_TRAP_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_trap_thread.c b/service-mgmt/sm-common-1.0.0/src/sm_trap_thread.c new file mode 100644 index 00000000..75da87b7 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_trap_thread.c @@ -0,0 +1,848 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_trap_thread.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_time.h" +#include "sm_utils.h" +#include "sm_selobj.h" +#include "sm_timer.h" +#include "sm_debug.h" + +#define SM_TRAP_THREAD_NAME "sm_trap" +#define SM_TRAP_THREAD_TICK_INTERVAL_IN_MS 1000 +#define SM_TRAP_THREAD_LOG_FILE "/var/log/sm-trap.log" + +static sig_atomic_t _stay_on = 1; +static pid_t _trap_thread_pid = -1; +static int _trap_fd = -1; +static FILE* _trap_log = NULL; +static char _si_num_str[80] = ""; +static char _si_code_str[80] = ""; +static char _msg_buffer[8192] __attribute__((aligned)); +static char _rx_buffer[sizeof(_msg_buffer)*2] __attribute__((aligned)); + +// **************************************************************************** +// Trap Thread - Signal Handler +// ============================ +static void sm_trap_thread_signal_handler( int signum ) +{ + switch( signum ) + { + case SIGINT: + case SIGTERM: + case SIGQUIT: + _stay_on = 0; + break; + + case SIGCONT: + DPRINTFD( "Ignoring signal SIGCONT (%i).", signum ); + break; + + case SIGHUP: + DPRINTFD( "Parent process is shutting down or has died, " + "exiting." ); + _stay_on = 0; + break; + + default: + DPRINTFD( "Signal (%i) ignored.", signum ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Setup Signal Handler +// ================================== +static void sm_trap_thread_setup_signal_handler( void ) +{ + struct sigaction sa; + + memset( &sa, 0, sizeof(sa) ); + sa.sa_handler = sm_trap_thread_signal_handler; + + sigaction( SIGINT, &sa, NULL ); + sigaction( SIGTERM, &sa, NULL ); + sigaction( SIGQUIT, &sa, NULL ); + sigaction( SIGCONT, &sa, NULL ); + sigaction( SIGHUP, &sa, NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Si-Num String +// =========================== +static const char* sm_trap_thread_si_num_str( int signum ) +{ + _si_num_str[0] = '\0'; + + switch( signum ) + { + case SIGSEGV: + snprintf( _si_num_str, sizeof(_si_num_str), + "invalid-memory-reference" ); + break; + case SIGILL: + snprintf( _si_num_str, sizeof(_si_num_str), + "illegal-instruction" ); + break; + case SIGFPE: + snprintf( _si_num_str, sizeof(_si_num_str), + "floating-point-exception" ); + break; + case SIGBUS: + snprintf( _si_num_str, sizeof(_si_num_str), + "bus-error" ); + break; + case SIGABRT: + snprintf( _si_num_str, sizeof(_si_num_str), + "abort" ); + break; + } + + return( _si_num_str ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Si-Code String +// ============================ +static const char* sm_trap_thread_si_code_str( int signum, int si_code ) +{ + _si_code_str[0] = '\0'; + + if( SIGILL == signum ) + { + switch( si_code ) + { + case ILL_ILLOPC: + snprintf( _si_code_str, sizeof(_si_code_str), + "illegal-opcode" ); + break; + case ILL_ILLOPN: + snprintf( _si_code_str, sizeof(_si_code_str), + "illegal-operand" ); + break; + case ILL_ILLADR: + snprintf( _si_code_str, sizeof(_si_code_str), + "illegal-addressing-mode" ); + break; + case ILL_ILLTRP: + snprintf( _si_code_str, sizeof(_si_code_str), + "illegal-trap" ); + break; + case ILL_PRVOPC: + snprintf( _si_code_str, sizeof(_si_code_str), + "privileged-opcode" ); + break; + case ILL_PRVREG: + snprintf( _si_code_str, sizeof(_si_code_str), + "privileged-register" ); + break; + case ILL_COPROC: + snprintf( _si_code_str, sizeof(_si_code_str), + "coprocessor-error" ); + break; + case ILL_BADSTK: + snprintf( _si_code_str, sizeof(_si_code_str), + "internal-stack-error" ); + break; + } + + } else if( SIGFPE == signum ) { + switch( si_code ) + { + case FPE_INTDIV: + snprintf( _si_code_str, sizeof(_si_code_str), + "integer-divide-by-zero" ); + break; + case FPE_INTOVF: + snprintf( _si_code_str, sizeof(_si_code_str), + "integer-overflow" ); + break; + case FPE_FLTDIV: + snprintf( _si_code_str, sizeof(_si_code_str), + "floating-point-divide-by-zero" ); + break; + case FPE_FLTOVF: + snprintf( _si_code_str, sizeof(_si_code_str), + "floating-point-overflow" ); + break; + case FPE_FLTUND: + snprintf( _si_code_str, sizeof(_si_code_str), + "floating-point-underflow" ); + break; + case FPE_FLTRES: + snprintf( _si_code_str, sizeof(_si_code_str), + "floating-point-inexact-result" ); + break; + case FPE_FLTINV: + snprintf( _si_code_str, sizeof(_si_code_str), + "floating-point-invalid-operation" ); + break; + case FPE_FLTSUB: + snprintf( _si_code_str, sizeof(_si_code_str), + "subscript-out-of-range" ); + break; + } + + } else if( SIGSEGV == signum ) { + switch( si_code ) + { + case SEGV_MAPERR: + snprintf( _si_code_str, sizeof(_si_code_str), + "address-not-mapped-to-object" ); + break; + case SEGV_ACCERR: + snprintf( _si_code_str, sizeof(_si_code_str), + "invalid-permissions-for-mapped-object" ); + break; + } + + } else if( SIGBUS == signum ) { + switch( si_code ) + { + case BUS_ADRALN: + snprintf( _si_code_str, sizeof(_si_code_str), + "invalid-address-alignment" ); + break; + case BUS_ADRERR: + snprintf( _si_code_str, sizeof(_si_code_str), + "nonexistent-physical-address" ); + break; + case BUS_OBJERR: + snprintf( _si_code_str, sizeof(_si_code_str), + "object-specific-hardware-error" ); + break; + } + } + + if( '\0' == _si_code_str[0] ) + { + switch( si_code ) + { + case SI_USER: + snprintf( _si_code_str, sizeof(_si_code_str), "si-user" ); + break; + case SI_KERNEL: + snprintf( _si_code_str, sizeof(_si_code_str), "si-kernel" ); + break; + case SI_QUEUE: + snprintf( _si_code_str, sizeof(_si_code_str), "si-queue" ); + break; + case SI_TIMER: + snprintf( _si_code_str, sizeof(_si_code_str), "si-timer" ); + break; + case SI_MESGQ: + snprintf( _si_code_str, sizeof(_si_code_str), "si-msg_queue" ); + break; + case SI_ASYNCIO: + snprintf( _si_code_str, sizeof(_si_code_str), "si-async_io" ); + break; + case SI_SIGIO: + snprintf( _si_code_str, sizeof(_si_code_str), "si-sigio" ); + break; + case SI_TKILL: + snprintf( _si_code_str, sizeof(_si_code_str), "si-tkill" ); + break; + } + } + + return( _si_code_str ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Log +// ================= +static void sm_trap_thread_log( SmTrapThreadMsgT* msg ) +{ + char time_str[80]; + char date_str[32]; + struct tm t_real; + struct timespec ts_real; + ucontext_t* ucontext = &(msg->user_context); + + if( NULL == localtime_r( &(msg->ts_real.tv_sec), &t_real ) ) + { + snprintf( time_str, sizeof(time_str), "YYYY:MM:DD HH:MM:SS.xxx" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + snprintf( time_str, sizeof(time_str), "%s.%03ld", date_str, + msg->ts_real.tv_nsec/1000000 ); + } + + fprintf( _trap_log, "\n*** trap detected at %s ***\n", time_str ); + + clock_gettime( CLOCK_REALTIME, &(ts_real) ); + + if( NULL == localtime_r( &(ts_real.tv_sec), &t_real ) ) + { + snprintf( time_str, sizeof(time_str), "YYYY:MM:DD HH:MM:SS.xxx" ); + } else { + strftime( date_str, sizeof(date_str), "%FT%T", &t_real ); + snprintf( time_str, sizeof(time_str), "%s.%03ld", date_str, + ts_real.tv_nsec/1000000 ); + } + + fprintf( _trap_log, "written-at: %s\n", time_str ); + + fprintf( _trap_log, "process-name: %s (%i)\n", msg->process_name, + msg->process_id ); + + if( '\0' == msg->thread_name[0] ) + { + fprintf( _trap_log, "thread-name: %s (%i)\n", msg->process_name, + msg->thread_id ); + } else { + fprintf( _trap_log, "thread-name: %s (%i)\n", msg->thread_name, + msg->thread_id ); + } + + fprintf( _trap_log, "signal-number: %s (%i)\n", + sm_trap_thread_si_num_str(msg->si_num), msg->si_num ); + + fprintf( _trap_log, "signal-code: %s (%i)\n", + sm_trap_thread_si_code_str( msg->si_num, msg->si_code), + msg->si_code ); + + if( 0 != msg->si_errno ) + { + fprintf( _trap_log, "signal-errno: %s (%i)\n", + strerror(msg->si_errno), msg->si_errno ); + } + + fprintf( _trap_log, "fault-address: %p\n", msg->si_address ); + + fprintf( _trap_log, "registers: \n" ); +#ifdef __x86_64__ + greg_t* gregs = &(ucontext->uc_mcontext.gregs[0]); + + fprintf( _trap_log, "RIP = %016llX (instruction-pointer)\n", + (long long) gregs[REG_RIP] ); + + fprintf( _trap_log, "RDI = %016llX RSP = %016llX " + "RSI = %016llX RDX = %016llX\n", + (long long) gregs[REG_RDI], (long long) gregs[REG_RSP], + (long long) gregs[REG_RSI], (long long) gregs[REG_RDX] ); + + fprintf( _trap_log, "RCX = %016llX RBP = %016llX " + "RAX = %016llX RBX = %016llX\n", + (long long) gregs[REG_RCX], (long long) gregs[REG_RBP], + (long long) gregs[REG_RAX], (long long) gregs[REG_RBX] ); + + fprintf( _trap_log, "R8 = %016llX R9 = %016llX " + "R10 = %016llX R11 = %016llX\n", + (long long) gregs[REG_R8], (long long) gregs[REG_R9], + (long long) gregs[REG_R10], (long long) gregs[REG_R11] ); + + fprintf( _trap_log, "R12 = %016llX R13 = %016llX " + "R14 = %016llX R15 = %016llX\n", + (long long) gregs[REG_R12], (long long) gregs[REG_R13], + (long long) gregs[REG_R14], (long long) gregs[REG_R15] ); + + fprintf( _trap_log, "ERR = %016llX TRAPNO = %016llX\n", + (long long) gregs[REG_ERR], (long long) gregs[REG_TRAPNO] ); + + fprintf( _trap_log, "CR2 = %016llX OLDMASK = %016llX\n", + (long long) gregs[REG_CR2], (long long) gregs[REG_OLDMASK] ); + +#elif __i386__ + greg_t* gregs = &(ucontext->uc_mcontext.gregs[0]); + + fprintf( _trap_log, "EIP = %08lX (instruction-pointer)\n", + (long) gregs[REG_EIP] ); + + fprintf( _trap_log, "EDI = %08lX ESP = %08lX ESI = %08lX EBP = %08lX\n", + (long) gregs[REG_EDI], (long) gregs[REG_ESP], + (long) gregs[REG_ESI], (long) gregs[REG_EBP] ); + + fprintf( _trap_log, "EDX = %08lX EAX = %08lX ECX = %08lX EBX = %08lX\n", + (long) gregs[REG_EDX], (long) gregs[REG_EAX], + (long) gregs[REG_ECX], (long) gregs[REG_EBX] ); + + fprintf( _trap_log, "ERR = %08lX TRAPNO = %08lX\n", + (long) gregs[REG_ERR], (long) gregs[REG_TRAPNO] ); + +#elif __PPC__ + fprintf( _trap_log, "NIP = %08lX (instruction-pointer)\n", + (long) ucontext->uc_mcontext.regs->nip ); +#endif + + fprintf( _trap_log, "traceback: \n" ); + fprintf( _trap_log, "%s\n", msg->address_trace_symbols ); + + fflush( _trap_log ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Get Message +// ========================= +static bool sm_trap_thread_get_message( char** byte_pointer, int* bytes_left ) +{ + bool msg_boundary_found = false; + char* msg_start_pointer = NULL; + char* msg_end_pointer = NULL; + int msg_start_offset = 0; + int msg_size = 0; + int bytes_move = 0; + + msg_boundary_found = false; + msg_start_pointer = _rx_buffer; + while( msg_start_pointer != *byte_pointer ) + { + if( SM_TRAP_THREAD_MSG_START_MARKER == *(uint32_t*) msg_start_pointer ) + { + DPRINTFD( "Message start delimiter found." ); + msg_start_pointer += sizeof(uint32_t); + msg_boundary_found = true; + break; + } + ++msg_start_pointer; + ++msg_start_offset; + } + + if( !msg_boundary_found ) + { + DPRINTFD( "Message start point not yet received." ); + return( false ); + } + + msg_boundary_found = false; + msg_end_pointer = msg_start_pointer; + while( msg_end_pointer != *byte_pointer ) + { + if( SM_TRAP_THREAD_MSG_END_MARKER == *(uint32_t*) msg_end_pointer ) + { + DPRINTFD( "Message end delimiter found." ); + msg_end_pointer += sizeof(uint32_t); + msg_boundary_found = true; + break; + } + ++msg_end_pointer; + ++msg_size; + } + + if( !msg_boundary_found ) + { + DPRINTFD( "Message end point not yet received." ); + return( false ); + } + + if( msg_size > (int) sizeof(_msg_buffer) ) + { + DPRINTFD( "Message received is too large, msg_size=%i, max=%i.", + msg_size, (int) sizeof(_msg_buffer) ); + *byte_pointer = _rx_buffer; + *bytes_left = sizeof(_rx_buffer); + memset( *byte_pointer, 0, sizeof(_rx_buffer) ); + return( false ); + } + + DPRINTFD( "Message received, msg_size=%i.", msg_size ); + + memset( _msg_buffer, 0, sizeof(_msg_buffer) ); + memcpy( _msg_buffer, msg_start_pointer, msg_size ); + + // Move the remaining bytes to the head of the receive buffer. + if( msg_end_pointer != *byte_pointer ) + { + char* p; + for( p = msg_end_pointer; p != *byte_pointer; ++p ) + { + ++bytes_move; + } + + if( bytes_move > 0 ) + { + memmove( _rx_buffer, msg_end_pointer, bytes_move ); + memset( msg_end_pointer, 0, bytes_move ); + } + } + + *byte_pointer = &(_rx_buffer[bytes_move]); + *bytes_left = sizeof(_rx_buffer) - bytes_move; + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Dispatch +// ====================== +static void sm_trap_thread_dispatch( int selobj, int64_t user_data ) +{ + static char* byte_pointer = _rx_buffer; + static int bytes_left = sizeof(_rx_buffer); + + int bytes_read = 0; + + int retry_count; + for( retry_count = 5; retry_count != 0; --retry_count ) + { + bytes_read = read( selobj, byte_pointer, bytes_left ); + if( 0 < bytes_read ) + { + DPRINTFD( "Bytes read %i.", bytes_read ); + + } else if( 0 == bytes_read ) { + // For connection oriented sockets, this indicates that the peer + // has performed an orderly shutdown. + DPRINTFI( "Trap connection has been broken, exiting." ); + _stay_on = 0; + break; + + } else if(( 0 > bytes_read )&&( EAGAIN == errno )) { + DPRINTFD( "No more data to be read." ); + break; + + } else if(( 0 > bytes_read )&&( EINTR != errno )) { + DPRINTFE( "Failed to read message, errno=%s.", strerror( errno ) ); + return; + } + + byte_pointer += bytes_read; + bytes_left -= bytes_read; + + if( 0 > bytes_left ) + { + byte_pointer = _rx_buffer; + bytes_left = sizeof(_rx_buffer); + memset( byte_pointer, 0, sizeof(_rx_buffer) ); + return; + } + } + + while( sm_trap_thread_get_message( &byte_pointer, &bytes_left ) ) + { + sm_trap_thread_log( (SmTrapThreadMsgT*) _msg_buffer ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Initialize +// ======================== +static SmErrorT sm_trap_thread_initialize( int trap_fd ) +{ + SmErrorT error; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_timer_initialize( SM_TRAP_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_selobj_register( trap_fd, sm_trap_thread_dispatch, 0 ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to register selection object, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + _trap_fd = trap_fd; + + _trap_log = fopen( SM_TRAP_THREAD_LOG_FILE, "a" ); + if( NULL == _trap_log ) + { + DPRINTFE( "Failed to open trap log file (%s).", + SM_TRAP_THREAD_LOG_FILE ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Finalize +// ====================== +static SmErrorT sm_trap_thread_finalize( void ) +{ + SmErrorT error; + + if( -1 != _trap_fd ) + { + error = sm_selobj_deregister( _trap_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to deregister selection object, error=%s.", + sm_error_str( error ) ); + } + + close( _trap_fd ); + _trap_fd = -1; + } + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize timer module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize selection object module, error=%s.", + sm_error_str( error ) ); + } + + if( NULL != _trap_log ) + { + fflush( _trap_log ); + fclose( _trap_log ); + _trap_log = NULL; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Main +// ================== +static SmErrorT sm_trap_thread_main( int trap_fd ) +{ + int result; + SmErrorT error; + + sm_trap_thread_setup_signal_handler(); + + DPRINTFI( "Starting" ); + + result = setpriority( PRIO_PROCESS, getpid(), -2 ); + if( 0 > result ) + { + DPRINTFE( "Failed to set priority of trap thread, error=%s.", + strerror( errno ) ); + return( SM_FAILED ); + } + + error = sm_trap_thread_initialize( trap_fd ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize trap thread, error=%s.", + sm_error_str(error) ); + return( error ); + } + + DPRINTFI( "Started." ); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_TRAP_THREAD_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + } + + DPRINTFI( "Shutting down." ); + + error = sm_trap_thread_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize trap thread, error=%s.", + sm_error_str(error) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Start +// =================== +SmErrorT sm_trap_thread_start( int trap_fd ) +{ + pid_t pid; + + _trap_thread_pid = -1; + + pid = fork(); + if( 0 > pid ) + { + printf( "Failed to fork process for trap thread, error=%s.\n", + strerror( errno ) ); + return( SM_FAILED ); + + } else if( 0 == pid ) { + // Child process. + int result; + struct rlimit file_limits; + SmErrorT error; + + result = prctl( PR_SET_NAME, SM_TRAP_THREAD_NAME ); + if( 0 > result ) + { + printf( "Failed to set trap thread process name, " + "error=%s.\n", strerror(errno) ); + exit( EXIT_FAILURE ); + } + + result = prctl( PR_SET_PDEATHSIG, SIGHUP ); + if( 0 > result ) + { + printf( "Failed to set trap thread parent death signal, " + "error=%s.\n", strerror(errno) ); + exit( EXIT_FAILURE ); + } + + if( 0 > getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + printf( "Failed to get file limits, error=%s.", + strerror( errno ) ); + exit( EXIT_FAILURE ); + } + + int fd_i; + for( fd_i=0; fd_i < (int) file_limits.rlim_cur; ++fd_i ) + { + if( fd_i != trap_fd ) + { + close( fd_i ); + } + } + + if( 0 > open( "/dev/null", O_RDONLY ) ) + { + printf( "Failed to open stdin to /dev/null, error=%s.\n", + strerror( errno ) ); + } + + if( 0 > open( "/dev/null", O_WRONLY ) ) + { + printf( "Failed to open stdout to /dev/null, error=%s.\n", + strerror( errno ) ); + } + + if( 0 > open( "/dev/null", O_WRONLY ) ) + { + printf( "Failed to open stderr to /dev/null, error=%s.\n", + strerror( errno ) ); + } + + error = sm_debug_initialize(); + if( SM_OKAY != error ) + { + printf( "Debug initialization failed, error=%s.\n", + sm_error_str( error ) ); + exit( EXIT_FAILURE ); + } + + if( !sm_utils_set_pid_file( SM_TRAP_PROCESS_PID_FILENAME ) ) + { + printf( "Failed to write pid file for %s, error=%s.\n", + SM_TRAP_THREAD_NAME, strerror(errno) ); + exit( EXIT_FAILURE ); + } + + error = sm_trap_thread_main( trap_fd ); + if( SM_OKAY != error ) + { + printf( "Process failure, error=%s.\n", sm_error_str( error ) ); + exit( EXIT_FAILURE ); + } + + error = sm_debug_finalize(); + if( SM_OKAY != error ) + { + printf( "Debug finalization failed, error=%s.\n", + sm_error_str( error ) ); + } + + exit( EXIT_SUCCESS ); + + } else { + // Parent process. + printf( "Trap thread (%i) created.\n", (int) pid ); + _trap_thread_pid = pid; + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Stop +// ================== +SmErrorT sm_trap_thread_stop( void ) +{ + if( -1 != _trap_thread_pid ) + { + pid_t pid; + long ms_expired; + SmTimeT time_prev; + + while( true ) + { + pid = waitpid( _trap_thread_pid, NULL, WNOHANG | WUNTRACED ); + if( -1 == pid ) + { + if( ECHILD != errno ) + { + printf( "Failed to wait for trap thread exit, error=%s.\n", + strerror(errno) ); + kill( _trap_thread_pid, SIGKILL ); + _trap_thread_pid = -1; + } + break; + + } else if( pid == _trap_thread_pid ) { + break; + } + + printf( "Sending trap thread (%i) shutdown signal.\n", + (int) _trap_thread_pid ); + kill( _trap_thread_pid, SIGHUP ); + + ms_expired = sm_time_get_elapsed_ms( &time_prev ); + if( 5000 <= ms_expired ) + { + printf( "Failed to stop trap thread, using SIGKILL.\n" ); + kill( _trap_thread_pid, SIGKILL ); + _trap_thread_pid = -1; + break; + } + + usleep( 250000 ); // 250 milliseconds. + } + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_trap_thread.h b/service-mgmt/sm-common-1.0.0/src/sm_trap_thread.h new file mode 100644 index 00000000..fd0fae2d --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_trap_thread.h @@ -0,0 +1,58 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_TRAP_THREAD_H__ +#define __SM_TRAP_THREAD_H__ + +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_TRAP_THREAD_MSG_START_MARKER 0xA5A5A5A5 +#define SM_TRAP_THREAD_MSG_END_MARKER 0xFDFDFDFD +#define SM_TRAP_MAX_ADDRESS_TRACE 32 + +typedef struct +{ + struct timespec ts_real; + int process_id; + char process_name[SM_PROCESS_NAME_MAX_CHAR]; + int thread_id; + char thread_name[SM_THREAD_NAME_MAX_CHAR]; + int si_num; + int si_code; + int si_errno; + void* si_address; + ucontext_t user_context; + int address_trace_count; + void* address_trace[SM_TRAP_MAX_ADDRESS_TRACE]; + // Starting point of symbol dump. + char address_trace_symbols[0]; +} SmTrapThreadMsgT; + +// **************************************************************************** +// Trap Thread - Start +// =================== +extern SmErrorT sm_trap_thread_start( int trap_fd ); +// **************************************************************************** + +// **************************************************************************** +// Trap Thread - Stop +// ================== +extern SmErrorT sm_trap_thread_stop( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_TRAP_THREAD_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_types.c b/service-mgmt/sm-common-1.0.0/src/sm_types.c new file mode 100644 index 00000000..0012972a --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_types.c @@ -0,0 +1,1824 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_types.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_debug.h" + +#define SM_VALUE_STR_MAPPING_MAX_CHAR 128 + +typedef struct +{ + int value; + char str[SM_VALUE_STR_MAPPING_MAX_CHAR]; +} SmValueStrMappingT; + +static SmValueStrMappingT +_sm_node_admin_state_mappings[SM_NODE_ADMIN_STATE_MAX] = +{ + { SM_NODE_ADMIN_STATE_NIL, "nil" }, + { SM_NODE_ADMIN_STATE_UNKNOWN, "unknown" }, + { SM_NODE_ADMIN_STATE_LOCKED, "locked" }, + { SM_NODE_ADMIN_STATE_UNLOCKED, "unlocked" }, +}; + +static SmValueStrMappingT +_sm_node_oper_state_mappings[SM_NODE_OPERATIONAL_STATE_MAX] = +{ + { SM_NODE_OPERATIONAL_STATE_NIL, "nil" }, + { SM_NODE_OPERATIONAL_STATE_UNKNOWN, "unknown" }, + { SM_NODE_OPERATIONAL_STATE_ENABLED, "enabled" }, + { SM_NODE_OPERATIONAL_STATE_DISABLED, "disabled" }, +}; + +static SmValueStrMappingT +_sm_node_avail_status_mappings[SM_NODE_AVAIL_STATUS_MAX] = +{ + { SM_NODE_AVAIL_STATUS_NIL, "nil" }, + { SM_NODE_AVAIL_STATUS_UNKNOWN, "unknown" }, + { SM_NODE_AVAIL_STATUS_NONE, "" }, + { SM_NODE_AVAIL_STATUS_AVAILABLE, "available" }, + { SM_NODE_AVAIL_STATUS_DEGRADED, "degraded" }, + { SM_NODE_AVAIL_STATUS_FAILED, "failed" }, +}; + +static SmValueStrMappingT +_sm_node_ready_state_mappings[SM_NODE_READY_STATE_MAX] = +{ + { SM_NODE_READY_STATE_NIL, "nil" }, + { SM_NODE_READY_STATE_UNKNOWN, "unknown" }, + { SM_NODE_READY_STATE_ENABLED, "enabled" }, + { SM_NODE_READY_STATE_DISABLED, "disabled" }, +}; + +static SmValueStrMappingT +_sm_node_event_mappings[SM_NODE_EVENT_MAX] = +{ + { SM_NODE_EVENT_NIL, "nil" }, + { SM_NODE_EVENT_UNKNOWN, "unknown" }, + { SM_NODE_EVENT_ENABLED, "enabled" }, + { SM_NODE_EVENT_DISABLED, "disabled" }, + { SM_NODE_EVENT_AUDIT, "audit" }, +}; + +static SmValueStrMappingT +_sm_interface_state_mappings[SM_INTERFACE_STATE_MAX] = +{ + { SM_INTERFACE_STATE_NIL, "nil" }, + { SM_INTERFACE_STATE_UNKNOWN, "unknown" }, + { SM_INTERFACE_STATE_ENABLED, "enabled" }, + { SM_INTERFACE_STATE_DISABLED, "disabled" }, + { SM_INTERFACE_STATE_NOT_IN_USE, "not-in-use" } +}; + +static SmValueStrMappingT +_sm_network_type_mappings[SM_NETWORK_TYPE_MAX] = +{ + { SM_NETWORK_TYPE_NIL, "nil" }, + { SM_NETWORK_TYPE_UNKNOWN, "unknown" }, + { SM_NETWORK_TYPE_IPV4, "ipv4" }, + { SM_NETWORK_TYPE_IPV6, "ipv6" }, + { SM_NETWORK_TYPE_IPV4_UDP, "ipv4-udp" }, + { SM_NETWORK_TYPE_IPV6_UDP, "ipv6-udp" }, +}; + +static SmValueStrMappingT +_sm_path_type_mappings[SM_PATH_TYPE_MAX] = +{ + { SM_PATH_TYPE_NIL, "nil" }, + { SM_PATH_TYPE_UNKNOWN, "unknown" }, + { SM_PATH_TYPE_PRIMARY, "primary" }, + { SM_PATH_TYPE_SECONDARY, "secondary" }, + { SM_PATH_TYPE_STATUS_ONLY, "status-only" }, +}; + +static SmValueStrMappingT +_sm_auth_type_mappings[SM_AUTH_TYPE_MAX] = +{ + { SM_AUTH_TYPE_NIL, "nil" }, + { SM_AUTH_TYPE_UNKNOWN, "unknown" }, + { SM_AUTH_TYPE_NONE, "none" }, + { SM_AUTH_TYPE_HMAC_SHA512, "hmac-sha512" }, +}; + +static SmValueStrMappingT +_sm_orchestration_type_mappings[SM_ORCHESTRATION_TYPE_MAX] = +{ + { SM_ORCHESTRATION_TYPE_NIL, "nil" }, + { SM_ORCHESTRATION_TYPE_UNKNOWN, "unknown" }, + { SM_ORCHESTRATION_TYPE_GEOGRAPHICAL, "geographical" }, + { SM_ORCHESTRATION_TYPE_REGIONAL, "regional" }, + { SM_ORCHESTRATION_TYPE_HYBRID, "hybrid" }, +}; + +static SmValueStrMappingT +_sm_designation_type_mappings[SM_DESIGNATION_TYPE_MAX] = +{ + { SM_DESIGNATION_TYPE_NIL, "nil" }, + { SM_DESIGNATION_TYPE_UNKNOWN, "unknown" }, + { SM_DESIGNATION_TYPE_LEADER, "leader" }, + { SM_DESIGNATION_TYPE_BACKUP, "backup" }, + { SM_DESIGNATION_TYPE_OTHER, "other" }, +}; + +static SmValueStrMappingT +_sm_service_domain_state_mappings[SM_SERVICE_DOMAIN_STATE_MAX] = +{ + { SM_SERVICE_DOMAIN_STATE_NIL, "nil" }, + { SM_SERVICE_DOMAIN_STATE_UNKNOWN, "unknown" }, + { SM_SERVICE_DOMAIN_STATE_INITIAL, "initial" }, + { SM_SERVICE_DOMAIN_STATE_WAITING, "waiting" }, + { SM_SERVICE_DOMAIN_STATE_LEADER, "leader" }, + { SM_SERVICE_DOMAIN_STATE_BACKUP, "backup" }, + { SM_SERVICE_DOMAIN_STATE_OTHER, "other" }, +}; + +static SmValueStrMappingT +_sm_service_domain_event_mappings[SM_SERVICE_DOMAIN_EVENT_MAX] = +{ + { SM_SERVICE_DOMAIN_EVENT_NIL, "nil" }, + { SM_SERVICE_DOMAIN_EVENT_UNKNOWN, "unknown" }, + { SM_SERVICE_DOMAIN_EVENT_HELLO_MSG, "hello-message" }, + { SM_SERVICE_DOMAIN_EVENT_NEIGHBOR_AGEOUT, "neighbor-ageout" }, + { SM_SERVICE_DOMAIN_EVENT_INTERFACE_ENABLED, "interface-enabled" }, + { SM_SERVICE_DOMAIN_EVENT_INTERFACE_DISABLED, "interface-disabled" }, + { SM_SERVICE_DOMAIN_EVENT_WAIT_EXPIRED, "wait-expired" }, +}; + +static SmValueStrMappingT +_sm_service_domain_interface_event_mappings[SM_SERVICE_DOMAIN_INTERFACE_EVENT_MAX] = +{ + { SM_SERVICE_DOMAIN_INTERFACE_EVENT_NIL, "nil" }, + { SM_SERVICE_DOMAIN_INTERFACE_EVENT_UNKNOWN, "unknown" }, + { SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_ENABLED, "node-enabled" }, + { SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_DISABLED, "node-disabled" }, + { SM_SERVICE_DOMAIN_INTERFACE_EVENT_ENABLED, "enabled" }, + { SM_SERVICE_DOMAIN_INTERFACE_EVENT_DISABLED, "disabled" }, + { SM_SERVICE_DOMAIN_INTERFACE_EVENT_AUDIT, "audit" }, + { SM_SERVICE_DOMAIN_INTERFACE_EVENT_NOT_IN_USE, "not-in-use" } +}; + +static SmValueStrMappingT +_sm_service_domain_neighbor_state_mappings[SM_SERVICE_DOMAIN_NEIGHBOR_STATE_MAX] = +{ + { SM_SERVICE_DOMAIN_NEIGHBOR_STATE_NIL, "nil" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN, "down" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START, "exchange-start" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE, "exchange" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL, "full" }, +}; + +static SmValueStrMappingT +_sm_service_domain_neighbor_event_mappings[SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_MAX] = +{ + { SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_NIL, "nil" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_UNKNOWN, "unknown" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_HELLO_MSG, "hello-message" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_MSG, "exchange-start-message" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_TIMER, "exchange-start-timer" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_MSG, "exchange-message" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_TIMEOUT, "exchange-timeout" }, + { SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DOWN, "down" }, +}; + +static SmValueStrMappingT +_sm_service_domain_member_redundancy_model_mappings[SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_MAX] = +{ + { SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_NIL, "nil" }, + { SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_UNKNOWN, "unknown" }, + { SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_NONE, "none" }, + { SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N, "N" }, + { SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_PLUS_M, "N + M" }, + { SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_TO_1, "N to 1" }, + { SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_TO_N, "N to N" }, +}; + +static SmValueStrMappingT +_sm_service_domain_split_brain_recovery_mappings[SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_MAX] = +{ + { SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_NIL, "nil" }, + { SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_UNKNOWN, "unknown" }, + { SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_DISABLE_ALL_ACTIVE, "disable-all-active" }, + { SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_SELECT_BEST_ACTIVE, "select-best-active" }, +}; + +static SmValueStrMappingT +_sm_service_group_action_mappings[SM_SERVICE_GROUP_ACTION_MAX] = +{ + { SM_SERVICE_GROUP_ACTION_NIL, "nil" }, + { SM_SERVICE_GROUP_ACTION_UNKNOWN, "unknown" }, + { SM_SERVICE_GROUP_ACTION_DISABLE, "disable" }, + { SM_SERVICE_GROUP_ACTION_GO_ACTIVE, "go-active" }, + { SM_SERVICE_GROUP_ACTION_GO_STANDBY, "go-standby" }, + { SM_SERVICE_GROUP_ACTION_AUDIT, "audit" }, + { SM_SERVICE_GROUP_ACTION_RECOVER, "recover" }, +}; + +static SmValueStrMappingT +_sm_service_group_state_mappings[SM_SERVICE_GROUP_STATE_MAX] = +{ + { SM_SERVICE_GROUP_STATE_NIL, "nil" }, + { SM_SERVICE_GROUP_STATE_NA, "not-applicable" }, + { SM_SERVICE_GROUP_STATE_INITIAL, "initial" }, + { SM_SERVICE_GROUP_STATE_UNKNOWN, "unknown" }, + { SM_SERVICE_GROUP_STATE_STANDBY, "standby" }, + { SM_SERVICE_GROUP_STATE_GO_STANDBY, "go-standby" }, + { SM_SERVICE_GROUP_STATE_GO_ACTIVE, "go-active" }, + { SM_SERVICE_GROUP_STATE_ACTIVE, "active" }, + { SM_SERVICE_GROUP_STATE_DISABLING, "disabling" }, + { SM_SERVICE_GROUP_STATE_DISABLED, "disabled" }, + { SM_SERVICE_GROUP_STATE_SHUTDOWN, "shutdown" }, +}; + +static SmValueStrMappingT +_sm_service_group_event_mappings[SM_SERVICE_GROUP_EVENT_MAX] = +{ + { SM_SERVICE_GROUP_EVENT_NIL, "nil" }, + { SM_SERVICE_GROUP_EVENT_UNKNOWN, "unknown" }, + { SM_SERVICE_GROUP_EVENT_GO_ACTIVE, "go-active" }, + { SM_SERVICE_GROUP_EVENT_GO_STANDBY, "go-standby" }, + { SM_SERVICE_GROUP_EVENT_DISABLE, "disable" }, + { SM_SERVICE_GROUP_EVENT_AUDIT, "audit" }, + { SM_SERVICE_GROUP_EVENT_SERVICE_SCN, "service-state-change" }, + { SM_SERVICE_GROUP_EVENT_SHUTDOWN, "shutdown" }, + { SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS, "notification-success" }, + { SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED, "notification-failed" }, + { SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT, "notification-timeout" }, +}; + +static SmValueStrMappingT +_sm_service_group_status_mappings[SM_SERVICE_GROUP_STATUS_MAX] = +{ + { SM_SERVICE_GROUP_STATUS_NIL, "nil" }, + { SM_SERVICE_GROUP_STATUS_UNKNOWN, "unknown" }, + { SM_SERVICE_GROUP_STATUS_NONE, "" }, + { SM_SERVICE_GROUP_STATUS_WARN, "warn" }, + { SM_SERVICE_GROUP_STATUS_DEGRADED, "degraded" }, + { SM_SERVICE_GROUP_STATUS_FAILED, "failed" }, +}; + +static SmValueStrMappingT +_sm_service_group_condition_mappings[SM_SERVICE_GROUP_CONDITION_MAX] = +{ + { SM_SERVICE_GROUP_CONDITION_NIL, "nil" }, + { SM_SERVICE_GROUP_CONDITION_UNKNOWN, "unknown" }, + { SM_SERVICE_GROUP_CONDITION_NONE, "" }, + { SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT, "data-inconsistent" }, + { SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED, "data-outdated" }, + { SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT, "data-consistent" }, + { SM_SERVICE_GROUP_CONDITION_DATA_SYNC, "data-syncing" }, + { SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE, "data-standalone" }, + { SM_SERVICE_GROUP_CONDITION_RECOVERY_FAILURE, "recovery-failure" }, + { SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE, "action-failure" }, + { SM_SERVICE_GROUP_CONDITION_FATAL_FAILURE, "fatal-failure" }, +}; + +static SmValueStrMappingT +_sm_service_group_notification_mappings[SM_SERVICE_GROUP_NOTIFICATION_MAX] = +{ + { SM_SERVICE_GROUP_NOTIFICATION_NIL, "nil" }, + { SM_SERVICE_GROUP_NOTIFICATION_UNKNOWN, "unknown" }, + { SM_SERVICE_GROUP_NOTIFICATION_STANDBY, "standby" }, + { SM_SERVICE_GROUP_NOTIFICATION_GO_STANDBY, "go-standby" }, + { SM_SERVICE_GROUP_NOTIFICATION_GO_ACTIVE, "go-active" }, + { SM_SERVICE_GROUP_NOTIFICATION_ACTIVE, "active" }, + { SM_SERVICE_GROUP_NOTIFICATION_DISABLING, "disabling" }, + { SM_SERVICE_GROUP_NOTIFICATION_DISABLED, "disabled" }, + { SM_SERVICE_GROUP_NOTIFICATION_SHUTDOWN, "shutdown" }, +}; + +static SmValueStrMappingT +_sm_service_admin_state_mappings[SM_SERVICE_ADMIN_STATE_MAX] = +{ + { SM_SERVICE_ADMIN_STATE_NIL, "nil" }, + { SM_SERVICE_ADMIN_STATE_NA, "not-applicable" }, + { SM_SERVICE_ADMIN_STATE_LOCKED, "initial" }, + { SM_SERVICE_ADMIN_STATE_UNLOCKED, "unknown" }, +}; + +static SmValueStrMappingT +_sm_service_state_mappings[SM_SERVICE_STATE_MAX] = +{ + { SM_SERVICE_STATE_NIL, "nil" }, + { SM_SERVICE_STATE_NA, "not-applicable" }, + { SM_SERVICE_STATE_INITIAL, "initial" }, + { SM_SERVICE_STATE_UNKNOWN, "unknown" }, + { SM_SERVICE_STATE_ENABLED_STANDBY, "enabled-standby" }, + { SM_SERVICE_STATE_ENABLED_GO_STANDBY, "enabled-go-standby" }, + { SM_SERVICE_STATE_ENABLED_GO_ACTIVE, "enabled-go-active" }, + { SM_SERVICE_STATE_ENABLED_ACTIVE, "enabled-active" }, + { SM_SERVICE_STATE_ENABLING, "enabling" }, + { SM_SERVICE_STATE_ENABLING_THROTTLE, "enabling-throttle" }, + { SM_SERVICE_STATE_DISABLING, "disabling" }, + { SM_SERVICE_STATE_DISABLED, "disabled" }, + { SM_SERVICE_STATE_SHUTDOWN, "shutdown" }, +}; + +static SmValueStrMappingT +_sm_service_event_mappings[SM_SERVICE_EVENT_MAX] = +{ + { SM_SERVICE_EVENT_NIL, "nil" }, + { SM_SERVICE_EVENT_UNKNOWN, "unknown" }, + { SM_SERVICE_EVENT_ENABLE_THROTTLE, "enable-throttle" }, + { SM_SERVICE_EVENT_ENABLE, "enable" }, + { SM_SERVICE_EVENT_ENABLE_SUCCESS, "enable-success" }, + { SM_SERVICE_EVENT_ENABLE_FAILED, "enable-failed" }, + { SM_SERVICE_EVENT_ENABLE_TIMEOUT, "enable-timeout" }, + { SM_SERVICE_EVENT_GO_ACTIVE, "go-active" }, + { SM_SERVICE_EVENT_GO_ACTIVE_SUCCESS, "go-active-success" }, + { SM_SERVICE_EVENT_GO_ACTIVE_FAILED, "go-active-failed" }, + { SM_SERVICE_EVENT_GO_ACTIVE_TIMEOUT, "go-active-timeout" }, + { SM_SERVICE_EVENT_GO_STANDBY, "go-standby" }, + { SM_SERVICE_EVENT_GO_STANDBY_SUCCESS, "go-standby-success" }, + { SM_SERVICE_EVENT_GO_STANDBY_FAILED, "go-standby-failed" }, + { SM_SERVICE_EVENT_GO_STANDBY_TIMEOUT, "go-standby-timeout" }, + { SM_SERVICE_EVENT_DISABLE, "disable" }, + { SM_SERVICE_EVENT_DISABLE_SUCCESS, "disable-success" }, + { SM_SERVICE_EVENT_DISABLE_FAILED, "disable-failed" }, + { SM_SERVICE_EVENT_DISABLE_TIMEOUT, "disable-timeout" }, + { SM_SERVICE_EVENT_AUDIT, "audit" }, + { SM_SERVICE_EVENT_AUDIT_SUCCESS, "audit-success" }, + { SM_SERVICE_EVENT_AUDIT_FAILED, "audit-failed" }, + { SM_SERVICE_EVENT_AUDIT_TIMEOUT, "audit-timeout" }, + { SM_SERVICE_EVENT_AUDIT_MISMATCH, "audit-mismatch" }, + { SM_SERVICE_EVENT_HEARTBEAT_OKAY, "heartbeat-okay" }, + { SM_SERVICE_EVENT_HEARTBEAT_WARN, "heartbeat-warn" }, + { SM_SERVICE_EVENT_HEARTBEAT_DEGRADE, "heartbeat-degrade" }, + { SM_SERVICE_EVENT_HEARTBEAT_FAIL, "heartbeat-fail" }, + { SM_SERVICE_EVENT_PROCESS_FAILURE, "process-failure" }, + { SM_SERVICE_EVENT_SHUTDOWN, "shutdown" }, +}; + +static SmValueStrMappingT +_sm_service_status_mappings[SM_SERVICE_STATUS_MAX] = +{ + { SM_SERVICE_STATUS_NIL, "nil" }, + { SM_SERVICE_STATUS_UNKNOWN, "unknown" }, + { SM_SERVICE_STATUS_NONE, "" }, + { SM_SERVICE_STATUS_WARN, "warn" }, + { SM_SERVICE_STATUS_DEGRADED, "degraded" }, + { SM_SERVICE_STATUS_FAILED, "failed" }, +}; + +static SmValueStrMappingT +_sm_service_condition_mappings[SM_SERVICE_CONDITION_MAX] = +{ + { SM_SERVICE_CONDITION_NIL, "nil" }, + { SM_SERVICE_CONDITION_UNKNOWN, "unknown" }, + { SM_SERVICE_CONDITION_NONE, "" }, + // Degraded Conditions. + { SM_SERVICE_CONDITION_DATA_INCONSISTENT, "data-inconsistent" }, + { SM_SERVICE_CONDITION_DATA_OUTDATED, "data-outdated" }, + { SM_SERVICE_CONDITION_DATA_CONSISTENT, "data-consistent" }, + { SM_SERVICE_CONDITION_DATA_SYNC, "data-syncing" }, + { SM_SERVICE_CONDITION_DATA_STANDALONE, "data-standalone" }, + // Failed Conditions. + { SM_SERVICE_CONDITION_RECOVERY_FAILURE, "recovery-failure" }, + { SM_SERVICE_CONDITION_ACTION_FAILURE, "action-failure" }, + { SM_SERVICE_CONDITION_FATAL_FAILURE, "fatal-failure" }, +}; + +static SmValueStrMappingT +_sm_service_severity_mappings[SM_SERVICE_SEVERITY_MAX] = +{ + { SM_SERVICE_SEVERITY_NIL, "nil" }, + { SM_SERVICE_SEVERITY_UNKNOWN, "unknown" }, + { SM_SERVICE_SEVERITY_NONE, "none" }, + { SM_SERVICE_SEVERITY_MINOR, "minor" }, + { SM_SERVICE_SEVERITY_MAJOR, "major" }, + { SM_SERVICE_SEVERITY_CRITICAL, "critical" }, +}; + +static SmValueStrMappingT +_sm_service_heartbeat_type_mappings[SM_SERVICE_HEARTBEAT_TYPE_MAX] = +{ + { SM_SERVICE_HEARTBEAT_TYPE_NIL, "nil" }, + { SM_SERVICE_HEARTBEAT_TYPE_UNKNOWN, "unknown" }, + { SM_SERVICE_HEARTBEAT_TYPE_UNIX, "unix" }, + { SM_SERVICE_HEARTBEAT_TYPE_UDP, "udp" }, +}; + +static SmValueStrMappingT +_sm_service_heartbeat_state_mappings[SM_SERVICE_HEARTBEAT_STATE_MAX] = +{ + { SM_SERVICE_HEARTBEAT_STATE_NIL, "nil" }, + { SM_SERVICE_HEARTBEAT_STATE_UNKNOWN, "unknown" }, + { SM_SERVICE_HEARTBEAT_STATE_STARTED, "started" }, + { SM_SERVICE_HEARTBEAT_STATE_STOPPED, "stopped" }, +}; + +static SmValueStrMappingT +_sm_service_dependency_type_mappings[SM_SERVICE_DEPENDENCY_TYPE_MAX] = +{ + { SM_SERVICE_DEPENDENCY_TYPE_NIL, "nil" }, + { SM_SERVICE_DEPENDENCY_TYPE_UNKNOWN, "unknown" }, + { SM_SERVICE_DEPENDENCY_TYPE_ACTION, "action" }, + { SM_SERVICE_DEPENDENCY_TYPE_STATE, "state" }, +}; + +static SmValueStrMappingT +_sm_service_action_mappings[SM_SERVICE_ACTION_MAX] = +{ + { SM_SERVICE_ACTION_NIL, "nil" }, + { SM_SERVICE_ACTION_NA, "not-applicable" }, + { SM_SERVICE_ACTION_UNKNOWN, "unknown" }, + { SM_SERVICE_ACTION_NONE, "none" }, + { SM_SERVICE_ACTION_ENABLE, "enable" }, + { SM_SERVICE_ACTION_DISABLE, "disable" }, + { SM_SERVICE_ACTION_GO_ACTIVE, "go-active" }, + { SM_SERVICE_ACTION_GO_STANDBY, "go-standby" }, + { SM_SERVICE_ACTION_AUDIT_ENABLED, "audit-enabled" }, + { SM_SERVICE_ACTION_AUDIT_DISABLED, "audit-disabled" }, +}; + +static SmValueStrMappingT +_sm_service_action_result_mappings[SM_SERVICE_ACTION_RESULT_MAX] = +{ + { SM_SERVICE_ACTION_RESULT_NIL, "nil" }, + { SM_SERVICE_ACTION_RESULT_UNKNOWN, "unknown" }, + { SM_SERVICE_ACTION_RESULT_SUCCESS, "success" }, + { SM_SERVICE_ACTION_RESULT_FATAL, "fatal" }, + { SM_SERVICE_ACTION_RESULT_FAILED, "failed" }, + { SM_SERVICE_ACTION_RESULT_TIMEOUT, "timeout" }, +}; + +static SmValueStrMappingT +_sm_service_domain_scheduling_state_mappings[SM_SERVICE_DOMAIN_SCHEDULING_STATE_MAX] = +{ + { SM_SERVICE_DOMAIN_SCHEDULING_STATE_NIL, "nil" }, + { SM_SERVICE_DOMAIN_SCHEDULING_STATE_UNKNOWN, "unknown" }, + { SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE, "none" }, + { SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT, "swact" }, + { SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE, "swact-force" }, + { SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE, "disable" }, + { SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE_FORCE, "disable-force" }, +}; + +static SmValueStrMappingT +_sm_service_domain_scheduling_list_mappings[] = +{ + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_NIL, "nil" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE, "active" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE, "go-active" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY, "go-standby" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY, "standby" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING, "disabling" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED, "disabled" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED, "failed" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL, "fatal" }, + { SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE, "unavailable" }, +}; + +static SmValueStrMappingT _sm_error_mappings[SM_ERROR_MAX] = +{ + { SM_OKAY, "OKAY" }, + { SM_NOT_FOUND, "NOT_FOUND" }, + { SM_NO_MSG, "NO_MSG" }, + { SM_NOT_IMPLEMENTED, "NOT_IMPLEMENTED" }, + { SM_FAILED, "FAILED" }, +}; + +typedef struct +{ + SmNodeAdminStateT admin_state; + SmNodeReadyStateT ready_state; + char str[SM_VALUE_STR_MAPPING_MAX_CHAR]; +} SmNodeStateStrMappingT; + +static SmNodeStateStrMappingT +_sm_node_state_mappings[SM_NODE_ADMIN_STATE_MAX*SM_NODE_READY_STATE_MAX] = +{ + { SM_NODE_ADMIN_STATE_NIL, SM_NODE_READY_STATE_NIL, "nil-nil" }, + { SM_NODE_ADMIN_STATE_NIL, SM_NODE_READY_STATE_UNKNOWN, "nil-unknown" }, + { SM_NODE_ADMIN_STATE_NIL, SM_NODE_READY_STATE_ENABLED, "nil-enabled" }, + { SM_NODE_ADMIN_STATE_NIL, SM_NODE_READY_STATE_DISABLED, "nil-disabled" }, + { SM_NODE_ADMIN_STATE_UNKNOWN, SM_NODE_READY_STATE_NIL, "unknown-nil" }, + { SM_NODE_ADMIN_STATE_UNKNOWN, SM_NODE_READY_STATE_UNKNOWN, "unknown-unknown" }, + { SM_NODE_ADMIN_STATE_UNKNOWN, SM_NODE_READY_STATE_ENABLED, "unknown-enabled" }, + { SM_NODE_ADMIN_STATE_UNKNOWN, SM_NODE_READY_STATE_DISABLED, "unknown-disabled" }, + { SM_NODE_ADMIN_STATE_LOCKED, SM_NODE_READY_STATE_NIL, "locked-nil" }, + { SM_NODE_ADMIN_STATE_LOCKED, SM_NODE_READY_STATE_UNKNOWN, "locked-unknown" }, + { SM_NODE_ADMIN_STATE_LOCKED, SM_NODE_READY_STATE_ENABLED, "locked-enabled" }, + { SM_NODE_ADMIN_STATE_LOCKED, SM_NODE_READY_STATE_DISABLED, "locked-disabled" }, + { SM_NODE_ADMIN_STATE_UNLOCKED, SM_NODE_READY_STATE_NIL, "unlocked-nil" }, + { SM_NODE_ADMIN_STATE_UNLOCKED, SM_NODE_READY_STATE_UNKNOWN, "unlocked-unknown" }, + { SM_NODE_ADMIN_STATE_UNLOCKED, SM_NODE_READY_STATE_ENABLED, "unlocked-enabled" }, + { SM_NODE_ADMIN_STATE_UNLOCKED, SM_NODE_READY_STATE_DISABLED, "unlocked-disabled" }, +}; + +static SmValueStrMappingT _sm_system_mode_mapping[SM_SYSTEM_MODE_MAX] = +{ + { SM_SYSTEM_MODE_UNKNOWN, "UNKNOWN" }, + { SM_SYSTEM_MODE_STANDARD, "standard" }, + { SM_SYSTEM_MODE_CPE_DUPLEX, "duplex" }, + { SM_SYSTEM_MODE_CPE_DUPLEX_DC, "duplex-direct" }, + { SM_SYSTEM_MODE_CPE_SIMPLEX, "simplex" }, +}; + +static SmValueStrMappingT + _sm_node_schedule_state_mappings[SM_NODE_STATE_MAX] = +{ + { SM_NODE_STATE_UNKNOWN, "unknown" }, + { SM_NODE_STATE_ACTIVE, "active" }, + { SM_NODE_STATE_STANDBY, "standby" }, + { SM_NODE_STATE_INIT, "init" }, + { SM_NODE_STATE_FAILED, "failed" } +}; + +// **************************************************************************** +// Types - Mapping Get String +// ========================== +static const char* sm_mapping_get_str( SmValueStrMappingT mappings[], + unsigned int num_mappings, int value ) +{ + unsigned int map_i; + for( map_i=0; num_mappings > map_i; ++map_i ) + { + if( value == mappings[map_i].value ) + { + return( &(mappings[map_i].str[0]) ); + } + } + + return( "???" ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Mapping Get Value +// ========================= +static int sm_mapping_get_value( SmValueStrMappingT mappings[], + unsigned int num_mappings, const char* str ) +{ + unsigned int map_i; + for( map_i=0; num_mappings > map_i; ++map_i ) + { + if( 0 == strcmp( &(mappings[map_i].str[0]), str ) ) + { + return( mappings[map_i].value ); + } + } + + return( 0 ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Administrative State Value +// ======================================= +SmNodeAdminStateT sm_node_admin_state_value( const char* state_str ) +{ + return( (SmNodeAdminStateT) + sm_mapping_get_value( _sm_node_admin_state_mappings, + SM_NODE_ADMIN_STATE_MAX, + state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Administrative State String +// ======================================== +const char* sm_node_admin_state_str( SmNodeAdminStateT state ) +{ + return( sm_mapping_get_str( _sm_node_admin_state_mappings, + SM_NODE_ADMIN_STATE_MAX, + state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Operational State Value +// ==================================== +SmNodeOperationalStateT sm_node_oper_state_value( const char* state_str ) +{ + return( (SmNodeOperationalStateT) + sm_mapping_get_value( _sm_node_oper_state_mappings, + SM_NODE_OPERATIONAL_STATE_MAX, + state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Operational State String +// ===================================== +const char* sm_node_oper_state_str( SmNodeOperationalStateT state ) +{ + return( sm_mapping_get_str( _sm_node_oper_state_mappings, + SM_NODE_OPERATIONAL_STATE_MAX, + state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Availability Status Value +// ====================================== +SmNodeAvailStatusT sm_node_avail_status_value( const char* status_str ) +{ + return( (SmNodeAvailStatusT) + sm_mapping_get_value( _sm_node_avail_status_mappings, + SM_NODE_AVAIL_STATUS_MAX, + status_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Availability Status String +// ======================================= +const char* sm_node_avail_status_str( SmNodeAvailStatusT status ) +{ + return( sm_mapping_get_str( _sm_node_avail_status_mappings, + SM_NODE_AVAIL_STATUS_MAX, + status ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Ready State Value +// ============================== +SmNodeReadyStateT sm_node_ready_state_value( const char* state_str ) +{ + return( (SmNodeReadyStateT) + sm_mapping_get_value( _sm_node_ready_state_mappings, + SM_NODE_READY_STATE_MAX, + state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Ready State String +// =============================== +const char* sm_node_ready_state_str( SmNodeReadyStateT state ) +{ + return( sm_mapping_get_str( _sm_node_ready_state_mappings, + SM_NODE_READY_STATE_MAX, + state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node State String +// ========================= +const char* sm_node_state_str( SmNodeAdminStateT admin_state, + SmNodeReadyStateT ready_state ) +{ + unsigned int map_i; + for( map_i=0; (SM_NODE_ADMIN_STATE_MAX*SM_NODE_READY_STATE_MAX) > map_i; + ++map_i ) + { + if(( admin_state == _sm_node_state_mappings[map_i].admin_state )&& + ( ready_state == _sm_node_state_mappings[map_i].ready_state )) + { + return( &(_sm_node_state_mappings[map_i].str[0]) ); + } + } + + return( "???" ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Event Value +// ======================== +SmNodeEventT sm_node_event_value( const char* event_str ) +{ + return( (SmNodeEventT) + sm_mapping_get_value( _sm_node_event_mappings, + SM_NODE_EVENT_MAX, event_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Node Event String +// ========================= +const char* sm_node_event_str( SmNodeEventT event ) +{ + return( sm_mapping_get_str( _sm_node_event_mappings, + SM_NODE_EVENT_MAX, event ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Interface State Value +// ============================= +SmInterfaceStateT sm_interface_state_value( const char* state_str ) +{ + return( (SmInterfaceStateT) + sm_mapping_get_value( _sm_interface_state_mappings, + SM_INTERFACE_STATE_MAX, state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Interface State String +// ============================== +const char* sm_interface_state_str( SmInterfaceStateT state ) +{ + return( sm_mapping_get_str( _sm_interface_state_mappings, + SM_INTERFACE_STATE_MAX, state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Network Type Value +// ========================== +SmNetworkTypeT sm_network_type_value( const char* network_type_str ) +{ + return( (SmNetworkTypeT) + sm_mapping_get_value( _sm_network_type_mappings, + SM_NETWORK_TYPE_MAX, network_type_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Network Type String +// =========================== +const char* sm_network_type_str( SmNetworkTypeT network_type ) +{ + return( sm_mapping_get_str( _sm_network_type_mappings, + SM_NETWORK_TYPE_MAX, network_type ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Path Type Value +// ======================= +SmPathTypeT sm_path_type_value( const char* path_type_str ) +{ + return( (SmPathTypeT) + sm_mapping_get_value( _sm_path_type_mappings, + SM_PATH_TYPE_MAX, path_type_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Path Type String +// ======================== +const char* sm_path_type_str( SmPathTypeT path_type ) +{ + return( sm_mapping_get_str( _sm_path_type_mappings, + SM_PATH_TYPE_MAX, path_type ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Authentication Type Value +// ================================= +SmAuthTypeT sm_auth_type_value( const char* auth_type_str ) +{ + return( (SmAuthTypeT) + sm_mapping_get_value( _sm_auth_type_mappings, + SM_AUTH_TYPE_MAX, auth_type_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Authentication Type String +// ================================== +const char* sm_auth_type_str( SmAuthTypeT auth_type ) +{ + return( sm_mapping_get_str( _sm_auth_type_mappings, + SM_AUTH_TYPE_MAX, auth_type ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Orchestration Type Value +// ================================ +SmOrchestrationTypeT sm_orchestration_type_value( + const char* orchestration_type_str ) +{ + return( (SmOrchestrationTypeT) + sm_mapping_get_value( _sm_orchestration_type_mappings, + SM_ORCHESTRATION_TYPE_MAX, + orchestration_type_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Orchestration Type String +// ================================= +const char* sm_orchestration_type_str( SmOrchestrationTypeT orchestration_type ) +{ + return( sm_mapping_get_str( _sm_orchestration_type_mappings, + SM_ORCHESTRATION_TYPE_MAX, + orchestration_type ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Designation Type Value +// ============================== +SmDesignationTypeT sm_designation_type_value( + const char* designation_type_str ) +{ + return( (SmDesignationTypeT) + sm_mapping_get_value( _sm_designation_type_mappings, + SM_DESIGNATION_TYPE_MAX, + designation_type_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Designation Type String +// =============================== +const char* sm_designation_type_str( SmDesignationTypeT designation_type ) +{ + return( sm_mapping_get_str( _sm_designation_type_mappings, + SM_DESIGNATION_TYPE_MAX, designation_type ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain State Value +// ================================== +SmServiceDomainStateT sm_service_domain_state_value( const char* state_str ) +{ + return( (SmServiceDomainStateT) + sm_mapping_get_value( _sm_service_domain_state_mappings, + SM_SERVICE_DOMAIN_STATE_MAX, state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain State String +// =================================== +const char* sm_service_domain_state_str( SmServiceDomainStateT state ) +{ + return( sm_mapping_get_str( _sm_service_domain_state_mappings, + SM_SERVICE_DOMAIN_STATE_MAX, state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Event Value +// ================================== +SmServiceDomainEventT sm_service_domain_event_value( const char* event_str ) +{ + return( (SmServiceDomainEventT) + sm_mapping_get_value( _sm_service_domain_event_mappings, + SM_SERVICE_DOMAIN_EVENT_MAX, event_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Event String +// =================================== +const char* sm_service_domain_event_str( SmServiceDomainEventT event ) +{ + return( sm_mapping_get_str( _sm_service_domain_event_mappings, + SM_SERVICE_DOMAIN_EVENT_MAX, event ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Scheduling State Value +// ============================================= +SmServiceDomainSchedulingStateT sm_service_domain_scheduling_state_value( + const char* sched_state_str ) +{ + return( (SmServiceDomainSchedulingStateT) + sm_mapping_get_value( _sm_service_domain_scheduling_state_mappings, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_MAX, + sched_state_str ) ); +} +// **************************************************************************** + +// *************************************************************************** +// Types - Service Domain Scheduling State String +// ============================================== +const char* sm_service_domain_scheduling_state_str( + SmServiceDomainSchedulingStateT sched_state ) +{ + return( sm_mapping_get_str( _sm_service_domain_scheduling_state_mappings, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_MAX, + sched_state ) ); +} +// *************************************************************************** + +// **************************************************************************** +// Types - Service Domain Scheduling List Value +// ============================================ +SmServiceDomainSchedulingListT sm_service_domain_scheduling_list_value( + const char* sched_list_str ) +{ + return( (SmServiceDomainSchedulingListT) + sm_mapping_get_value( _sm_service_domain_scheduling_list_mappings, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_MAX, + sched_list_str ) ); +} +// **************************************************************************** + +// *************************************************************************** +// Types - Service Domain Scheduling List String +// ============================================= +const char* sm_service_domain_scheduling_list_str( + SmServiceDomainSchedulingListT sched_list ) +{ + return( sm_mapping_get_str( _sm_service_domain_scheduling_list_mappings, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_MAX, + sched_list ) ); +} +// *************************************************************************** + +// **************************************************************************** +// Types - Service Domain Interface Event Value +// ============================================ +SmServiceDomainInterfaceEventT sm_service_domain_interface_event_value( + const char* event_str ) +{ + return( (SmServiceDomainInterfaceEventT) + sm_mapping_get_value( _sm_service_domain_interface_event_mappings, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_MAX, + event_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Interface Event String +// ============================================= +const char* sm_service_domain_interface_event_str( + SmServiceDomainInterfaceEventT event ) +{ + return( sm_mapping_get_str( _sm_service_domain_interface_event_mappings, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_MAX, + event ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Neighbor State Value +// =========================================== +SmServiceDomainNeighborStateT sm_service_domain_neighbor_state_value( + const char* neighbor_state_str ) +{ + return( (SmServiceDomainNeighborStateT) + sm_mapping_get_value( _sm_service_domain_neighbor_state_mappings, + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_MAX, + neighbor_state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Neighbor State String +// ============================================ +const char* sm_service_domain_neighbor_state_str( + SmServiceDomainNeighborStateT neighbor_state ) +{ + return( sm_mapping_get_str( _sm_service_domain_neighbor_state_mappings, + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_MAX, + neighbor_state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Neighbor Event Value +// =========================================== +SmServiceDomainNeighborEventT sm_service_domainneighbor_event_value( + const char* neighbor_event_str ) +{ + return( (SmServiceDomainNeighborEventT) + sm_mapping_get_value( _sm_service_domain_neighbor_event_mappings, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_MAX, + neighbor_event_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Neighbor Event String +// ============================================ +const char* sm_service_domain_neighbor_event_str( + SmServiceDomainNeighborEventT neighbor_event ) +{ + return( sm_mapping_get_str( _sm_service_domain_neighbor_event_mappings, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_MAX, + neighbor_event ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Member Redundancy Model Value +// ==================================================== +SmServiceDomainMemberRedundancyModelT sm_service_domain_member_redundancy_model_value( + const char* model_str ) +{ + return( (SmServiceDomainMemberRedundancyModelT) + sm_mapping_get_value( _sm_service_domain_member_redundancy_model_mappings, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_MAX, + model_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Member Redundancy Model String +// ===================================================== +const char* sm_service_domain_member_redundancy_model_str( + SmServiceDomainMemberRedundancyModelT model ) +{ + return( sm_mapping_get_str( _sm_service_domain_member_redundancy_model_mappings, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_MAX, + model ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Split Brain Recovery Value +// ================================================= +SmServiceDomainSplitBrainRecoveryT sm_service_domain_split_brain_recovery_value( + const char* recovery_str ) +{ + return( (SmServiceDomainSplitBrainRecoveryT) + sm_mapping_get_value( _sm_service_domain_split_brain_recovery_mappings, + SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_MAX, + recovery_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Split Brain Recovery String +// ================================================== +const char* sm_service_domain_split_brain_recovery_str( + SmServiceDomainSplitBrainRecoveryT recovery ) +{ + return( sm_mapping_get_str( _sm_service_domain_split_brain_recovery_mappings, + SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_MAX, + recovery ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Action Value +// ================================== +SmServiceGroupActionT sm_service_group_action_value( + const char* action_str ) +{ + return( (SmServiceGroupActionT) + sm_mapping_get_value( _sm_service_group_action_mappings, + SM_SERVICE_GROUP_ACTION_MAX, action_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Action String +// =================================== +const char* sm_service_group_action_str( SmServiceGroupActionT action ) +{ + return( sm_mapping_get_str( _sm_service_group_action_mappings, + SM_SERVICE_GROUP_ACTION_MAX, action ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group State Value +// ================================= +SmServiceGroupStateT sm_service_group_state_value( + const char* state_str ) +{ + return( (SmServiceGroupStateT) + sm_mapping_get_value( _sm_service_group_state_mappings, + SM_SERVICE_GROUP_STATE_MAX, state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group State String +// ================================== +const char* sm_service_group_state_str( SmServiceGroupStateT state ) +{ + return( sm_mapping_get_str( _sm_service_group_state_mappings, + SM_SERVICE_GROUP_STATE_MAX, state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group State Lesser Value +// ======================================== +SmServiceGroupStateT sm_service_group_state_lesser( + SmServiceGroupStateT state_a, SmServiceGroupStateT state_b ) +{ + SmServiceGroupStateT lesser_state = SM_SERVICE_GROUP_STATE_UNKNOWN; + + switch( state_a ) + { + case SM_SERVICE_GROUP_STATE_NIL: + lesser_state = state_b; + break; + + case SM_SERVICE_GROUP_STATE_INITIAL: + if( SM_SERVICE_GROUP_STATE_NIL == state_b ) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_GROUP_STATE_UNKNOWN: + if(( SM_SERVICE_GROUP_STATE_NIL == state_b )|| + ( SM_SERVICE_GROUP_STATE_INITIAL == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLED: + if(( SM_SERVICE_GROUP_STATE_NIL == state_b )|| + ( SM_SERVICE_GROUP_STATE_INITIAL == state_b )|| + ( SM_SERVICE_GROUP_STATE_UNKNOWN == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_GROUP_STATE_DISABLING: + if(( SM_SERVICE_GROUP_STATE_NIL == state_b )|| + ( SM_SERVICE_GROUP_STATE_INITIAL == state_b )|| + ( SM_SERVICE_GROUP_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLED == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_GROUP_STATE_STANDBY: + if(( SM_SERVICE_GROUP_STATE_NIL == state_b )|| + ( SM_SERVICE_GROUP_STATE_INITIAL == state_b )|| + ( SM_SERVICE_GROUP_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLING == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLED == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_GROUP_STATE_GO_ACTIVE: + if(( SM_SERVICE_GROUP_STATE_NIL == state_b )|| + ( SM_SERVICE_GROUP_STATE_INITIAL == state_b )|| + ( SM_SERVICE_GROUP_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLING == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLED == state_b )|| + ( SM_SERVICE_GROUP_STATE_STANDBY == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_GROUP_STATE_GO_STANDBY: + if(( SM_SERVICE_GROUP_STATE_NIL == state_b )|| + ( SM_SERVICE_GROUP_STATE_INITIAL == state_b )|| + ( SM_SERVICE_GROUP_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLING == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLED == state_b )|| + ( SM_SERVICE_GROUP_STATE_STANDBY == state_b )|| + ( SM_SERVICE_GROUP_STATE_GO_ACTIVE == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_GROUP_STATE_ACTIVE: + if(( SM_SERVICE_GROUP_STATE_NIL == state_b )|| + ( SM_SERVICE_GROUP_STATE_INITIAL == state_b )|| + ( SM_SERVICE_GROUP_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLING == state_b )|| + ( SM_SERVICE_GROUP_STATE_DISABLED == state_b )|| + ( SM_SERVICE_GROUP_STATE_STANDBY == state_b )|| + ( SM_SERVICE_GROUP_STATE_GO_ACTIVE == state_b )|| + ( SM_SERVICE_GROUP_STATE_GO_STANDBY == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + default: + DPRINTFE( "Unknown state (%s) given.", + sm_service_group_state_str( state_a ) ); + break; + } + + return( lesser_state ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Event Value +// ================================= +SmServiceGroupEventT sm_service_group_event_value( const char* event_str ) +{ + return( (SmServiceGroupEventT) + sm_mapping_get_value( _sm_service_group_event_mappings, + SM_SERVICE_GROUP_EVENT_MAX, event_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Event String +// ================================== +const char* sm_service_group_event_str( SmServiceGroupEventT event ) +{ + return( sm_mapping_get_str( _sm_service_group_event_mappings, + SM_SERVICE_GROUP_EVENT_MAX, event ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Status Value +// ================================== +SmServiceGroupStatusT sm_service_group_status_value( + const char* status_str ) +{ + return( (SmServiceGroupStatusT) + sm_mapping_get_value( _sm_service_group_status_mappings, + SM_SERVICE_GROUP_STATUS_MAX, status_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Status String +// =================================== +const char* sm_service_group_status_str( SmServiceGroupStatusT status ) +{ + return( sm_mapping_get_str( _sm_service_group_status_mappings, + SM_SERVICE_GROUP_STATUS_MAX, status ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Condition Value +// ===================================== +SmServiceGroupConditionT sm_service_group_condition_value( + const char* condition_str ) +{ + return( (SmServiceGroupConditionT) + sm_mapping_get_value( _sm_service_group_condition_mappings, + SM_SERVICE_GROUP_CONDITION_MAX, + condition_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Condition String +// ====================================== +const char* sm_service_group_condition_str( SmServiceGroupConditionT condition ) +{ + return( sm_mapping_get_str( _sm_service_group_condition_mappings, + SM_SERVICE_GROUP_CONDITION_MAX, condition ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Notification Value +// ======================================== +SmServiceGroupNotificationT sm_service_group_notification_value( + const char* notification_str ) +{ + return( (SmServiceGroupNotificationT) + sm_mapping_get_value( _sm_service_group_notification_mappings, + SM_SERVICE_GROUP_NOTIFICATION_MAX, + notification_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Notification String +// ========================================= +const char* sm_service_group_notification_str( + SmServiceGroupNotificationT notification ) +{ + return( sm_mapping_get_str( _sm_service_group_notification_mappings, + SM_SERVICE_GROUP_NOTIFICATION_MAX, + notification ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Admin State Value +// ================================= +SmServiceAdminStateT sm_service_admin_state_value( const char* state_str ) +{ + return( (SmServiceAdminStateT) + sm_mapping_get_value( _sm_service_admin_state_mappings, + SM_SERVICE_ADMIN_STATE_MAX, state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Admin State String +// ================================== +const char* sm_service_admin_state_str( SmServiceAdminStateT state ) +{ + return( sm_mapping_get_str( _sm_service_admin_state_mappings, + SM_SERVICE_ADMIN_STATE_MAX, state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service State Value +// =========================== +SmServiceStateT sm_service_state_value( const char* state_str ) +{ + return( (SmServiceStateT) + sm_mapping_get_value( _sm_service_state_mappings, + SM_SERVICE_STATE_MAX, state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service State String +// ============================ +const char* sm_service_state_str( SmServiceStateT state ) +{ + return( sm_mapping_get_str( _sm_service_state_mappings, + SM_SERVICE_STATE_MAX, state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service State Lesser Value +// ================================== +SmServiceStateT sm_service_state_lesser( SmServiceStateT state_a, + SmServiceStateT state_b ) +{ + SmServiceStateT lesser_state = SM_SERVICE_STATE_UNKNOWN; + + switch( state_a ) + { + case SM_SERVICE_STATE_NIL: + lesser_state = state_b; + break; + + case SM_SERVICE_STATE_INITIAL: + if( SM_SERVICE_STATE_NIL == state_b ) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_STATE_UNKNOWN: + if(( SM_SERVICE_STATE_NIL == state_b )|| + ( SM_SERVICE_STATE_INITIAL == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_STATE_DISABLED: + if(( SM_SERVICE_STATE_NIL == state_b )|| + ( SM_SERVICE_STATE_INITIAL == state_b )|| + ( SM_SERVICE_STATE_UNKNOWN == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_STATE_ENABLING: + if(( SM_SERVICE_STATE_NIL == state_b )|| + ( SM_SERVICE_STATE_INITIAL == state_b )|| + ( SM_SERVICE_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_STATE_ENABLING_THROTTLE == state_b )|| + ( SM_SERVICE_STATE_DISABLED == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_STATE_DISABLING: + if(( SM_SERVICE_STATE_NIL == state_b )|| + ( SM_SERVICE_STATE_INITIAL == state_b )|| + ( SM_SERVICE_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_STATE_DISABLED == state_b )|| + ( SM_SERVICE_STATE_ENABLING == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_STATE_ENABLED_STANDBY: + if(( SM_SERVICE_STATE_NIL == state_b )|| + ( SM_SERVICE_STATE_INITIAL == state_b )|| + ( SM_SERVICE_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_STATE_ENABLING_THROTTLE == state_b )|| + ( SM_SERVICE_STATE_ENABLING == state_b )|| + ( SM_SERVICE_STATE_DISABLING == state_b )|| + ( SM_SERVICE_STATE_DISABLED == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_ACTIVE: + if(( SM_SERVICE_STATE_NIL == state_b )|| + ( SM_SERVICE_STATE_INITIAL == state_b )|| + ( SM_SERVICE_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_STATE_ENABLING_THROTTLE == state_b )|| + ( SM_SERVICE_STATE_ENABLING == state_b )|| + ( SM_SERVICE_STATE_DISABLING == state_b )|| + ( SM_SERVICE_STATE_DISABLED == state_b )|| + ( SM_SERVICE_STATE_ENABLED_STANDBY == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_STATE_ENABLED_GO_STANDBY: + if(( SM_SERVICE_STATE_NIL == state_b )|| + ( SM_SERVICE_STATE_INITIAL == state_b )|| + ( SM_SERVICE_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_STATE_ENABLING_THROTTLE == state_b )|| + ( SM_SERVICE_STATE_ENABLING == state_b )|| + ( SM_SERVICE_STATE_DISABLING == state_b )|| + ( SM_SERVICE_STATE_DISABLED == state_b )|| + ( SM_SERVICE_STATE_ENABLED_STANDBY == state_b )|| + ( SM_SERVICE_STATE_ENABLED_GO_ACTIVE == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + case SM_SERVICE_STATE_ENABLED_ACTIVE: + if(( SM_SERVICE_STATE_NIL == state_b )|| + ( SM_SERVICE_STATE_INITIAL == state_b )|| + ( SM_SERVICE_STATE_UNKNOWN == state_b )|| + ( SM_SERVICE_STATE_ENABLING_THROTTLE == state_b )|| + ( SM_SERVICE_STATE_ENABLING == state_b )|| + ( SM_SERVICE_STATE_DISABLING == state_b )|| + ( SM_SERVICE_STATE_DISABLED == state_b )|| + ( SM_SERVICE_STATE_ENABLED_STANDBY == state_b )|| + ( SM_SERVICE_STATE_ENABLED_GO_ACTIVE == state_b )|| + ( SM_SERVICE_STATE_ENABLED_GO_STANDBY == state_b )) + { + lesser_state = state_b; + } else { + lesser_state = state_a; + } + break; + + default: + DPRINTFE( "Unknown state (%s) given.", + sm_service_state_str( state_a ) ); + break; + } + + return( lesser_state ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Event Value +// =========================== +SmServiceEventT sm_service_event_value( const char* event_str ) +{ + return( (SmServiceEventT) + sm_mapping_get_value( _sm_service_event_mappings, + SM_SERVICE_EVENT_MAX, event_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Event String +// ============================ +const char* sm_service_event_str( SmServiceEventT event ) +{ + return( sm_mapping_get_str( _sm_service_event_mappings, + SM_SERVICE_EVENT_MAX, event ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Status Value +// ============================ +SmServiceStatusT sm_service_status_value( const char* status_str ) +{ + return( (SmServiceStatusT) + sm_mapping_get_value( _sm_service_status_mappings, + SM_SERVICE_STATUS_MAX, status_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Status String +// ============================= +const char* sm_service_status_str( SmServiceStatusT status ) +{ + return( sm_mapping_get_str( _sm_service_status_mappings, + SM_SERVICE_STATUS_MAX, status ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Condition Value +// =============================== +SmServiceConditionT sm_service_condition_value( const char* condition_str ) +{ + return( (SmServiceConditionT) + sm_mapping_get_value( _sm_service_condition_mappings, + SM_SERVICE_CONDITION_MAX, condition_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Condition String +// ================================ +const char* sm_service_condition_str( SmServiceConditionT condition ) +{ + return( sm_mapping_get_str( _sm_service_condition_mappings, + SM_SERVICE_CONDITION_MAX, condition ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Severity Value +// ============================== +SmServiceSeverityT sm_service_severity_value( const char* severity_str ) +{ + return( (SmServiceSeverityT) + sm_mapping_get_value( _sm_service_severity_mappings, + SM_SERVICE_SEVERITY_MAX, severity_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Severity String +// =============================== +const char* sm_service_severity_str( SmServiceSeverityT severity ) +{ + return( sm_mapping_get_str( _sm_service_severity_mappings, + SM_SERVICE_SEVERITY_MAX, severity ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Heartbeat Type Value +// ==================================== +SmServiceHeartbeatTypeT sm_service_heartbeat_type_value( + const char* heartbeat_type_str ) +{ + return( (SmServiceHeartbeatTypeT) + sm_mapping_get_value( _sm_service_heartbeat_type_mappings, + SM_SERVICE_HEARTBEAT_TYPE_MAX, + heartbeat_type_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Heartbeat Type String +// ===================================== +const char* sm_service_heartbeat_type_str( + SmServiceHeartbeatTypeT heartbeat_type ) +{ + return( sm_mapping_get_str( _sm_service_heartbeat_type_mappings, + SM_SERVICE_HEARTBEAT_TYPE_MAX, + heartbeat_type ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Heartbeat State Value +// ===================================== +SmServiceHeartbeatStateT sm_service_heartbeat_state_value( + const char* heartbeat_state_str ) +{ + return( (SmServiceHeartbeatStateT) + sm_mapping_get_value( _sm_service_heartbeat_state_mappings, + SM_SERVICE_HEARTBEAT_STATE_MAX, + heartbeat_state_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Heartbeat State String +// ====================================== +const char* sm_service_heartbeat_state_str( + SmServiceHeartbeatStateT heartbeat_state ) +{ + return( sm_mapping_get_str( _sm_service_heartbeat_state_mappings, + SM_SERVICE_HEARTBEAT_STATE_MAX, + heartbeat_state ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Dependency Type Value +// ===================================== +SmServiceDependencyTypeT sm_service_dependency_type_value( + const char* type_str ) +{ + return( (SmServiceDependencyTypeT) + sm_mapping_get_value( _sm_service_dependency_type_mappings, + SM_SERVICE_DEPENDENCY_TYPE_MAX, type_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Dependency Type String +// ====================================== +const char* sm_service_dependency_type_str( SmServiceDependencyTypeT type ) +{ + return( sm_mapping_get_str( _sm_service_dependency_type_mappings, + SM_SERVICE_DEPENDENCY_TYPE_MAX, type ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Action Value +// ============================ +SmServiceActionT sm_service_action_value( const char* action_str ) +{ + return( (SmServiceActionT) + sm_mapping_get_value( _sm_service_action_mappings, + SM_SERVICE_ACTION_MAX, action_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Action String +// ============================= +const char* sm_service_action_str( SmServiceActionT action ) +{ + return( sm_mapping_get_str( _sm_service_action_mappings, + SM_SERVICE_ACTION_MAX, action ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Action Result Value +// =================================== +SmServiceActionResultT sm_service_action_result_value( const char* result_str ) +{ + return( (SmServiceActionResultT) + sm_mapping_get_value( _sm_service_action_result_mappings, + SM_SERVICE_ACTION_RESULT_MAX, result_str ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Service Action Result String +// ==================================== +const char* sm_service_action_result_str( SmServiceActionResultT result ) +{ + return( sm_mapping_get_str( _sm_service_action_result_mappings, + SM_SERVICE_ACTION_RESULT_MAX, result ) ); +} +// **************************************************************************** + +// **************************************************************************** +// Types - Network Address Value +// ============================= +bool sm_network_address_value( const char address_str[], + SmNetworkAddressT* address ) +{ + int result = 0; + + if( NULL == address ) + { + return false; + } + + if(( SM_NETWORK_TYPE_IPV4 == address->type )|| + ( SM_NETWORK_TYPE_IPV4_UDP == address->type )) + { + result = inet_pton( AF_INET, address_str, &(address->u.ipv4.sin) ); + + } else if(( SM_NETWORK_TYPE_IPV6 == address->type )|| + ( SM_NETWORK_TYPE_IPV6_UDP == address->type )) + { + result = inet_pton( AF_INET6, address_str, &(address->u.ipv6.sin6) ); + + } else { + DPRINTFD( "Unsupported network address type (%s).", + sm_network_type_str( address->type ) ); + } + + if( 0 >= result ) + { + memset( address, 0, sizeof(SmNetworkAddressT) ); + return false; + } + + return true; +} +// **************************************************************************** + +// **************************************************************************** +// Types - Network Address String +// ============================== +void sm_network_address_str( const SmNetworkAddressT* address, + char address_str[] ) +{ + address_str[0] = '\0'; + + if( NULL != address ) + { + const char* result = NULL; + + if(( SM_NETWORK_TYPE_IPV4 == address->type )|| + ( SM_NETWORK_TYPE_IPV4_UDP == address->type )) + { + result = inet_ntop( AF_INET, &(address->u.ipv4.sin), + address_str, SM_NETWORK_ADDRESS_MAX_CHAR ); + + } else if(( SM_NETWORK_TYPE_IPV6 == address->type )|| + ( SM_NETWORK_TYPE_IPV6_UDP == address->type )) + { + result = inet_ntop( AF_INET6, &(address->u.ipv6.sin6), + address_str, SM_NETWORK_ADDRESS_MAX_CHAR ); + + } else { + DPRINTFD( "Unsupported network address type (%s).", + sm_network_type_str( address->type ) ); + } + + if( NULL == result ) + { + address_str[0] = '\0'; + } + } +} +// **************************************************************************** + +// **************************************************************************** +// Types - Error String +// ==================== +const char* sm_error_str( SmErrorT error ) +{ + return( sm_mapping_get_str( _sm_error_mappings, SM_ERROR_MAX, error ) ); +} +// **************************************************************************** + + +// **************************************************************************** +// Types - System Mode String +// ======================================= +const char* sm_system_mode_str( SmSystemModeT system_mode) +{ + return( sm_mapping_get_str(_sm_system_mode_mapping, SM_SYSTEM_MODE_MAX, system_mode) ); +} +// **************************************************************************** + + +// **************************************************************************** +// Service Domain Interface Type +// ===================================== +SmInterfaceTypeT sm_get_interface_type( const char* domain_interface ) +{ + if ( 0 == strcmp ( SM_SERVICE_DOMAIN_MGMT_INTERFACE, domain_interface ) ) + { + return SM_INTERFACE_MGMT; + } else if ( 0 == strcmp ( SM_SERVICE_DOMAIN_OAM_INTERFACE, domain_interface ) ) + { + return SM_INTERFACE_OAM; + } else if ( 0 == strcmp ( SM_SERVICE_DOMAIN_INFRA_INTERFACE, domain_interface ) ) + { + return SM_INTERFACE_INFRA; + } + + return SM_INTERFACE_UNKNOWN; +} +// **************************************************************************** + +// **************************************************************************** +// node schedule state +// ===================================== +const char* sm_node_schedule_state_str( SmNodeScheduleStateT state ) +{ + return( sm_mapping_get_str(_sm_node_schedule_state_mappings, SM_NODE_STATE_MAX, state) ); +} +// **************************************************************************** + diff --git a/service-mgmt/sm-common-1.0.0/src/sm_types.h b/service-mgmt/sm-common-1.0.0/src/sm_types.h new file mode 100644 index 00000000..0fa563cd --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_types.h @@ -0,0 +1,1252 @@ +// +// Copyright (c) 2014-2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_TYPES_H__ +#define __SM_TYPES_H__ + +#include +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_CONFIG_OPTION_STANDBY_ALL_SERVICES_ON_A_LOCKED_NODE + +#define STRINGIZE(str) #str +#define MAKE_STRING(str) STRINGIZE(str) + +#define SM_VERSION 1 +#define SM_REVISION 2 +#define SM_RUN_DIRECTORY "/var/run/sm" +#define SM_RUN_SERVICES_DIRECTORY "/var/run/sm/services" +#define SM_DATABASE_NAME "/var/run/sm/sm.db" +#define SM_HEARTBEAT_DATABASE_NAME "/var/run/sm/sm.hb.db" +#define SM_MASTER_DATABASE_NAME "/var/lib/sm/sm.db" +#define SM_MASTER_HEARTBEAT_DATABASE_NAME "/var/lib/sm/sm.hb.db" +#define SM_PATCH_SCRIPT "/var/lib/sm/patches/sm-patch.sql" + +#define SM_SERVICE_ACTION_PLUGIN_TYPE_LSB_SCRIPT "lsb-script" +#ifdef __LSB_DIR +#define SM_SERVICE_ACTION_PLUGIN_TYPE_LSB_DIR MAKE_STRING(__LSB_DIR) +#else +#define SM_SERVICE_ACTION_PLUGIN_TYPE_LSB_DIR "/etc/init.d" +#endif + +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_VERSION "1" +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_REVISION "1" +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_SCRIPT "ocf-script" + +#ifdef __OCF_DIR +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_DIR MAKE_STRING(__OCF_DIR) +#else +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_DIR "/usr/lib/ocf" +#endif +#ifdef __OCF_PLUGIN_DIR +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_PLUGIN_DIR MAKE_STRING(__OCF_PLUGIN_DIR) +#else +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_PLUGIN_DIR "/usr/lib/ocf/resource.d" +#endif + +#ifdef __OCF_DIR64 +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_DIR64 MAKE_STRING(__OCF_DIR64) +#else +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_DIR64 "/usr/lib64/ocf" +#endif +#ifdef __OCF_PLUGIN_DIR64 +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_PLUGIN_DIR64 MAKE_STRING(__OCF_PLUGIN_DIR64) +#else +#define SM_SERVICE_ACTION_PLUGIN_TYPE_OCF_PLUGIN_DIR64 "/usr/lib64/ocf/resource.d" +#endif + +#define SM_SERVICE_ACTION_PLUGIN_TYPE_PYTHON_SCRIPT "python-script" +#define SM_SERVICE_ACTION_PLUGIN_TYPE_CUSTOM_SCRIPT "custom-script" +#define SM_SERVICE_ACTION_PLUGIN_TYPE_SHARED_LIBRARY "shared-library" + +#define SM_PROCESS_FAILED -65533 +#define SM_SERVICE_ACTION_PLUGIN_TIMEOUT -65534 +#define SM_SERVICE_ACTION_PLUGIN_FAILURE -65535 +#define SM_SERVICE_ACTION_PLUGIN_FORCE_SUCCESS -65536 + +#define SM_INVALID_INDEX -1 + +#define SM_PROCESS_PID_FILENAME "/var/run/sm.pid" +#define SM_TRAP_PROCESS_PID_FILENAME "/var/run/sm-trap.pid" +#define SM_WATCHDOG_PROCESS_PID_FILENAME "/var/run/sm-watchdog.pid" +#define SM_ERU_PROCESS_PID_FILENAME "/var/run/sm-eru.pid" + +#define SM_BOOT_COMPLETE_FILENAME "/var/run/sm_boot_complete" + +#define SM_INDICATE_DEGRADED_FILENAME "/var/run/.sm_degraded" + +#define SM_WATCHDOG_HEARTBEAT_FILENAME "/var/run/.sm_watchdog_heartbeat" + +#define SM_DUMP_DATA_FILE "/tmp/sm_data_dump.txt" + +#define SM_TROUBLESHOOT_LOG_FILE "/var/log/sm-troubleshoot.log" +#define SM_TROUBLESHOOT_SCRIPT "/usr/local/sbin/sm-troubleshoot" + +#define SM_NOTIFICATION_SCRIPT "/usr/local/sbin/sm-notification" + +#define SM_SERVICE_DOMAIN_WEIGHT_MINIMUM 0 +#define SM_SERVICE_DOMAIN_WEIGHT_UNSELECTABLE_ACTIVE -1 + +#define SM_SERVICE_DOMAIN_MGMT_INTERFACE "management-interface" +#define SM_SERVICE_DOMAIN_OAM_INTERFACE "oam-interface" +#define SM_SERVICE_DOMAIN_INFRA_INTERFACE "infrastructure-interface" + +#define SM_MGMT_INTERFACE_NAME "mgmt" +#define SM_OAM_INTERFACE_NAME "oam" +#define SM_INFRA_INTERFACE_NAME "infra" +#define SM_MAX_IF_NAME_LEN 5 + +#define SM_NODE_CONTROLLER_0_NAME "controller-0" +#define SM_NODE_CONTROLLER_1_NAME "controller-1" + +#define SM_CPE_MODE_SIMPLEX "simplex" +#define SM_CPE_MODE_DUPLEX_DIRECT "duplex-direct" +#define SM_CPE_MODE_DUPLEX "duplex" + +typedef enum +{ + SM_DB_TYPE_MAIN, + SM_DB_TYPE_HEARTBEAT, + SM_DB_TYPE_MAX +} SmDbTypeT; + +typedef enum +{ + SM_COMPARE_OPERATOR_GT, + SM_COMPARE_OPERATOR_GE, + SM_COMPARE_OPERATOR_LT, + SM_COMPARE_OPERATOR_LE, + SM_COMPARE_OPERATOR_EQ, + SM_COMPARE_OPERATOR_NE, + SM_COMPARE_OPERATOR_MAX +} SmCompareOperatorT; + +typedef enum +{ + SM_NODE_ADMIN_STATE_NIL, + SM_NODE_ADMIN_STATE_UNKNOWN, + SM_NODE_ADMIN_STATE_LOCKED, + SM_NODE_ADMIN_STATE_UNLOCKED, + SM_NODE_ADMIN_STATE_MAX +} SmNodeAdminStateT; + +typedef enum +{ + SM_NODE_OPERATIONAL_STATE_NIL, + SM_NODE_OPERATIONAL_STATE_UNKNOWN, + SM_NODE_OPERATIONAL_STATE_ENABLED, + SM_NODE_OPERATIONAL_STATE_DISABLED, + SM_NODE_OPERATIONAL_STATE_MAX +} SmNodeOperationalStateT; + +typedef enum +{ + SM_NODE_AVAIL_STATUS_NIL, + SM_NODE_AVAIL_STATUS_UNKNOWN, + SM_NODE_AVAIL_STATUS_NONE, + SM_NODE_AVAIL_STATUS_AVAILABLE, + SM_NODE_AVAIL_STATUS_DEGRADED, + SM_NODE_AVAIL_STATUS_FAILED, + SM_NODE_AVAIL_STATUS_MAX +} SmNodeAvailStatusT; + +typedef enum +{ + SM_NODE_READY_STATE_NIL, + SM_NODE_READY_STATE_UNKNOWN, + SM_NODE_READY_STATE_ENABLED, + SM_NODE_READY_STATE_DISABLED, + SM_NODE_READY_STATE_MAX +} SmNodeReadyStateT; + +typedef enum +{ + SM_NODE_EVENT_NIL, + SM_NODE_EVENT_UNKNOWN, + SM_NODE_EVENT_ENABLED, + SM_NODE_EVENT_DISABLED, + SM_NODE_EVENT_AUDIT, + SM_NODE_EVENT_MAX +} SmNodeEventT; + +typedef enum +{ + SM_INTERFACE_STATE_NIL, + SM_INTERFACE_STATE_UNKNOWN, + SM_INTERFACE_STATE_ENABLED, + SM_INTERFACE_STATE_DISABLED, + SM_INTERFACE_STATE_NOT_IN_USE, + SM_INTERFACE_STATE_MAX +} SmInterfaceStateT; + +typedef enum +{ + SM_NETWORK_TYPE_NIL, + SM_NETWORK_TYPE_UNKNOWN, + SM_NETWORK_TYPE_IPV4, + SM_NETWORK_TYPE_IPV6, + SM_NETWORK_TYPE_IPV4_UDP, + SM_NETWORK_TYPE_IPV6_UDP, + SM_NETWORK_TYPE_MAX +} SmNetworkTypeT; + +typedef enum +{ + SM_INTERFACE_UNKNOWN, + SM_INTERFACE_MGMT, + SM_INTERFACE_INFRA, + SM_INTERFACE_OAM +}SmInterfaceTypeT; + +typedef enum +{ + SM_PATH_TYPE_NIL, + SM_PATH_TYPE_UNKNOWN, + SM_PATH_TYPE_PRIMARY, + SM_PATH_TYPE_SECONDARY, + SM_PATH_TYPE_STATUS_ONLY, + SM_PATH_TYPE_MAX +} SmPathTypeT; + +typedef enum +{ + SM_AUTH_TYPE_NIL, + SM_AUTH_TYPE_UNKNOWN, + SM_AUTH_TYPE_NONE, + SM_AUTH_TYPE_HMAC_SHA512, + SM_AUTH_TYPE_MAX +} SmAuthTypeT; + +typedef enum +{ + SM_ORCHESTRATION_TYPE_NIL, + SM_ORCHESTRATION_TYPE_UNKNOWN, + SM_ORCHESTRATION_TYPE_GEOGRAPHICAL, + SM_ORCHESTRATION_TYPE_REGIONAL, + SM_ORCHESTRATION_TYPE_HYBRID, + SM_ORCHESTRATION_TYPE_MAX +} SmOrchestrationTypeT; + +typedef enum +{ + SM_DESIGNATION_TYPE_NIL, + SM_DESIGNATION_TYPE_UNKNOWN, + SM_DESIGNATION_TYPE_LEADER, + SM_DESIGNATION_TYPE_BACKUP, + SM_DESIGNATION_TYPE_OTHER, + SM_DESIGNATION_TYPE_MAX +} SmDesignationTypeT; + +typedef enum +{ + SM_SERVICE_DOMAIN_STATE_NIL, + SM_SERVICE_DOMAIN_STATE_UNKNOWN, + SM_SERVICE_DOMAIN_STATE_INITIAL, + SM_SERVICE_DOMAIN_STATE_WAITING, + SM_SERVICE_DOMAIN_STATE_LEADER, + SM_SERVICE_DOMAIN_STATE_BACKUP, + SM_SERVICE_DOMAIN_STATE_OTHER, + SM_SERVICE_DOMAIN_STATE_MAX +} SmServiceDomainStateT; + +typedef enum +{ + SM_SERVICE_DOMAIN_EVENT_NIL, + SM_SERVICE_DOMAIN_EVENT_UNKNOWN, + SM_SERVICE_DOMAIN_EVENT_HELLO_MSG, + SM_SERVICE_DOMAIN_EVENT_NEIGHBOR_AGEOUT, + SM_SERVICE_DOMAIN_EVENT_INTERFACE_ENABLED, + SM_SERVICE_DOMAIN_EVENT_INTERFACE_DISABLED, + SM_SERVICE_DOMAIN_EVENT_WAIT_EXPIRED, + SM_SERVICE_DOMAIN_EVENT_MAX +} SmServiceDomainEventT; + +typedef enum +{ + SM_SERVICE_DOMAIN_EVENT_DATA_MSG_NODE_NAME, + SM_SERVICE_DOMAIN_EVENT_DATA_MSG_GENERATION, + SM_SERVICE_DOMAIN_EVENT_DATA_MSG_PRIORITY, + SM_SERVICE_DOMAIN_EVENT_DATA_MSG_LEADER, + SM_SERVICE_DOMAIN_EVENT_DATA_MAX +} SmServiceDomainEventDataT; + +typedef enum +{ + SM_SERVICE_DOMAIN_INTERFACE_EVENT_NIL, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_UNKNOWN, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_ENABLED, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_NODE_DISABLED, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_ENABLED, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_DISABLED, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_AUDIT, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_NOT_IN_USE, + SM_SERVICE_DOMAIN_INTERFACE_EVENT_MAX +} SmServiceDomainInterfaceEventT; + +typedef enum +{ + SM_SERVICE_DOMAIN_INTERFACE_CONNECT_TYPE_TOR, + SM_SERVICE_DOMAIN_INTERFACE_CONNECT_TYPE_DC +} SmServiceDomainInterfaceConnectTypeT; + +typedef enum +{ + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_NIL, + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN, + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE_START, + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_EXCHANGE, + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL, + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_MAX +} SmServiceDomainNeighborStateT; + +typedef enum +{ + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_NIL, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_UNKNOWN, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_HELLO_MSG, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_MSG, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_START_TIMER, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_MSG, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_EXCHANGE_TIMEOUT, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DOWN, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_MAX +} SmServiceDomainNeighborEventT; + +typedef enum +{ + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MSG_EXCHANGE_SEQ, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MSG_MORE_MEMBERS, + SM_SERVICE_DOMAIN_NEIGHBOR_EVENT_DATA_MAX +} SmServiceDomainNeighborEventDataT; + +typedef enum +{ + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_NIL, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_UNKNOWN, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_NONE, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_PLUS_M, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_TO_1, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_N_TO_N, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_MAX +} SmServiceDomainMemberRedundancyModelT; + +typedef enum +{ + SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_NIL, + SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_UNKNOWN, + SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_DISABLE_ALL_ACTIVE, + SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_SELECT_BEST_ACTIVE, + SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_MAX +} SmServiceDomainSplitBrainRecoveryT; + +typedef enum +{ + SM_SERVICE_GROUP_ACTION_NIL, + SM_SERVICE_GROUP_ACTION_UNKNOWN, + SM_SERVICE_GROUP_ACTION_DISABLE, + SM_SERVICE_GROUP_ACTION_GO_ACTIVE, + SM_SERVICE_GROUP_ACTION_GO_STANDBY, + SM_SERVICE_GROUP_ACTION_AUDIT, + SM_SERVICE_GROUP_ACTION_RECOVER, + SM_SERVICE_GROUP_ACTION_MAX +} SmServiceGroupActionT; + +#define SM_SERVICE_GROUP_ACTION_FLAG_RECOVER 1 +#define SM_SERVICE_GROUP_ACTION_FLAG_ESCALATE_RECOVERY 2 +#define SM_SERVICE_GROUP_ACTION_FLAG_CLEAR_FATAL_CONDITION 3 + +#define SM_FLAG_SET(flags, flag) (flags |= (1 << flag)) +#define SM_FLAG_CLEAR(flags, flag) (flags &= ~(1 << flag)) +#define SM_FLAG_TOGGLE(flags, flag) (flags ^= (1 << flag)) +#define SM_FLAG_IS_SET(flags, flag) (flags & (1 << flag)) + +// bit flag for sm service action options +// restart a service without restarting its dependency +#define SM_SVC_RESTART_NO_DEP 0x1 + +typedef uint64_t SmServiceGroupActionFlagsT; + +typedef enum +{ + SM_SERVICE_GROUP_STATE_NIL, + SM_SERVICE_GROUP_STATE_NA, + SM_SERVICE_GROUP_STATE_INITIAL, + SM_SERVICE_GROUP_STATE_UNKNOWN, + SM_SERVICE_GROUP_STATE_STANDBY, + SM_SERVICE_GROUP_STATE_GO_STANDBY, + SM_SERVICE_GROUP_STATE_GO_ACTIVE, + SM_SERVICE_GROUP_STATE_ACTIVE, + SM_SERVICE_GROUP_STATE_DISABLING, + SM_SERVICE_GROUP_STATE_DISABLED, + SM_SERVICE_GROUP_STATE_SHUTDOWN, + SM_SERVICE_GROUP_STATE_MAX +} SmServiceGroupStateT; + +typedef enum +{ + SM_SERVICE_GROUP_EVENT_NIL, + SM_SERVICE_GROUP_EVENT_UNKNOWN, + SM_SERVICE_GROUP_EVENT_GO_ACTIVE, + SM_SERVICE_GROUP_EVENT_GO_STANDBY, + SM_SERVICE_GROUP_EVENT_DISABLE, + SM_SERVICE_GROUP_EVENT_AUDIT, + SM_SERVICE_GROUP_EVENT_SERVICE_SCN, + SM_SERVICE_GROUP_EVENT_SHUTDOWN, + SM_SERVICE_GROUP_EVENT_NOTIFICATION_SUCCESS, + SM_SERVICE_GROUP_EVENT_NOTIFICATION_FAILED, + SM_SERVICE_GROUP_EVENT_NOTIFICATION_TIMEOUT, + SM_SERVICE_GROUP_EVENT_MAX, +} SmServiceGroupEventT; + +typedef enum +{ + SM_SERVICE_GROUP_EVENT_DATA_SERVICE_NAME, + SM_SERVICE_GROUP_EVENT_DATA_SERVICE_STATE, + SM_SERVICE_GROUP_EVENT_DATA_MAX +} SmServiceGroupEventDataT; + +typedef enum +{ + SM_SERVICE_GROUP_STATUS_NIL, + SM_SERVICE_GROUP_STATUS_UNKNOWN, + SM_SERVICE_GROUP_STATUS_NONE, + SM_SERVICE_GROUP_STATUS_WARN, + SM_SERVICE_GROUP_STATUS_DEGRADED, + SM_SERVICE_GROUP_STATUS_FAILED, + SM_SERVICE_GROUP_STATUS_MAX +} SmServiceGroupStatusT; + +typedef enum +{ + SM_SERVICE_GROUP_CONDITION_NIL, + SM_SERVICE_GROUP_CONDITION_UNKNOWN, + SM_SERVICE_GROUP_CONDITION_NONE, + SM_SERVICE_GROUP_CONDITION_DATA_INCONSISTENT, + SM_SERVICE_GROUP_CONDITION_DATA_OUTDATED, + SM_SERVICE_GROUP_CONDITION_DATA_CONSISTENT, + SM_SERVICE_GROUP_CONDITION_DATA_SYNC, + SM_SERVICE_GROUP_CONDITION_DATA_STANDALONE, + SM_SERVICE_GROUP_CONDITION_RECOVERY_FAILURE, + SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE, + SM_SERVICE_GROUP_CONDITION_FATAL_FAILURE, + SM_SERVICE_GROUP_CONDITION_MAX +} SmServiceGroupConditionT; + +typedef enum +{ + SM_SERVICE_GROUP_NOTIFICATION_NIL, + SM_SERVICE_GROUP_NOTIFICATION_UNKNOWN, + SM_SERVICE_GROUP_NOTIFICATION_STANDBY, + SM_SERVICE_GROUP_NOTIFICATION_GO_STANDBY, + SM_SERVICE_GROUP_NOTIFICATION_GO_ACTIVE, + SM_SERVICE_GROUP_NOTIFICATION_ACTIVE, + SM_SERVICE_GROUP_NOTIFICATION_DISABLING, + SM_SERVICE_GROUP_NOTIFICATION_DISABLED, + SM_SERVICE_GROUP_NOTIFICATION_SHUTDOWN, + SM_SERVICE_GROUP_NOTIFICATION_MAX +} SmServiceGroupNotificationT; + +typedef enum +{ + SM_SERVICE_ADMIN_STATE_NIL, + SM_SERVICE_ADMIN_STATE_NA, + SM_SERVICE_ADMIN_STATE_LOCKED, + SM_SERVICE_ADMIN_STATE_UNLOCKED, + SM_SERVICE_ADMIN_STATE_MAX +} SmServiceAdminStateT; + +typedef enum +{ + SM_SERVICE_STATE_NIL, + SM_SERVICE_STATE_NA, + SM_SERVICE_STATE_INITIAL, + SM_SERVICE_STATE_UNKNOWN, + SM_SERVICE_STATE_ENABLED_STANDBY, + SM_SERVICE_STATE_ENABLED_GO_STANDBY, + SM_SERVICE_STATE_ENABLED_GO_ACTIVE, + SM_SERVICE_STATE_ENABLED_ACTIVE, + SM_SERVICE_STATE_ENABLING_THROTTLE, + SM_SERVICE_STATE_ENABLING, + SM_SERVICE_STATE_DISABLING, + SM_SERVICE_STATE_DISABLED, + SM_SERVICE_STATE_SHUTDOWN, + SM_SERVICE_STATE_MAX +} SmServiceStateT; + +typedef enum +{ + SM_SERVICE_EVENT_NIL, + SM_SERVICE_EVENT_UNKNOWN, + SM_SERVICE_EVENT_ENABLE_THROTTLE, + SM_SERVICE_EVENT_ENABLE, + SM_SERVICE_EVENT_ENABLE_SUCCESS, + SM_SERVICE_EVENT_ENABLE_FAILED, + SM_SERVICE_EVENT_ENABLE_TIMEOUT, + SM_SERVICE_EVENT_GO_ACTIVE, + SM_SERVICE_EVENT_GO_ACTIVE_SUCCESS, + SM_SERVICE_EVENT_GO_ACTIVE_FAILED, + SM_SERVICE_EVENT_GO_ACTIVE_TIMEOUT, + SM_SERVICE_EVENT_GO_STANDBY, + SM_SERVICE_EVENT_GO_STANDBY_SUCCESS, + SM_SERVICE_EVENT_GO_STANDBY_FAILED, + SM_SERVICE_EVENT_GO_STANDBY_TIMEOUT, + SM_SERVICE_EVENT_DISABLE, + SM_SERVICE_EVENT_DISABLE_SUCCESS, + SM_SERVICE_EVENT_DISABLE_FAILED, + SM_SERVICE_EVENT_DISABLE_TIMEOUT, + SM_SERVICE_EVENT_AUDIT, + SM_SERVICE_EVENT_AUDIT_SUCCESS, + SM_SERVICE_EVENT_AUDIT_FAILED, + SM_SERVICE_EVENT_AUDIT_TIMEOUT, + SM_SERVICE_EVENT_AUDIT_MISMATCH, + SM_SERVICE_EVENT_HEARTBEAT_OKAY, + SM_SERVICE_EVENT_HEARTBEAT_WARN, + SM_SERVICE_EVENT_HEARTBEAT_DEGRADE, + SM_SERVICE_EVENT_HEARTBEAT_FAIL, + SM_SERVICE_EVENT_PROCESS_FAILURE, + SM_SERVICE_EVENT_SHUTDOWN, + SM_SERVICE_EVENT_MAX, +} SmServiceEventT; + +typedef enum +{ + SM_SERVICE_EVENT_DATA_IS_ACTION, + SM_SERVICE_EVENT_DATA_STATE, + SM_SERVICE_EVENT_DATA_STATUS, + SM_SERVICE_EVENT_DATA_CONDITION, + SM_SERVICE_EVENT_DATA_MAX +} SmServiceEventDataT; + +typedef enum +{ + SM_SERVICE_STATUS_NIL, + SM_SERVICE_STATUS_UNKNOWN, + SM_SERVICE_STATUS_NONE, + SM_SERVICE_STATUS_WARN, + SM_SERVICE_STATUS_DEGRADED, + SM_SERVICE_STATUS_FAILED, + SM_SERVICE_STATUS_MAX +} SmServiceStatusT; + +// Service Condition Meanings: +// data-inconsistent: data is not useable. +// data-outdated: data is consistent, but not the latest. +// data-consistent: data is consistent, but might not be the latest (unknown). +// data-standalone: data is consistent, but will not sync. +// recovery-failure: recovery of the service has failed. +// action-failure: a service action has failed. +// fatal-failure: a fatal failure has occured. +typedef enum +{ + SM_SERVICE_CONDITION_NIL, + SM_SERVICE_CONDITION_UNKNOWN, + SM_SERVICE_CONDITION_NONE, + SM_SERVICE_CONDITION_DATA_INCONSISTENT, + SM_SERVICE_CONDITION_DATA_OUTDATED, + SM_SERVICE_CONDITION_DATA_CONSISTENT, + SM_SERVICE_CONDITION_DATA_SYNC, + SM_SERVICE_CONDITION_DATA_STANDALONE, + SM_SERVICE_CONDITION_RECOVERY_FAILURE, + SM_SERVICE_CONDITION_ACTION_FAILURE, + SM_SERVICE_CONDITION_FATAL_FAILURE, + SM_SERVICE_CONDITION_MAX +} SmServiceConditionT; + +typedef enum +{ + SM_SERVICE_SEVERITY_NIL, + SM_SERVICE_SEVERITY_UNKNOWN, + SM_SERVICE_SEVERITY_NONE, + SM_SERVICE_SEVERITY_MINOR, + SM_SERVICE_SEVERITY_MAJOR, + SM_SERVICE_SEVERITY_CRITICAL, + SM_SERVICE_SEVERITY_MAX +} SmServiceSeverityT; + +typedef enum +{ + SM_SERVICE_HEARTBEAT_TYPE_NIL, + SM_SERVICE_HEARTBEAT_TYPE_UNKNOWN, + SM_SERVICE_HEARTBEAT_TYPE_UNIX, + SM_SERVICE_HEARTBEAT_TYPE_UDP, + SM_SERVICE_HEARTBEAT_TYPE_MAX, +} SmServiceHeartbeatTypeT; + +typedef enum +{ + SM_SERVICE_HEARTBEAT_STATE_NIL, + SM_SERVICE_HEARTBEAT_STATE_UNKNOWN, + SM_SERVICE_HEARTBEAT_STATE_STARTED, + SM_SERVICE_HEARTBEAT_STATE_STOPPED, + SM_SERVICE_HEARTBEAT_STATE_MAX, +} SmServiceHeartbeatStateT; + +typedef enum +{ + SM_SERVICE_DEPENDENCY_TYPE_NIL, + SM_SERVICE_DEPENDENCY_TYPE_UNKNOWN, + SM_SERVICE_DEPENDENCY_TYPE_ACTION, + SM_SERVICE_DEPENDENCY_TYPE_STATE, + SM_SERVICE_DEPENDENCY_TYPE_MAX, +} SmServiceDependencyTypeT; + +typedef enum +{ + SM_SERVICE_ACTION_NIL, + SM_SERVICE_ACTION_NA, + SM_SERVICE_ACTION_UNKNOWN, + SM_SERVICE_ACTION_NONE, + SM_SERVICE_ACTION_ENABLE, + SM_SERVICE_ACTION_DISABLE, + SM_SERVICE_ACTION_GO_ACTIVE, + SM_SERVICE_ACTION_GO_STANDBY, + SM_SERVICE_ACTION_AUDIT_ENABLED, + SM_SERVICE_ACTION_AUDIT_DISABLED, + SM_SERVICE_ACTION_MAX +} SmServiceActionT; + +typedef enum +{ + SM_SERVICE_ACTION_RESULT_NIL, + SM_SERVICE_ACTION_RESULT_UNKNOWN, + SM_SERVICE_ACTION_RESULT_SUCCESS, + SM_SERVICE_ACTION_RESULT_FATAL, + SM_SERVICE_ACTION_RESULT_FAILED, + SM_SERVICE_ACTION_RESULT_TIMEOUT, + SM_SERVICE_ACTION_RESULT_MAX +} SmServiceActionResultT; + +typedef enum +{ + SM_SERVICE_DOMAIN_SCHEDULING_STATE_NIL, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_UNKNOWN, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE_FORCE, + SM_SERVICE_DOMAIN_SCHEDULING_STATE_MAX +} SmServiceDomainSchedulingStateT; + +typedef enum +{ + SM_SERVICE_DOMAIN_SCHEDULING_LIST_NIL, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE, + SM_SERVICE_DOMAIN_SCHEDULING_LIST_MAX +} SmServiceDomainSchedulingListT; + +typedef struct +{ + struct in_addr sin; // stored in network order +} SmIpv4AddressT; + +typedef struct +{ + struct in6_addr sin6; // stored in network order +} SmIpv6AddressT; + +typedef struct +{ + SmNetworkTypeT type; + + union + { + SmIpv4AddressT ipv4; + SmIpv6AddressT ipv6; + } u; +} SmNetworkAddressT; + +typedef enum +{ + SM_OKAY, + SM_NOT_FOUND, + SM_NO_MSG, + SM_FAILED, + SM_NOT_IMPLEMENTED, + SM_ERROR_MAX +} SmErrorT; + +typedef uint32_t SmHeartbeatMsgIfStateT; + +typedef enum +{ + SM_SYSTEM_MODE_UNKNOWN, + SM_SYSTEM_MODE_STANDARD, + SM_SYSTEM_MODE_CPE_DUPLEX, + SM_SYSTEM_MODE_CPE_DUPLEX_DC, + SM_SYSTEM_MODE_CPE_SIMPLEX, + SM_SYSTEM_MODE_MAX +}SmSystemModeT; + +typedef enum +{ + SM_NODE_STATE_UNKNOWN, + SM_NODE_STATE_ACTIVE, + SM_NODE_STATE_STANDBY, + SM_NODE_STATE_INIT, + SM_NODE_STATE_FAILED, + SM_NODE_STATE_MAX +}SmNodeScheduleStateT; + +// **************************************************************************** +// Types - System Mode String +// ======================================= +extern const char* sm_system_mode_str( SmSystemModeT system_mode); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Administrative State Value +// ======================================= +extern SmNodeAdminStateT sm_node_admin_state_value( const char* state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Administrative State String +// ======================================== +extern const char* sm_node_admin_state_str( SmNodeAdminStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Operational State Value +// ==================================== +extern SmNodeOperationalStateT sm_node_oper_state_value( const char* state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Operational State String +// ===================================== +extern const char* sm_node_oper_state_str( SmNodeOperationalStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Availability Status Value +// ====================================== +extern SmNodeAvailStatusT sm_node_avail_status_value( const char* status_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Availability Status String +// ======================================= +extern const char* sm_node_avail_status_str( SmNodeAvailStatusT status ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Ready State Value +// ============================== +extern SmNodeReadyStateT sm_node_ready_state_value( const char* state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Ready State String +// =============================== +extern const char* sm_node_ready_state_str( SmNodeReadyStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node State String +// ========================= +extern const char* sm_node_state_str( SmNodeAdminStateT admin_state, + SmNodeReadyStateT ready_state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Event Value +// ======================== +extern SmNodeEventT sm_node_event_value( const char* event_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Node Event String +// ========================= +extern const char* sm_node_event_str( SmNodeEventT event ); +// **************************************************************************** + +// **************************************************************************** +// Types - Interface State Value +// ============================= +extern SmInterfaceStateT sm_interface_state_value( const char* state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Interface State String +// ============================== +extern const char* sm_interface_state_str( SmInterfaceStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Network Type Value +// ========================== +extern SmNetworkTypeT sm_network_type_value( const char* network_type_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Network Type String +// =========================== +extern const char* sm_network_type_str( SmNetworkTypeT network_type ); +// **************************************************************************** + +// **************************************************************************** +// Types - Path Type Value +// ======================= +extern SmPathTypeT sm_path_type_value( const char* path_type_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Path Type String +// ======================== +extern const char* sm_path_type_str( SmPathTypeT path_type ); +// **************************************************************************** + +// **************************************************************************** +// Types - Authentication Type Value +// ================================= +extern SmAuthTypeT sm_auth_type_value( const char* auth_type_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Authentication Type String +// ================================== +extern const char* sm_auth_type_str( SmAuthTypeT auth_type ); +// **************************************************************************** + +// **************************************************************************** +// Types - Orchestration Type Value +// ================================ +extern SmOrchestrationTypeT sm_orchestration_type_value( + const char* orchestration_type_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Orchestration Type String +// ================================= +extern const char* sm_orchestration_type_str( + SmOrchestrationTypeT orchestration_type ); +// **************************************************************************** + +// **************************************************************************** +// Types - Designation Type Value +// ============================== +extern SmDesignationTypeT sm_designation_type_value( + const char* designation_type_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Designation Type String +// =============================== +extern const char* sm_designation_type_str( + SmDesignationTypeT designation_type ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain State Value +// ================================== +extern SmServiceDomainStateT sm_service_domain_state_value( const char* state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain State String +// =================================== +extern const char* sm_service_domain_state_str( SmServiceDomainStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Event Value +// ================================== +extern SmServiceDomainEventT sm_service_domain_event_value( const char* event_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Event String +// =================================== +extern const char* sm_service_domain_event_str( SmServiceDomainEventT event ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Scheduling State Value +// ============================================= +extern SmServiceDomainSchedulingStateT sm_service_domain_scheduling_state_value( + const char* sched_state_str ); +// **************************************************************************** + +// *************************************************************************** +// Types - Service Domain Scheduling State String +// ============================================== +extern const char* sm_service_domain_scheduling_state_str( + SmServiceDomainSchedulingStateT sched_state ); +// *************************************************************************** + +// **************************************************************************** +// Types - Service Domain Scheduling List Value +// ============================================ +extern SmServiceDomainSchedulingListT sm_service_domain_scheduling_list_value( + const char* sched_list_str ); +// **************************************************************************** + +// *************************************************************************** +// Types - Service Domain Scheduling List String +// ============================================= +extern const char* sm_service_domain_scheduling_list_str( + SmServiceDomainSchedulingListT sched_list ); +// *************************************************************************** + +// **************************************************************************** +// Types - Service Domain Interface Event Value +// ============================================ +extern SmServiceDomainInterfaceEventT sm_service_domain_interface_event_value( + const char* event_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Interface Event String +// ============================================= +extern const char* sm_service_domain_interface_event_str( + SmServiceDomainInterfaceEventT event ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Neighbor State Value +// =========================================== +extern SmServiceDomainNeighborStateT sm_service_domain_neighbor_state_value( + const char* neighbor_state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Neighbor State String +// ============================================ +extern const char* sm_service_domain_neighbor_state_str( + SmServiceDomainNeighborStateT neighbor_state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Neighbor Event Value +// =========================================== +extern SmServiceDomainNeighborEventT sm_service_domain_neighbor_event_value( + const char* neighbor_event_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Neighbor Event String +// ============================================ +extern const char* sm_service_domain_neighbor_event_str( + SmServiceDomainNeighborEventT neighbor_event ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Member Redundancy Model Value +// ==================================================== +extern SmServiceDomainMemberRedundancyModelT +sm_service_domain_member_redundancy_model_value( + const char* model_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Member Redundancy Model String +// ===================================================== +extern const char* sm_service_domain_member_redundancy_model_str( + SmServiceDomainMemberRedundancyModelT model ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Split Brain Recovery Value +// ================================================= +extern SmServiceDomainSplitBrainRecoveryT +sm_service_domain_split_brain_recovery_value( + const char* recovery_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Domain Split Brain Recovery String +// ================================================== +extern const char* sm_service_domain_split_brain_recovery_str( + SmServiceDomainSplitBrainRecoveryT recovery ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Action Value +// ================================== +extern SmServiceGroupActionT sm_service_group_action_value( + const char* action_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Action String +// =================================== +extern const char* sm_service_group_action_str( SmServiceGroupActionT action ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group State Value +// ================================= +extern SmServiceGroupStateT sm_service_group_state_value( + const char* state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group State String +// ================================== +extern const char* sm_service_group_state_str( SmServiceGroupStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group State Lesser Value +// ======================================== +extern SmServiceGroupStateT sm_service_group_state_lesser( + SmServiceGroupStateT state_a, SmServiceGroupStateT state_b ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Event Value +// ================================= +extern SmServiceGroupEventT sm_service_group_event_value( const char* event_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Event String +// ================================== +extern const char* sm_service_group_event_str( SmServiceGroupEventT event ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Status Value +// ================================== +extern SmServiceGroupStatusT sm_service_group_status_value( + const char* status_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Status String +// =================================== +extern const char* sm_service_group_status_str( SmServiceGroupStatusT status ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Condition Value +// ===================================== +extern SmServiceGroupConditionT sm_service_group_condition_value( + const char* condition_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Condition String +// ====================================== +extern const char* sm_service_group_condition_str( + SmServiceGroupConditionT condition ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Notification Value +// ======================================== +extern SmServiceGroupNotificationT sm_service_group_notification_value( + const char* notification_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Group Notification String +// ========================================= +extern const char* sm_service_group_notification_str( + SmServiceGroupNotificationT notification ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Admin State Value +// ================================= +extern SmServiceAdminStateT sm_service_admin_state_value( const char* state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Admin State String +// ================================== +extern const char* sm_service_admin_state_str( SmServiceAdminStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service State Value +// =========================== +extern SmServiceStateT sm_service_state_value( const char* state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service State String +// ============================ +extern const char* sm_service_state_str( SmServiceStateT state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service State Lesser Value +// ================================== +extern SmServiceStateT sm_service_state_lesser( SmServiceStateT state_a, + SmServiceStateT state_b ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Event Value +// =========================== +extern SmServiceEventT sm_service_event_value( const char* event_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Event String +// ============================ +extern const char* sm_service_event_str( SmServiceEventT event ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Status Value +// ============================ +extern SmServiceStatusT sm_service_status_value( const char* status_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Status String +// ============================= +extern const char* sm_service_status_str( SmServiceStatusT status ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Condition Value +// =============================== +extern SmServiceConditionT sm_service_condition_value( const char* condition_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Condition String +// ================================ +extern const char* sm_service_condition_str( SmServiceConditionT condition ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Severity Value +// ============================== +extern SmServiceSeverityT sm_service_severity_value( const char* severity_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Severity String +// ============================== +extern const char* sm_service_severity_str( SmServiceSeverityT severity ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Heartbeat Type Value +// ==================================== +extern SmServiceHeartbeatTypeT sm_service_heartbeat_type_value( + const char* heartbeat_type_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Heartbeat Type String +// ===================================== +extern const char* sm_service_heartbeat_type_str( + SmServiceHeartbeatTypeT heartbeat_type ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Heartbeat State Value +// ===================================== +extern SmServiceHeartbeatStateT sm_service_heartbeat_state_value( + const char* heartbeat_state_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Heartbeat State String +// ====================================== +extern const char* sm_service_heartbeat_state_str( + SmServiceHeartbeatStateT heartbeat_state ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Dependency Type Value +// ===================================== +extern SmServiceDependencyTypeT sm_service_dependency_type_value( + const char* type_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Dependency Type String +// ====================================== +extern const char* sm_service_dependency_type_str( + SmServiceDependencyTypeT type ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Action Value +// ============================ +extern SmServiceActionT sm_service_action_value( const char* action_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Action String +// ============================= +extern const char* sm_service_action_str( SmServiceActionT action ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Action Result Value +// =================================== +extern SmServiceActionResultT sm_service_action_result_value( + const char* result_str ); +// **************************************************************************** + +// **************************************************************************** +// Types - Service Action Result String +// ==================================== +extern const char* sm_service_action_result_str( + SmServiceActionResultT result ); +// **************************************************************************** + +// **************************************************************************** +// Types - Network Address Value +// ============================= +extern bool sm_network_address_value( const char address_str[], + SmNetworkAddressT* address ); +// **************************************************************************** + +// *************************************************************************** +// Types - Network Address As String +// ================================= +extern void sm_network_address_str( const SmNetworkAddressT* address, + char addr_str[] ); +// *************************************************************************** + +// **************************************************************************** +// Types - Error String +// ==================== +extern const char* sm_error_str( SmErrorT error ); +// **************************************************************************** + +// **************************************************************************** +// Service Domain Interface Type +// ===================================== +extern SmInterfaceTypeT sm_get_interface_type( const char* domain_interface ); +// **************************************************************************** + + +// **************************************************************************** +// node schedule state +// ===================================== +extern const char* sm_node_schedule_state_str( SmNodeScheduleStateT state ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_TYPES_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_util_types.c b/service-mgmt/sm-common-1.0.0/src/sm_util_types.c new file mode 100644 index 00000000..00a1ef4e --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_util_types.c @@ -0,0 +1,27 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include +#include +#include "sm_util_types.h" +#include "sm_debug.h" + +mutex_holder::mutex_holder(pthread_mutex_t* mutex) +{ + this->_mutex = mutex; + if( 0 != pthread_mutex_lock( this->_mutex ) ) + { + DPRINTFE("Critical error, failed to obtain the mutex. Quit..."); + abort(); + } +} + +mutex_holder::~mutex_holder() +{ + if( 0 != pthread_mutex_unlock( this->_mutex ) ) + { + DPRINTFE( "Failed to release mutex." ); + } +} diff --git a/service-mgmt/sm-common-1.0.0/src/sm_util_types.h b/service-mgmt/sm-common-1.0.0/src/sm_util_types.h new file mode 100644 index 00000000..19ac1214 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_util_types.h @@ -0,0 +1,20 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_UTIL_TYPES_H__ +#define __SM_UTIL_TYPES_H__ + +#include + +class mutex_holder +{ + private: + pthread_mutex_t* _mutex; + public: + mutex_holder(pthread_mutex_t* mutex); + virtual ~mutex_holder(); +}; + +#endif //__SM_UTIL_TYPES_H__ \ No newline at end of file diff --git a/service-mgmt/sm-common-1.0.0/src/sm_utils.c b/service-mgmt/sm-common-1.0.0/src/sm_utils.c new file mode 100644 index 00000000..ade30e07 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_utils.c @@ -0,0 +1,203 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_utils.h" + +#include "sm_types.h" +#include "sm_debug.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// **************************************************************************** +// Utils - Process Running +// ======================= +bool sm_utils_process_running( const char* pid_filename ) +{ + FILE *fp; + int result; + bool running = true; + + fp = fopen( pid_filename, "r" ); + if( NULL == fp ) + { + running = false; + } else { + int pid; + + fscanf( fp, "%d", &pid ); + if( pid != getpid() ) + { + result = kill( pid, 0 ); + if(( 0 > result )&&( ESRCH == errno )) + { + running = false; + } + } + fclose( fp ); + } + + return( running ); +} +// **************************************************************************** + +// **************************************************************************** +// Utils - Set Pid File +// ==================== +bool sm_utils_set_pid_file( const char* pid_filename ) +{ + FILE *fp = fopen( pid_filename, "w" ); + if( NULL != fp ) + { + fprintf( fp, "%i\n", (int) getpid() ); + fclose( fp ); + return( true ); + } + return( false ); +} +// **************************************************************************** + +// **************************************************************************** +// Utils - Boot Complete +// ===================== +bool sm_utils_boot_complete( void ) +{ + if( 0 > access( SM_BOOT_COMPLETE_FILENAME, F_OK ) ) + { + return( false ); + } + + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Utils - Set Boot Complete +// ========================= +SmErrorT sm_utils_set_boot_complete( void ) +{ + int fd = open( SM_BOOT_COMPLETE_FILENAME, O_RDWR | O_CREAT, + S_IRUSR | S_IRGRP | S_IROTH | O_CLOEXEC ); + if( 0 > fd ) + { + DPRINTFE( "Failed to set boot complete, error=%s.", strerror(errno) ); + return( SM_FAILED ); + } + + close( fd ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Utils - Indicate Degraded +// ========================= +SmErrorT sm_utils_indicate_degraded( void ) +{ + int fd = open( SM_INDICATE_DEGRADED_FILENAME, O_RDWR | O_CREAT, + S_IRUSR | S_IRGRP | S_IROTH | O_CLOEXEC ); + if( 0 > fd ) + { + DPRINTFE( "Failed to indicate degraded, error=%s.", strerror(errno) ); + return( SM_FAILED ); + } + + close( fd ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Utils - Clear Degraded +// ====================== +SmErrorT sm_utils_clear_degraded( void ) +{ + unlink( SM_INDICATE_DEGRADED_FILENAME ); + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Utils - Watchdog Heartbeat +// ========================== +void sm_utils_watchdog_heartbeat( void ) +{ + struct utimbuf file_times; + struct timespec ts_mono; + + clock_gettime( CLOCK_MONOTONIC_RAW, &ts_mono ); + + memset( &file_times, 0, sizeof(struct utimbuf) ); + + file_times.actime = ts_mono.tv_sec; + file_times.modtime = ts_mono.tv_sec; + + if( 0 > access( SM_WATCHDOG_HEARTBEAT_FILENAME, F_OK ) ) + { + int fd = open( SM_WATCHDOG_HEARTBEAT_FILENAME, O_RDWR | O_CREAT, + S_IRUSR | S_IRGRP | S_IROTH | O_CLOEXEC ); + if( 0 > fd ) + { + DPRINTFE( "Failed to create/open watchdog heartbeat, error=%s.", + strerror(errno) ); + return; + } + + close( fd ); + } + + if( 0 > utime( SM_WATCHDOG_HEARTBEAT_FILENAME, &file_times ) ) + { + DPRINTFE( "Failed to update watchdog heartbeat timings, error=%s.", + strerror(errno) ); + return; + } +} +// **************************************************************************** + +// **************************************************************************** +// Utils - Watchdog Delayed +// ========================= +bool sm_utils_watchdog_delayed( int max_delay_secs ) +{ + struct stat stat_data; + + if( 0 == access( SM_WATCHDOG_HEARTBEAT_FILENAME, F_OK ) ) + { + int elapsed_secs; + struct timespec ts_mono; + + clock_gettime( CLOCK_MONOTONIC_RAW, &ts_mono ); + + if( 0 > stat( SM_WATCHDOG_HEARTBEAT_FILENAME, &stat_data ) ) + { + DPRINTFE( "Stat failed on file (%s), error=%s.", + SM_WATCHDOG_HEARTBEAT_FILENAME, strerror( errno ) ); + return( false ); + } + + // Make sure that the elapsed seconds drift is in a valid range. + elapsed_secs = ts_mono.tv_sec - stat_data.st_mtime; + if(( max_delay_secs < elapsed_secs )&&( elapsed_secs <= 300 )) + { + DPRINTFI( "SM-Watchdog has been delayed by more than %d " + "seconds, elapsed_secs=%d", max_delay_secs, + elapsed_secs ); + return( true ); + } + } + + return( false ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_utils.h b/service-mgmt/sm-common-1.0.0/src/sm_utils.h new file mode 100644 index 00000000..f76c7940 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_utils.h @@ -0,0 +1,69 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_UTILS_H__ +#define __SM_UTILS_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Utils - Process Running +// ======================= +extern bool sm_utils_process_running( const char* pid_filename ); +// **************************************************************************** + +// **************************************************************************** +// Utils - Set Pid File +// ==================== +extern bool sm_utils_set_pid_file( const char* pid_filename ); +// **************************************************************************** + +// **************************************************************************** +// Utils - Boot Complete +// ===================== +extern bool sm_utils_boot_complete( void ); +// **************************************************************************** + +// **************************************************************************** +// Utils - Set Boot Complete +// ========================= +extern SmErrorT sm_utils_set_boot_complete( void ); +// **************************************************************************** + +// **************************************************************************** +// Utils - Indicate Degraded +// ========================= +extern SmErrorT sm_utils_indicate_degraded( void ); +// **************************************************************************** + +// **************************************************************************** +// Utils - Clear Degraded +// ====================== +extern SmErrorT sm_utils_clear_degraded( void ); +// **************************************************************************** + +// **************************************************************************** +// Utils - Watchdog Heartbeat +// ========================== +extern void sm_utils_watchdog_heartbeat( void ); +// **************************************************************************** + +// **************************************************************************** +// Utils - Watchdog Delayed +// ========================= +extern bool sm_utils_watchdog_delayed( int max_delay_secs ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_UTILS_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_uuid.c b/service-mgmt/sm-common-1.0.0/src/sm_uuid.c new file mode 100644 index 00000000..657fe260 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_uuid.c @@ -0,0 +1,43 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_uuid.h" + +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" + +// **************************************************************************** +// Universally Unique Identifier - Create +// ====================================== +void sm_uuid_create( SmUuidT uuid ) +{ + uuid_t uu; + + memset( uuid, 0, sizeof(SmUuidT) ); + uuid_generate( uu ); + uuid_unparse_lower( uu, uuid ); +} +// **************************************************************************** + +// **************************************************************************** +// Universally Unique Identifier - Initialize +// ========================================== +SmErrorT sm_uuid_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Universally Unique Identifier - Finalize +// ======================================== +SmErrorT sm_uuid_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_uuid.h b/service-mgmt/sm-common-1.0.0/src/sm_uuid.h new file mode 100644 index 00000000..7e391616 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_uuid.h @@ -0,0 +1,42 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_UUID_H__ +#define __SM_UUID_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_UUID_MAX_CHAR 42 + +typedef char SmUuidT[SM_UUID_MAX_CHAR]; +typedef char* SmUuidPtrT; + +// **************************************************************************** +// Universally Unique Identifier - Create +// ====================================== +extern void sm_uuid_create( SmUuidT uuid ); +// **************************************************************************** + +// **************************************************************************** +// Universally Unique Identifier - Initialize +// ========================================== +extern SmErrorT sm_uuid_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Universally Unique Identifier - Finalize +// ======================================== +extern SmErrorT sm_uuid_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_UUID_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_watchdog_main.c b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_main.c new file mode 100644 index 00000000..c9b807d9 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_main.c @@ -0,0 +1,49 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_watchdog_process.h" + +// **************************************************************************** +// Main - Thread +// ============= +int main( int argc, char *argv[], char *envp[] ) +{ + SmErrorT error; + + error = sm_debug_initialize(); + if( SM_OKAY != error ) + { + printf( "Debug initialization failed, error=%s.\n", + sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + error = sm_watchdog_process_main( argc, argv, envp ); + if( SM_OKAY != error ) + { + printf( "Process failure, error=%s.\n", sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + error = sm_debug_finalize(); + if( SM_OKAY != error ) + { + printf( "Debug finalization failed, error=%s.\n", + sm_error_str( error ) ); + } + + return( EXIT_SUCCESS ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_watchdog_module.c b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_module.c new file mode 100644 index 00000000..b489faac --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_module.c @@ -0,0 +1,247 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_watchdog_module.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_list.h" +#include "sm_timer.h" +#include "sm_debug.h" + +#define SM_WATCHDOG_MODULE_FILENAME_MAX_SIZE 128 +#define SM_WATCHDOG_MODULE_PATH "/var/lib/sm/watchdog/modules" +#define SM_WATCHDOG_MODULE_DO_CHECK_FUNC "sm_watchdog_module_do_check" +#define SM_WATCHDOG_MODULE_INITIALIZE_FUNC "sm_watchdog_module_initialize" +#define SM_WATCHDOG_MODULE_FINALIZE_FUNC "sm_watchdog_module_finalize" + +typedef void (*SmWatchdogModuleDoCheckT) (void); +typedef bool (*SmWatchdogModuleInitializeT) (int* do_check_in_ms); +typedef bool (*SmWatchdogModuleFinalizeT) (void); + +typedef struct +{ + gchar filename[SM_WATCHDOG_MODULE_FILENAME_MAX_SIZE]; + GModule* glibmod; + int do_check_in_ms; + SmTimerIdT do_check_timer_id; + SmWatchdogModuleDoCheckT do_check; + SmWatchdogModuleInitializeT initialize; + SmWatchdogModuleFinalizeT finalize; +} SmWatchdogModuleT; + +static SmListT* _modules = NULL; + +// **************************************************************************** +// Watchdog Module - Do Check Timer +// ================================ +static bool sm_watchdog_module_do_check_timer( SmTimerIdT timer_id, + int64_t user_data ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmWatchdogModuleT* module = NULL; + + SM_LIST_FOREACH( _modules, entry, entry_data ) + { + module = (SmWatchdogModuleT*) entry_data; + if( NULL == module ) + { + continue; + } + + if( timer_id == module->do_check_timer_id ) + { + DPRINTFD( "Found do-check timer for module (%s).", + g_module_name(module->glibmod) ); + break; + } + } + + if( NULL != module ) + { + if( NULL != module->do_check ) + { + DPRINTFD( "Calling do-check for module (%s).", + g_module_name(module->glibmod) ); + module->do_check(); + return( true ); + } + } else { + DPRINTFE( "Module not found for do-check timer." ); + } + + return( false ); +} +// **************************************************************************** + +// *************************************************************************** +// Watchdog Module - Load +// ====================== +static SmErrorT sm_watchdog_module_load( const gchar* filename ) +{ + gchar* filepath; + SmWatchdogModuleT* module; + + module = (SmWatchdogModuleT*) malloc( sizeof(SmWatchdogModuleT) ); + if( NULL == module ) + { + DPRINTFE( "Failed to allocate watchdog module." ); + return( SM_FAILED ); + } + + memset( module, 0, sizeof(SmWatchdogModuleT) ); + + g_snprintf(module->filename, SM_WATCHDOG_MODULE_FILENAME_MAX_SIZE, + "%s", filename); + + filepath = g_module_build_path( SM_WATCHDOG_MODULE_PATH, filename ); + + module->glibmod = g_module_open( filepath, G_MODULE_BIND_LAZY ); + if( NULL == module->glibmod ) + { + DPRINTFE( "Failed to open module (%s).", filepath ); + free( module ); + g_free( filepath ); + return( SM_FAILED ); + } + + g_free( filepath ); + + g_module_symbol( module->glibmod, SM_WATCHDOG_MODULE_INITIALIZE_FUNC, + (gpointer*) &(module->initialize) ); + + g_module_symbol( module->glibmod, SM_WATCHDOG_MODULE_FINALIZE_FUNC, + (gpointer*) &(module->finalize) ); + + g_module_symbol( module->glibmod, SM_WATCHDOG_MODULE_DO_CHECK_FUNC, + (gpointer*) &(module->do_check) ); + + SM_LIST_PREPEND( _modules, (SmListEntryDataPtrT) module ); + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Watchdog Module - Load All +// ========================== +SmErrorT sm_watchdog_module_load_all( void ) +{ + const gchar* file; + GDir* directory; + GError* g_error; + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmWatchdogModuleT* module; + SmErrorT error; + + directory = g_dir_open( SM_WATCHDOG_MODULE_PATH, 0, &g_error ); + if( NULL == directory ) + { + DPRINTFE( "Failed to open directory( %s), error=%s", + SM_WATCHDOG_MODULE_PATH, g_error->message ); + g_error_free( g_error ); + return( SM_FAILED ); + } + + file = g_dir_read_name( directory ); + while( NULL != file ) + { + DPRINTFI( "Loading module (%s).", file ); + + error = sm_watchdog_module_load( file ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to load module (%s), error=%s.", + file, sm_error_str(error) ); + } + + file = g_dir_read_name( directory ); + } + + g_dir_close( directory ); + + SM_LIST_FOREACH( _modules, entry, entry_data ) + { + module = (SmWatchdogModuleT*) entry_data; + if( NULL == module ) + { + continue; + } + + if( NULL != module->initialize ) + { + DPRINTFI( "Initializing module (%s).", + g_module_name(module->glibmod) ); + + if( !(module->initialize( &(module->do_check_in_ms) )) ) + { + DPRINTFE( "Failed to initialize %s.", + g_module_name(module->glibmod) ); + return( SM_FAILED ); + } + + error = sm_timer_register( module->filename, + module->do_check_in_ms, + sm_watchdog_module_do_check_timer, + 0, &(module->do_check_timer_id) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create module (%s) do-check timer, " + "error=%s.", g_module_name(module->glibmod), + sm_error_str( error ) ); + return( error ); + } + } + } + + return( SM_OKAY ); +} +// *************************************************************************** + +// *************************************************************************** +// Watchdog Module - Unload All +// ============================ +SmErrorT sm_watchdog_module_unload_all( void ) +{ + SmListT* entry = NULL; + SmListEntryDataPtrT entry_data; + SmWatchdogModuleT* module; + + SM_LIST_FOREACH( _modules, entry, entry_data ) + { + module = (SmWatchdogModuleT*) entry_data; + if( NULL == module ) + { + continue; + } + + if( NULL != module->finalize ) + { + DPRINTFI( "Finalizing module (%s).", + g_module_name(module->glibmod) ); + + if( !(module->finalize()) ) + { + DPRINTFE( "Failed to finalize %s.", + g_module_name(module->glibmod) ); + } + } + + g_module_close( module->glibmod ); + } + + SM_LIST_CLEANUP_ALL( _modules ); + + return( SM_OKAY ); +} +// *************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_watchdog_module.h b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_module.h new file mode 100644 index 00000000..acd7f997 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_module.h @@ -0,0 +1,31 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_WATCHDOG_MODULE_H__ +#define __SM_WATCHDOG_MODULE_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Watchdog Module - Load All +// ========================== +extern SmErrorT sm_watchdog_module_load_all( void ); +// **************************************************************************** + +// **************************************************************************** +// Watchdog Module - Unload All +// ============================ +extern SmErrorT sm_watchdog_module_unload_all( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_WATCHDOG_MODULE_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_watchdog_nfs.c b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_nfs.c new file mode 100644 index 00000000..db085999 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_nfs.c @@ -0,0 +1,608 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_watchdog_nfs.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_time.h" +#include "sm_debug.h" +#include "sm_node_utils.h" +#include "sm_node_stats.h" + +#define SM_WATCHDOG_NFS_THREAD_NAME "(nfsd)" +#define SM_WATCHDOG_NFS_REBOOT_INPROGRESS 0xA5A5A5A5 +#define SM_WATCHDOG_NFS_MAX_BLOCKED_THREADS 32 +#define SM_WATCHDOG_NFS_CHECK_IN_MS 10000 +#define SM_WATCHDOG_NFS_MAX_UNINTERRUPTIBLE_SLEEP 60000 +#define SM_WATCHDOG_NFS_DELAY_REBOOT_IN_MS 60000 +#define SM_WATCHDOG_NFS_DELAY_REBOOT_FORCE_IN_MS 480000 +#define SM_WATCHDOG_NFS_DEBUG_FILE "/var/log/nfs.debug" + +typedef struct +{ + bool inuse; + bool stale; + int pid; + SmTimeT timestamp; + SmNodeProcessStatusT status; +} SmWatchDogNfsBlockedInfoT; + +static uint32_t _nfs_reboot_inprogress; + +static SmWatchDogNfsBlockedInfoT + _nfs_blocked_threads[SM_WATCHDOG_NFS_MAX_BLOCKED_THREADS]; + +// **************************************************************************** +// Watchdog NFS - Find Blocked Thread +// ================================== +static SmWatchDogNfsBlockedInfoT* sm_watchdog_nfs_find_blocked_thread( int pid ) +{ + SmWatchDogNfsBlockedInfoT* entry; + + int thread_i; + for( thread_i=0; SM_WATCHDOG_NFS_MAX_BLOCKED_THREADS > thread_i; + ++thread_i ) + { + entry = &(_nfs_blocked_threads[thread_i]); + + if( entry->inuse ) + { + if( pid == entry->pid ) + { + return( entry ); + } + } + } + + return( NULL ); +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Add Blocked Thread +// ================================= +static void sm_watchdog_nfs_add_blocked_thread( int pid, + SmNodeProcessStatusT* status ) +{ + SmWatchDogNfsBlockedInfoT* entry; + + int thread_i; + for( thread_i=0; SM_WATCHDOG_NFS_MAX_BLOCKED_THREADS > thread_i; + ++thread_i ) + { + entry = &(_nfs_blocked_threads[thread_i]); + + if( !(entry->inuse) ) + { + entry->inuse = true; + entry->stale = false; + entry->pid = pid; + sm_time_get( &(entry->timestamp) ); + memcpy( &(entry->status), status, sizeof(SmNodeProcessStatusT) ); + return; + } + } + + DPRINTFE( "Not enough room for all the NFS blocked threads." ); +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Delete Blocked Thread +// ==================================== +static void sm_watchdog_nfs_delete_blocked_thread( int pid ) +{ + SmWatchDogNfsBlockedInfoT* entry; + + entry = sm_watchdog_nfs_find_blocked_thread( pid ); + if( NULL != entry ) + { + memset( entry, 0, sizeof(SmWatchDogNfsBlockedInfoT) ); + entry->inuse = false; + } +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Do Reboot +// ======================== +static void sm_watchdog_nfs_do_reboot( void ) +{ + char cmd[2048]; + pid_t reboot_pid; + pid_t reboot_force_pid; + pid_t sm_troubleshoot_pid; + pid_t collect_pid; + SmWatchDogNfsBlockedInfoT* entry; + SmErrorT error; + + if( SM_WATCHDOG_NFS_REBOOT_INPROGRESS == _nfs_reboot_inprogress ) + { + DPRINTFD( "Reboot already inprogress." ); + return; + } + + // Fork child to do the reboot. + reboot_pid = fork(); + if( 0 > reboot_pid ) + { + DPRINTFE( "Failed to fork process for reboot, error=%s.", + strerror( errno ) ); + return; + + } else if( 0 == reboot_pid ) { + // Child process. + long ms_expired; + char reboot_cmd[] = "reboot"; + char* reboot_argv[] = {reboot_cmd, NULL}; + char* reboot_env[] = {NULL}; + struct rlimit file_limits; + SmTimeT timestamp; + + setpgid( 0, 0 ); + + if( 0 == getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + unsigned int fd_i; + for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i ) + { + close( fd_i ); + } + + open( "/dev/null", O_RDONLY ); // stdin + open( "/dev/null", O_WRONLY ); // stdout + open( "/dev/null", O_WRONLY ); // stderr + } + + sm_time_get( ×tamp ); + + while( true ) + { + ms_expired = sm_time_get_elapsed_ms( ×tamp ); + if( SM_WATCHDOG_NFS_DELAY_REBOOT_IN_MS < ms_expired ) + { + break; + } + + sleep( 10 ); // 10 seconds + } + + execve( "/sbin/reboot", reboot_argv, reboot_env ); + + // Shouldn't get this far, else there was an error. + exit(-1); + } + + // Fork child to do reboot force. + reboot_force_pid = fork(); + if( 0 > reboot_force_pid ) + { + DPRINTFE( "Failed to fork process for reboot escalation, " + "error=%s.", strerror( errno ) ); + return; + + } else if( 0 == reboot_force_pid ) { + // Child process. + long ms_expired; + int sysrq_handler_fd; + int sysrq_tigger_fd; + struct rlimit file_limits; + SmTimeT timestamp; + + setpgid( 0, 0 ); + + if( 0 == getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + unsigned int fd_i; + for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i ) + { + close( fd_i ); + } + + open( "/dev/null", O_RDONLY ); // stdin + open( "/dev/null", O_WRONLY ); // stdout + open( "/dev/null", O_WRONLY ); // stderr + } + + sm_time_get( ×tamp ); + + while( true ) + { + ms_expired = sm_time_get_elapsed_ms( ×tamp ); + if( SM_WATCHDOG_NFS_DELAY_REBOOT_FORCE_IN_MS < ms_expired ) + { + break; + } + + sleep( 10 ); // 10 seconds + } + + // Enable sysrq handling. + sysrq_handler_fd = open( "/proc/sys/kernel/sysrq", O_RDWR | O_CLOEXEC ); + if( 0 > sysrq_handler_fd ) + { + return; + } + + write( sysrq_handler_fd, "1", 1 ); + close( sysrq_handler_fd ); + + // Trigger sysrq command. + sysrq_tigger_fd = open( "/proc/sysrq-trigger", O_RDWR | O_CLOEXEC ); + if( 0 > sysrq_tigger_fd ) + { + return; + } + + write( sysrq_tigger_fd, "b", 1 ); + close( sysrq_tigger_fd ); + + exit( EXIT_SUCCESS ); + } + + _nfs_reboot_inprogress = SM_WATCHDOG_NFS_REBOOT_INPROGRESS; + + // Fork child to do the sm-troubleshoot. + sm_troubleshoot_pid = fork(); + if( 0 > sm_troubleshoot_pid ) + { + DPRINTFE( "Failed to fork process for sm-trouble, error=%s.", + strerror( errno ) ); + + } else if( 0 == sm_troubleshoot_pid ) { + // Child process. + char cmd[] = "sm-troubleshoot"; + char log_file[] = SM_TROUBLESHOOT_LOG_FILE; + char* argv[] = {cmd, log_file, NULL}; + char* env[] = {NULL}; + struct rlimit file_limits; + + setpgid( 0, 0 ); + + if( 0 == getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + unsigned int fd_i; + for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i ) + { + close( fd_i ); + } + + open( "/dev/null", O_RDONLY ); // stdin + open( "/dev/null", O_WRONLY ); // stdout + open( "/dev/null", O_WRONLY ); // stderr + } + + execve( SM_TROUBLESHOOT_SCRIPT, argv, env ); + + // Shouldn't get this far, else there was an error. + exit(-1); + } + + // Fork child to run collect. + collect_pid = fork(); + if( 0 > collect_pid ) + { + DPRINTFE( "Failed to fork process for collect, error=%s.", + strerror( errno ) ); + + } else if( 0 == collect_pid ) { + // Child process. + char cmd[] = "collect"; + char* argv[] = {cmd, NULL}; + char* env[] = {NULL}; + struct rlimit file_limits; + + setpgid( 0, 0 ); + + if( 0 == getrlimit( RLIMIT_NOFILE, &file_limits ) ) + { + unsigned int fd_i; + for( fd_i=0; fd_i < file_limits.rlim_cur; ++fd_i ) + { + close( fd_i ); + } + + open( "/dev/null", O_RDONLY ); // stdin + open( "/dev/null", O_WRONLY ); // stdout + open( "/dev/null", O_WRONLY ); // stderr + } + + execve( "/usr/local/sbin/collect", argv, env ); + + // Shouldn't get this far, else there was an error. + exit(-1); + } + + error = sm_node_utils_set_unhealthy(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set node unhealthy, error=%s.", + sm_error_str(error) ); + } + + DPRINTFI( "*******************************************************" ); + DPRINTFI( "** Issuing a reboot of the system, NFS hang detected **" ); + DPRINTFI( "*******************************************************" ); + + DPRINTFI( "Reboot (%i) process created.", (int) reboot_pid ); + DPRINTFI( "Reboot force (%i) process created.", (int) reboot_force_pid ); + DPRINTFI( "SM troubleshoot (%i) process created.", (int) sm_troubleshoot_pid ); + DPRINTFI( "Collect (%i) process created.", (int) collect_pid ); + + snprintf( cmd, sizeof(cmd), + "date >> %s; " + "echo \"*******************************************\" >> %s; " + "echo \"NFS HANG DETECTED\" >> %s", SM_WATCHDOG_NFS_DEBUG_FILE, + SM_WATCHDOG_NFS_DEBUG_FILE, SM_WATCHDOG_NFS_DEBUG_FILE ); + system( cmd ); + + int thread_i; + for( thread_i=0; SM_WATCHDOG_NFS_MAX_BLOCKED_THREADS > thread_i; + ++thread_i ) + { + entry = &(_nfs_blocked_threads[thread_i]); + + if( entry->inuse ) + { + snprintf( cmd, sizeof(cmd), + "date >> %s; " + "echo \"cat /proc/%i/sched\" >> %s; " + "cat /proc/%i/sched >> %s", SM_WATCHDOG_NFS_DEBUG_FILE, + entry->pid, SM_WATCHDOG_NFS_DEBUG_FILE, entry->pid, + SM_WATCHDOG_NFS_DEBUG_FILE ); + system( cmd ); + + snprintf( cmd, sizeof(cmd), + "date >> %s; " + "echo \"cat /proc/%i/stack\" >> %s; " + "cat /proc/%i/stack >> %s", SM_WATCHDOG_NFS_DEBUG_FILE, + entry->pid, SM_WATCHDOG_NFS_DEBUG_FILE, entry->pid, + SM_WATCHDOG_NFS_DEBUG_FILE ); + system( cmd ); + } + } + + snprintf( cmd, sizeof(cmd), + "echo \"*******************************************\" >> %s", + SM_WATCHDOG_NFS_DEBUG_FILE ); + system( cmd ); +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Search +// ===================== +static void sm_watchdog_nfs_search( const char dir_name[] ) +{ + bool is_dir; + DIR* dir; + char path[PATH_MAX]; + int path_len; + SmNodeProcessStatusT status; + SmErrorT error; + + dir = opendir( dir_name ); + if( NULL == dir ) + { + DPRINTFE( "Failed to open directory (%s), error=%s.", dir_name, + strerror( errno ) ); + return; + } + + struct dirent* entry; + for( entry = readdir( dir ); NULL != entry; entry = readdir( dir ) ) + { + is_dir = false; + + path_len = snprintf( path, sizeof(path), "%s/%s", dir_name, + entry->d_name ); + if( PATH_MAX <= path_len ) + { + DPRINTFE( "Path (%s/%s) is too long, max_len=%i.", + dir_name, entry->d_name, path_len ); + break; + } + + if( 0 != (DT_REG & entry->d_type) ) + { + if( '.' != entry->d_name[0] ) + { + struct stat stat_data; + + if( 0 > lstat( path, &stat_data ) ) + { + DPRINTFE( "Stat on (%s) failed, error=%s.", entry->d_name, + strerror( errno ) ); + continue; + } + + is_dir = S_ISDIR( stat_data.st_mode ); + } + } else if( 0 != (DT_DIR & entry->d_type) ) { + if(( 0 != strcmp( ".", entry->d_name ) )&& + ( 0 != strcmp( "..", entry->d_name ) )) + { + is_dir = true; + } + } + + if( is_dir ) + { + long val; + char* end; + + val = strtol( entry->d_name, &end, 10 ); + if(( ERANGE == errno )&& + (( LONG_MIN == val ) ||( LONG_MAX == val ))) + { + DPRINTFD( "Directory (%s) name out of range.", + entry->d_name ); + continue; + } + + if( end == entry->d_name ) + { + DPRINTFD( "Directory (%s) is not a pid directory.", + entry->d_name ); + continue; + } + + error = sm_node_stats_get_process_status( val, &status ); + if( SM_OKAY != error ) + { + if( SM_NOT_FOUND == error ) + { + DPRINTFD( "Failed to get %ld pid status, error=%s.", + val, sm_error_str(error) ); + } else { + DPRINTFE( "Failed to get %ld pid status, error=%s.", + val, sm_error_str(error) ); + } + continue; + } + + DPRINTFD( "Looking at pid=%i, name=%s", status.pid, status.name ); + + if( 0 != strcmp( SM_WATCHDOG_NFS_THREAD_NAME, status.name ) ) + { + DPRINTFD( "Process (%s) not an nfs thread, pid=%i.", + status.name, status.pid ); + continue; + } + + DPRINTFD( "NFS thread, pid=%i, state=%c, block_start_ns=%lld.", + status.pid, status.state, status.block_start_ns ); + + if(( 0 != status.block_start_ns )&&( 'D' == status.state )) + { + SmWatchDogNfsBlockedInfoT* entry; + + entry = sm_watchdog_nfs_find_blocked_thread( (int) val ); + if( NULL == entry ) + { + sm_watchdog_nfs_add_blocked_thread( (int) val, &status ); + + } else if( status.block_start_ns == entry->status.block_start_ns ) { + long ms_expired; + + entry->stale = false; + ms_expired = sm_time_get_elapsed_ms( &(entry->timestamp) ); + if( SM_WATCHDOG_NFS_MAX_UNINTERRUPTIBLE_SLEEP < ms_expired ) + { + sm_watchdog_nfs_do_reboot(); + DPRINTFI( "Rebooting stuck nfs thread (%i).", + (int) val ); + break; + } else { + if( (SM_WATCHDOG_NFS_MAX_UNINTERRUPTIBLE_SLEEP/2) + < ms_expired ) + { + DPRINTFI( "WARNING: NFS thread, pid=%i, state=%c, " + "block_start_ns=%lld, elapsed_ms=%ld.", + status.pid, status.state, + status.block_start_ns, ms_expired ); + } + } + } else { + sm_watchdog_nfs_delete_blocked_thread( (int) val ); + sm_watchdog_nfs_add_blocked_thread( (int) val, &status ); + } + } else { + sm_watchdog_nfs_delete_blocked_thread( (int) val ); + } + } + } + + closedir( dir ); +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Do Check +// ======================= +void sm_watchdog_module_do_check( void ) +{ + DPRINTFD( "NFS do check called." ); + + if( SM_WATCHDOG_NFS_REBOOT_INPROGRESS != _nfs_reboot_inprogress ) + { + int thread_i; + SmWatchDogNfsBlockedInfoT* entry; + + // Mark entries as stale. + for( thread_i=0; SM_WATCHDOG_NFS_MAX_BLOCKED_THREADS > thread_i; + ++thread_i ) + { + entry = &(_nfs_blocked_threads[thread_i]); + + if( entry->inuse ) + { + entry->stale = true; + } + } + + // Audit NFS threads. + sm_watchdog_nfs_search( "/proc" ); + + // Cleanup stale entries. + for( thread_i=0; SM_WATCHDOG_NFS_MAX_BLOCKED_THREADS > thread_i; + ++thread_i ) + { + entry = &(_nfs_blocked_threads[thread_i]); + + if(( entry->inuse )&&( entry->stale )) + { + memset( entry, 0, sizeof(SmWatchDogNfsBlockedInfoT) ); + entry->inuse = false; + } + } + } else { + DPRINTFD( "Reboot inprogress." ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Initialize +// ========================= +bool sm_watchdog_module_initialize( int* do_check_in_ms ) +{ + *do_check_in_ms = SM_WATCHDOG_NFS_CHECK_IN_MS; + _nfs_reboot_inprogress = 0; + memset( &_nfs_blocked_threads, 0, sizeof(_nfs_blocked_threads) ); + return( true ); +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Finalize +// ======================= +bool sm_watchdog_module_finalize( void ) +{ + _nfs_reboot_inprogress = 0; + memset( &_nfs_blocked_threads, 0, sizeof(_nfs_blocked_threads) ); + return( true ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_watchdog_nfs.h b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_nfs.h new file mode 100644 index 00000000..cd80d43b --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_nfs.h @@ -0,0 +1,37 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_WATCHDOG_NFS_H__ +#define __SM_WATCHDOG_NFS_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Watchdog NFS - Do Check +// ======================= +extern void sm_watchdog_module_do_check( void ); +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Initialize +// ========================= +extern bool sm_watchdog_module_initialize( int* do_check_in_ms ); +// **************************************************************************** + +// **************************************************************************** +// Watchdog NFS - Finalize +// ======================= +extern bool sm_watchdog_module_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_WATCHDOG_NFS_H__ diff --git a/service-mgmt/sm-common-1.0.0/src/sm_watchdog_process.c b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_process.c new file mode 100644 index 00000000..b252483b --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_process.c @@ -0,0 +1,241 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_watchdog_process.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_utils.h" +#include "sm_selobj.h" +#include "sm_time.h" +#include "sm_timer.h" +#include "sm_node_stats.h" +#include "sm_watchdog_module.h" + +#define SM_WATCHDOG_PROCESS_TICK_INTERVAL_IN_MS 1000 + +static sig_atomic_t _stay_on = 1; + +// **************************************************************************** +// Watchdog Process - Signal Handler +// ================================= +static void sm_watchdog_process_signal_handler( int signum ) +{ + switch( signum ) + { + case SIGINT: + case SIGTERM: + case SIGQUIT: + _stay_on = 0; + break; + + case SIGCONT: + DPRINTFD( "Ignoring signal SIGCONT (%i).", signum ); + break; + + default: + DPRINTFD( "Signal (%i) ignored.", signum ); + break; + } +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog Process - Setup Signal Handler +// ======================================= +static void sm_watchdog_process_setup_signal_handler( void ) +{ + struct sigaction sa; + + memset( &sa, 0, sizeof(sa) ); + sa.sa_handler = sm_watchdog_process_signal_handler; + + sigaction( SIGINT, &sa, NULL ); + sigaction( SIGTERM, &sa, NULL ); + sigaction( SIGQUIT, &sa, NULL ); + sigaction( SIGCONT, &sa, NULL ); + + signal( SIGCHLD, SIG_IGN ); +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog Process - Initialize +// ============================= +static SmErrorT sm_watchdog_process_initialize( void ) +{ + SmErrorT error; + + error = sm_selobj_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize selection object module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_timer_initialize( SM_WATCHDOG_PROCESS_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize timer module, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_node_stats_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node stats, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog Process - Finalize +// =========================== +static SmErrorT sm_watchdog_process_finalize( void ) +{ + SmErrorT error; + + error = sm_node_stats_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize node stats, error=%s.", + sm_error_str( error ) ); + } + + error = sm_timer_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize timer module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_selobj_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize selection object module, error=%s.", + sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Watchdog Process - Main +// ======================= +SmErrorT sm_watchdog_process_main( int argc, char *argv[], char *envp[] ) +{ + long ms_expired; + SmTimeT watchdog_heartbeat_time_prev; + SmErrorT error; + + sm_watchdog_process_setup_signal_handler(); + + DPRINTFI( "Starting" ); + + if( sm_utils_process_running( SM_WATCHDOG_PROCESS_PID_FILENAME ) ) + { + DPRINTFI( "Already running an instance of sm-watchdog." ); + return( SM_OKAY ); + } + + if( !sm_utils_set_pid_file( SM_WATCHDOG_PROCESS_PID_FILENAME ) ) + { + DPRINTFE( "Failed to write pid file for sm-watchdog, error=%s.", + strerror(errno) ); + return( SM_FAILED ); + } + + error = sm_watchdog_process_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed initialize process, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_watchdog_module_load_all(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed load modules, error=%s.", + sm_error_str(error) ); + return( error ); + } + + DPRINTFI( "Started." ); + + sm_time_get( &watchdog_heartbeat_time_prev ); + sm_utils_watchdog_heartbeat(); + + while( _stay_on ) + { + error = sm_selobj_dispatch( SM_WATCHDOG_PROCESS_TICK_INTERVAL_IN_MS ); + if( SM_OKAY != error ) + { + DPRINTFE( "Selection object dispatch failed, error=%s.", + sm_error_str(error) ); + break; + } + + ms_expired = sm_time_get_elapsed_ms( &watchdog_heartbeat_time_prev ); + if( SM_WATCHDOG_PROCESS_TICK_INTERVAL_IN_MS <= ms_expired ) + { + if( sm_timer_scheduling_on_time() ) + { + sm_utils_watchdog_heartbeat(); + sm_time_get( &watchdog_heartbeat_time_prev ); + } + } + } + + DPRINTFI( "Shutting down." ); + + error = sm_watchdog_module_unload_all(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed unload modules, error=%s.", + sm_error_str(error) ); + } + + error = sm_watchdog_process_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize process, error=%s.", + sm_error_str( error ) ); + } + + DPRINTFI( "Shutdown complete." ); + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-common-1.0.0/src/sm_watchdog_process.h b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_process.h new file mode 100644 index 00000000..10a97408 --- /dev/null +++ b/service-mgmt/sm-common-1.0.0/src/sm_watchdog_process.h @@ -0,0 +1,25 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_WATCHDOG_PROCESS_H__ +#define __SM_WATCHDOG_PROCESS_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// **************************************************************************** +// Watchdog Process - Main +// ======================= +extern SmErrorT sm_watchdog_process_main( int argc, char *argv[], char *envp[] ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_WATCHDOG_PROCESS_H__ diff --git a/service-mgmt/sm-db-1.0.0/LICENSE b/service-mgmt/sm-db-1.0.0/LICENSE new file mode 100644 index 00000000..d6456956 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/service-mgmt/sm-db-1.0.0/Makefile b/service-mgmt/sm-db-1.0.0/Makefile new file mode 100644 index 00000000..c9dace30 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/Makefile @@ -0,0 +1,14 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +build: + @(cd src; make build VER=$(VER) VER_MJR=$(VER_MJR)) + +install_non_bb: + @(cd src; make $@) + @(cd database; make $@) + +clean: + @( cd src; make clean ) diff --git a/service-mgmt/sm-db-1.0.0/centos/build_srpm.data b/service-mgmt/sm-db-1.0.0/centos/build_srpm.data new file mode 100644 index 00000000..998c72e2 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/centos/build_srpm.data @@ -0,0 +1,5 @@ +SRC_DIR=`pwd` +COPY_LIST="$PKG_BASE/LICENSE" +TAR_NAME=sm-db +VERSION=1.0.0 +TIS_PATCH_VER=25 diff --git a/service-mgmt/sm-db-1.0.0/centos/sm-db.spec b/service-mgmt/sm-db-1.0.0/centos/sm-db.spec new file mode 100644 index 00000000..fde5042e --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/centos/sm-db.spec @@ -0,0 +1,95 @@ +Summary: Service Management Databases +Name: sm-db +Version: 1.0.0 +Release: %{tis_patch_ver}%{?_tis_dist} +License: Apache-2.0 +Group: base +Packager: Wind River +URL: unknown +Source0: %{name}-%{version}.tar.gz +Source1: LICENSE + +BuildRequires: gcc +BuildRequires: sm-common-dev +BuildRequires: glib2-devel +BuildRequires: glibc +BuildRequires: sqlite-devel +BuildRequires: libuuid-devel + +%description +Service Managment Databases + +#%package -n sm-db-dbg +#Summary: Service Management Databases - Debugging files +#Group: devel +#Suggests: libsqlite3-dbg +#Suggests: libgcc-s-dbg(x86_64) +#Suggests: libglib-2.0-dbg(x86_64) +#Suggests: libstdc++-dbg(x86_64) +#Suggests: libc6-dbg(x86_64) +#Suggests: util-linux-libuuid-dbg +#Suggests: sm-common-dbg(x86_64) +#Recommends: sm-db = 1.0.0-r16.0 +#Provides: sm-db-dbg(x86_64) = 1.0.0-r16.0 + +#%description -n sm-db-dbg +#Service Managment Databases This package contains ELF symbols and related +#sources for debugging purposes. + +%package dev +Summary: Service Management Databases - Development files +Group: devel +Requires: %{name} = %{version}-%{release} + +%description dev +Service Managment Databases This package contains symbolic links, header +files, and related items necessary for software development. + +%prep + +%autosetup + +%build +sqlite3 database/sm.db < database/create_sm_db.sql +sqlite3 database/sm.hb.db < database/create_sm_hb_db.sql +VER=%{version} +MAJOR=`echo $VER | awk -F . '{print $1}'` +make VER=${VER} VER_MJR=$MAJOR + +%install +rm -rf $RPM_BUILD_ROOT +VER=%{version} +MAJOR=`echo $VER | awk -F . '{print $1}'` +make DEST_DIR=$RPM_BUILD_ROOT VER=$VER VER_MJR=$MAJOR install_non_bb + +%files +%license LICENSE +%defattr(-,root,root,-) +"/usr/lib64/libsm_db.so.1" +"/usr/lib64/libsm_db.so.1.0.0" +%config(noreplace)"/var/lib/sm/sm.hb.db" +%config(noreplace)"/var/lib/sm/sm.db" +"/var/lib/sm/patches/sm-patch.sql" + +#%files -n sm-db-dbg +#%defattr(-,-,-,-) +#%dir "/usr" +#%dir "/usr/lib64" +#%dir "/usr/bin" +#%dir "/usr/src" +#%dir "/usr/lib64/.debug" +#"/usr/lib64/.debug/libsm_db.so.1.0.0" +#%dir "/usr/bin/.debug" +#%dir "/usr/src/debug" +#%dir "/usr/src/debug/sm-db" +#%dir "/usr/src/debug/sm-db/1.0.0-r16" +#%dir "/usr/src/debug/sm-db/1.0.0-r16/src" +#/usr/src/debug/sm-db/1.0.0-r16/src/*.h +#/usr/src/debug/sm-db/1.0.0-r16/src/*.c + +%files dev +%defattr(-,root,root,-) +/usr/lib64/libsm_db.so +/usr/include/*.h + + diff --git a/service-mgmt/sm-db-1.0.0/database/Makefile b/service-mgmt/sm-db-1.0.0/database/Makefile new file mode 100644 index 00000000..7b227d80 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/database/Makefile @@ -0,0 +1,7 @@ +install_non_bb: + install -d ${DEST_DIR}/var/lib/sm + install -d ${DEST_DIR}/var/lib/sm/patches + install sm.hb.db ${DEST_DIR}/var/lib/sm + install sm.db ${DEST_DIR}/var/lib/sm + install -m 644 sm-patch.sql ${DEST_DIR}/var/lib/sm/patches + diff --git a/service-mgmt/sm-db-1.0.0/database/README b/service-mgmt/sm-db-1.0.0/database/README new file mode 100644 index 00000000..e06bf778 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/database/README @@ -0,0 +1,11 @@ +The SM database is generated by the corresponding SQL scripts: +create_sm_db.sql -> sm.db +create_sm_hb_db.sql -> sm.db.hb + +Instructions: +1. Update the SM excel spreadsheet (sm_database.xlsb) with your changes, +2. Update the corresponding SQL script i.e, create_sm_db.sql or create_sm_hb_db.sql: + Add proper SQL statement(s) (insert, update, delete) to the sql file. + + + diff --git a/service-mgmt/sm-db-1.0.0/database/create_sm_db.sql b/service-mgmt/sm-db-1.0.0/database/create_sm_db.sql new file mode 100644 index 00000000..dedf1838 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/database/create_sm_db.sql @@ -0,0 +1,971 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE NODES ( ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME CHAR(32), ADMINISTRATIVE_STATE CHAR(32), OPERATIONAL_STATE CHAR(32), AVAILABILITY_STATUS CHAR(32), READY_STATE CHAR(32), STATE_UUID CHAR(42)); +CREATE TABLE NODE_HISTORY ( ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME CHAR(32), ADMINISTRATIVE_STATE CHAR(32), OPERATIONAL_STATE CHAR(32), AVAILABILITY_STATUS CHAR(32), READY_STATE CHAR(32), STATE_UUID CHAR(42)); +CREATE TABLE SERVICE_DOMAIN_INTERFACES ( ID INTEGER PRIMARY KEY AUTOINCREMENT, PROVISIONED CHAR(32), SERVICE_DOMAIN CHAR(32), SERVICE_DOMAIN_INTERFACE CHAR(32), PATH_TYPE CHAR(32), AUTH_TYPE CHAR(32), AUTH_KEY CHAR(128), INTERFACE_NAME CHAR(32), INTERFACE_STATE CHAR(32), NETWORK_TYPE CHAR(32), NETWORK_MULTICAST CHAR(256), NETWORK_ADDRESS CHAR(256), NETWORK_PORT INT, NETWORK_HEARTBEAT_PORT INT, NETWORK_PEER_ADDRESS CHAR(256), NETWORK_PEER_PORT INT, NETWORK_PEER_HEARTBEAT_PORT INT , INTERFACE_CONNECT_TYPE CHAR(32) DEFAULT 'tor'); +INSERT INTO "SERVICE_DOMAIN_INTERFACES" VALUES(1,'yes','controller','management-interface','primary','none','','','','','','','','','','','','tor'); +INSERT INTO "SERVICE_DOMAIN_INTERFACES" VALUES(2,'yes','controller','oam-interface','secondary','hmac-sha512','titanium-server','','','','','','','','','','','tor'); +INSERT INTO "SERVICE_DOMAIN_INTERFACES" VALUES(3,'yes','controller','infrastructure-interface','secondary','none','','','','','','','','','','','','tor'); +CREATE TABLE SERVICE_DOMAINS ( ID INTEGER PRIMARY KEY AUTOINCREMENT, PROVISIONED CHAR(32), NAME CHAR(32), ORCHESTRATION CHAR(32), DESIGNATION CHAR(32), PREEMPT CHAR(32), PRIORITY INT, HELLO_INTERVAL INT, DEAD_INTERVAL INT, WAIT_INTERVAL INT, EXCHANGE_INTERVAL INT, STATE CHAR(32), SPLIT_BRAIN_RECOVERY CHAR(32), LEADER CHAR(32), GENERATION INT); +INSERT INTO "SERVICE_DOMAINS" VALUES(1,'yes','controller','regional','unknown','no',230,200,800,2500,2000,'initial','select-best-active','',1); +CREATE TABLE SERVICE_DOMAIN_MEMBERS ( ID INTEGER PRIMARY KEY AUTOINCREMENT, PROVISIONED CHAR(32), NAME CHAR(32), SERVICE_GROUP_NAME CHAR(32), REDUNDANCY_MODEL CHAR(32), N_ACTIVE INT, M_STANDBY INT, SERVICE_GROUP_AGGREGATE CHAR(32), ACTIVE_ONLY_IF_ACTIVE CHAR(32) ); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(1,'yes','controller','oam-services','N + M',1,1,'controller-aggregate','directory-services'); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(2,'yes','controller','controller-services','N + M',1,1,'controller-aggregate','directory-services'); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(3,'yes','controller','cloud-services','N + M',1,1,'controller-aggregate','directory-services'); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(4,'yes','controller','vim-services','N + M',1,1,'controller-aggregate','directory-services'); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(5,'yes','controller','patching-services','N + M',1,1,'',''); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(6,'yes','controller','directory-services','N',2,0,'',''); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(7,'yes','controller','web-services','N',2,0,'',''); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(8,'no','controller','storage-services','N',2,0,'',''); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(9,'no','controller','storage-monitoring-services','N + M',1,1,'',''); +CREATE TABLE SERVICE_DOMAIN_NEIGHBORS ( ID INTEGER PRIMARY KEY AUTOINCREMENT, NAME CHAR(32), SERVICE_DOMAIN CHAR(32), ORCHESTRATION CHAR(32), DESIGNATION CHAR(32), PRIORITY INT, HELLO_INTERVAL INT, DEAD_INTERVAL INT, WAIT_INTERVAL INT, EXCHANGE_INTERVAL INT, STATE CHAR(32), GENERATION INT); +CREATE TABLE SERVICE_DOMAIN_ASSIGNMENTS ( ID INTEGER PRIMARY KEY AUTOINCREMENT, UUID CHAR(42), NAME CHAR(32), NODE_NAME CHAR(32), SERVICE_GROUP_NAME CHAR(32), DESIRED_STATE CHAR(32), STATE CHAR(32), STATUS CHAR(32), CONDITION CHAR(32) ); +CREATE TABLE SERVICE_GROUPS ( ID INTEGER PRIMARY KEY AUTOINCREMENT, PROVISIONED CHAR(32), NAME CHAR(32), AUTO_RECOVER CHAR(32), CORE CHAR(32), DESIRED_STATE CHAR(32), STATE CHAR(32), STATUS CHAR(32), CONDITION CHAR(32), FAILURE_DEBOUNCE INT, FATAL_ERROR_REBOOT CHAR(32) ); +INSERT INTO "SERVICE_GROUPS" VALUES(1,'yes','oam-services','no','no','initial','initial','','',300000,'no'); +INSERT INTO "SERVICE_GROUPS" VALUES(2,'yes','controller-services','no','no','initial','initial','','',300000,'yes'); +INSERT INTO "SERVICE_GROUPS" VALUES(3,'yes','cloud-services','no','no','initial','initial','','',300000,'yes'); +INSERT INTO "SERVICE_GROUPS" VALUES(4,'yes','patching-services','no','no','initial','initial','','',300000,'no'); +INSERT INTO "SERVICE_GROUPS" VALUES(5,'yes','directory-services','no','no','initial','initial','','',300000,'no'); +INSERT INTO "SERVICE_GROUPS" VALUES(6,'yes','web-services','no','no','initial','initial','','',300000,'no'); +INSERT INTO "SERVICE_GROUPS" VALUES(7,'no','storage-services','no','no','initial','initial','','',120000,'yes'); +INSERT INTO "SERVICE_GROUPS" VALUES(8,'no','storage-monitoring-services','no','no','initial','initial','','',120000,'no'); +INSERT INTO "SERVICE_GROUPS" VALUES(9,'yes','vim-services','no','no','initial','initial','','',300000,'yes'); +CREATE TABLE SERVICE_GROUP_MEMBERS ( ID INTEGER PRIMARY KEY AUTOINCREMENT, PROVISIONED CHAR(32), NAME CHAR(32), SERVICE_NAME CHAR(32), SERVICE_FAILURE_IMPACT CHAR(32)); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(1,'yes','oam-services','oam-ip','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(2,'yes','controller-services','management-ip','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(3,'yes','controller-services','drbd-pg','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(4,'yes','controller-services','drbd-rabbit','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(5,'yes','controller-services','drbd-cgcs','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(6,'yes','controller-services','drbd-platform','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(7,'yes','controller-services','pg-fs','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(8,'yes','controller-services','rabbit-fs','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(9,'yes','controller-services','nfs-mgmt','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(10,'yes','controller-services','cgcs-fs','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(11,'yes','controller-services','platform-fs','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(12,'yes','controller-services','postgres','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(13,'yes','controller-services','rabbit','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(14,'yes','controller-services','cgcs-export-fs','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(15,'yes','controller-services','platform-export-fs','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(16,'yes','controller-services','cgcs-nfs-ip','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(17,'yes','controller-services','platform-nfs-ip','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(18,'yes','controller-services','sysinv-inv','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(19,'yes','controller-services','sysinv-conductor','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(20,'yes','controller-services','mtc-agent','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(21,'yes','controller-services','hbs-agent','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(22,'yes','controller-services','hw-mon','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(23,'yes','controller-services','dnsmasq','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(24,'yes','controller-services','fm-mgr','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(25,'yes','controller-services','snmp','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(26,'yes','cloud-services','keystone','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(27,'yes','cloud-services','glance-registry','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(28,'yes','cloud-services','glance-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(29,'yes','cloud-services','neutron-server','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(30,'yes','cloud-services','nova-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(31,'yes','cloud-services','nova-scheduler','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(32,'yes','cloud-services','nova-conductor','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(34,'yes','cloud-services','nova-console-auth','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(35,'yes','cloud-services','nova-novnc','minor'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(36,'yes','cloud-services','cinder-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(37,'yes','cloud-services','cinder-scheduler','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(38,'yes','cloud-services','cinder-volume','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(40,'yes','cloud-services','ceilometer-collector','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(41,'yes','cloud-services','ceilometer-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(44,'yes','cloud-services','ceilometer-agent-notification','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(45,'yes','cloud-services','heat-engine','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(46,'yes','cloud-services','heat-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(47,'yes','cloud-services','heat-api-cfn','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(48,'yes','cloud-services','heat-api-cloudwatch','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(49,'yes','directory-services','open-ldap','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(50,'yes','web-services','lighttpd','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(51,'yes','web-services','horizon','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(52,'yes','patching-services','patch-alarm-manager','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(53,'no','storage-services','ceph-rest-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(54,'no','storage-monitoring-services','ceph-manager','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(55,'no','controller-services','drbd-cinder','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(56,'no','controller-services','cinder-lvm','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(57,'no','controller-services','iscsi','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(58,'no','controller-services','cinder-ip','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(59,'yes','vim-services','vim','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(60,'yes','vim-services','vim-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(61,'yes','vim-services','vim-webserver','minor'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(62,'yes','controller-services','guest-agent','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(63,'yes','cloud-services','nova-api-proxy','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(64,'yes','oam-services','haproxy','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(65,'no','controller-services','pxeboot-ip','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(67,'no','storage-monitoring-services','ceph-radosgw','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(68,'yes','cloud-services','aodh-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(69,'yes','cloud-services','aodh-evaluator','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(70,'yes','cloud-services','aodh-listener','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(71,'yes','cloud-services','aodh-notifier','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(72,'yes','cloud-services','murano-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(73,'yes','cloud-services','murano-engine','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(74,'yes','controller-services','murano-rabbit','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(75,'yes','controller-services','drbd-extension','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(76,'yes','controller-services','extension-fs','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(77,'yes','controller-services','extension-export-fs','critical'); +CREATE TABLE SERVICES ( ID INTEGER PRIMARY KEY AUTOINCREMENT, PROVISIONED CHAR(32), NAME CHAR(32), DESIRED_STATE CHAR(32), STATE CHAR(32), STATUS CHAR(32), CONDITION CHAR(32), MAX_FAILURES INT, FAIL_COUNTDOWN INT, FAIL_COUNTDOWN_INTERVAL INT, MAX_ACTION_FAILURES INT, MAX_TRANSITION_FAILURES INT, PID_FILE CHAR(256) ); +INSERT INTO "SERVICES" VALUES(1,'yes','oam-ip','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(2,'yes','management-ip','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(3,'yes','drbd-pg','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(4,'yes','drbd-rabbit','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(5,'yes','drbd-cgcs','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(6,'yes','drbd-platform','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(7,'yes','pg-fs','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(8,'yes','rabbit-fs','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(9,'yes','nfs-mgmt','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(10,'yes','cgcs-fs','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(11,'yes','platform-fs','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(12,'yes','postgres','initial','initial','none','none',2,1,90000,4,16,'/var/run/postmaster.pid'); +INSERT INTO "SERVICES" VALUES(13,'yes','rabbit','initial','initial','none','none',2,1,90000,4,16,'/var/run/rabbitmq/rabbitmq.pid'); +INSERT INTO "SERVICES" VALUES(14,'yes','cgcs-export-fs','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(15,'yes','platform-export-fs','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(16,'yes','cgcs-nfs-ip','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(17,'yes','platform-nfs-ip','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(18,'yes','sysinv-inv','initial','initial','none','none',2,1,90000,4,16,'/var/run/sysinv-api.pid'); +INSERT INTO "SERVICES" VALUES(19,'yes','sysinv-conductor','initial','initial','none','none',2,1,90000,4,16,'/var/run/sysinv-conductor.pid'); +INSERT INTO "SERVICES" VALUES(20,'yes','mtc-agent','initial','initial','none','none',2,1,90000,4,16,'/var/run/mtcAgent.pid'); +INSERT INTO "SERVICES" VALUES(21,'yes','hbs-agent','initial','initial','none','none',2,1,90000,4,16,'/var/run/hbsAgent.pid'); +INSERT INTO "SERVICES" VALUES(22,'yes','hw-mon','initial','initial','none','none',2,1,90000,4,16,'/var/run/hwmond.pid'); +INSERT INTO "SERVICES" VALUES(23,'yes','dnsmasq','initial','initial','none','none',2,1,90000,4,16,'/var/run/dnsmasq.pid'); +INSERT INTO "SERVICES" VALUES(24,'yes','fm-mgr','initial','initial','none','none',2,1,90000,4,16,'/var/run/fmManager.pid'); +INSERT INTO "SERVICES" VALUES(25,'yes','keystone','initial','initial','none','none',2,1,90000,4,16,'/var/run/openstack-keystone.pid'); +INSERT INTO "SERVICES" VALUES(26,'yes','glance-registry','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/glance-registry.pid'); +INSERT INTO "SERVICES" VALUES(27,'yes','glance-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/glance-api.pid'); +INSERT INTO "SERVICES" VALUES(28,'yes','neutron-server','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/neutron-server.pid'); +INSERT INTO "SERVICES" VALUES(29,'yes','nova-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/nova-api.pid'); +INSERT INTO "SERVICES" VALUES(30,'yes','nova-scheduler','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/nova-scheduler.pid'); +INSERT INTO "SERVICES" VALUES(31,'yes','nova-conductor','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/nova-conductor.pid'); +INSERT INTO "SERVICES" VALUES(33,'yes','nova-console-auth','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/nova-console-auth.pid'); +INSERT INTO "SERVICES" VALUES(34,'yes','nova-novnc','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/nova-novnc.pid'); +INSERT INTO "SERVICES" VALUES(35,'yes','cinder-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/cinder-api.pid'); +INSERT INTO "SERVICES" VALUES(36,'yes','cinder-scheduler','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/cinder-scheduler.pid'); +INSERT INTO "SERVICES" VALUES(37,'yes','cinder-volume','initial','initial','none','none',32,16,180000,4,16,'/var/run/resource-agents/cinder-volume.pid'); +INSERT INTO "SERVICES" VALUES(39,'yes','ceilometer-collector','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/ceilometer-collector.pid'); +INSERT INTO "SERVICES" VALUES(40,'yes','ceilometer-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/ceilometer-api.pid'); +INSERT INTO "SERVICES" VALUES(43,'yes','ceilometer-agent-notification','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/ceilometer-agent-notification.pid'); +INSERT INTO "SERVICES" VALUES(44,'yes','heat-engine','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/heat-engine.pid'); +INSERT INTO "SERVICES" VALUES(45,'yes','heat-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/heat-api.pid'); +INSERT INTO "SERVICES" VALUES(46,'yes','heat-api-cfn','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/heat-api-cfn.pid'); +INSERT INTO "SERVICES" VALUES(47,'yes','heat-api-cloudwatch','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/heat-api-cloudwatch.pid'); +INSERT INTO "SERVICES" VALUES(48,'yes','open-ldap','initial','initial','none','none',2,1,90000,4,16,'/var/run/slapd.pid'); +INSERT INTO "SERVICES" VALUES(49,'yes','snmp','initial','initial','none','none',32,16,90000,4,16,'/var/run/snmpd.pid'); +INSERT INTO "SERVICES" VALUES(50,'yes','lighttpd','initial','initial','none','none',2,1,90000,4,16,'/var/run/lighttpd.pid'); +INSERT INTO "SERVICES" VALUES(51,'yes','horizon','initial','initial','none','none',2,1,90000,4,16,'/var/run/openstack-dashboard.pid'); +INSERT INTO "SERVICES" VALUES(52,'yes','patch-alarm-manager','initial','initial','none','none',2,1,90000,4,16,'/var/run/patch-alarm-manager.pid'); +INSERT INTO "SERVICES" VALUES(53,'no','ceph-rest-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/ceph/ceph-rest-api.pid'); +INSERT INTO "SERVICES" VALUES(54,'no','ceph-manager','initial','initial','none','none',2,1,90000,4,16,'/var/run/ceph/ceph-manager.pid'); +INSERT INTO "SERVICES" VALUES(55,'no','drbd-cinder','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(56,'no','cinder-lvm','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(57,'no','iscsi','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(58,'no','cinder-ip','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(59,'yes','vim','initial','initial','none','none',2,1,90000,4,16,'/var/run/nfv-vim.pid'); +INSERT INTO "SERVICES" VALUES(60,'yes','vim-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/nfv-vim-api.pid'); +INSERT INTO "SERVICES" VALUES(61,'yes','vim-webserver','initial','initial','none','none',2,1,90000,4,16,'/var/run/nfv-vim-webserver.pid'); +INSERT INTO "SERVICES" VALUES(62,'yes','guest-agent','initial','initial','none','none',2,1,90000,4,16,'/var/run/guestAgent.pid'); +INSERT INTO "SERVICES" VALUES(63,'yes','nova-api-proxy','initial','initial','none','none',2,1,90000,4,16,'/var/run/nova-api-proxy.pid'); +INSERT INTO "SERVICES" VALUES(64,'yes','haproxy','initial','initial','none','none',2,1,90000,4,16,'/var/run/haproxy.pid'); +INSERT INTO "SERVICES" VALUES(65,'no','pxeboot-ip','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(67,'no','ceph-radosgw','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(68,'yes','aodh-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/aodh-api.pid'); +INSERT INTO "SERVICES" VALUES(69,'yes','aodh-evaluator','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/aodh-evaluator.pid'); +INSERT INTO "SERVICES" VALUES(70,'yes','aodh-listener','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/aodh-listener.pid'); +INSERT INTO "SERVICES" VALUES(71,'yes','aodh-notifier','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/aodh-notifier.pid'); +INSERT INTO "SERVICES" VALUES(72,'yes','murano-api','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(73,'yes','murano-engine','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(74,'yes','murano-rabbit','initial','initial','none','none',2,1,90000,4,16,'/var/run/rabbitmq/murano-rabbit.pid'); +INSERT INTO "SERVICES" VALUES(75,'yes','drbd-extension','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(76,'yes','extension-fs','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(77,'yes','extension-export-fs','initial','initial','none','none',2,1,90000,4,16,''); +CREATE TABLE SERVICE_HEARTBEAT ( ID INTEGER PRIMARY KEY AUTOINCREMENT, PROVISIONED CHAR(32), NAME CHAR(32), TYPE CHAR(32), SRC_ADDRESS CHAR(256), SRC_PORT INT, DST_ADDRESS CHAR(256), DST_PORT INT, MESSAGE CHAR(256), INTERVAL_IN_MS INT, MISSED_WARN INT, MISSED_DEGRADE INT, MISSED_FAIL INT, STATE CHAR(32), MISSED INT, HEARTBEAT_TIMER_ID INT, HEARTBEAT_SOCKET INT ); +CREATE TABLE SERVICE_DEPENDENCY ( DEPENDENCY_TYPE CHAR(32), SERVICE_NAME CHAR(32), STATE CHAR(32), ACTION CHAR(32), DEPENDENT CHAR(32), DEPENDENT_STATE CHAR(32), PRIMARY KEY (DEPENDENCY_TYPE, SERVICE_NAME, STATE, ACTION, DEPENDENT)); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','oam-ip','not-applicable','enable','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','haproxy','not-applicable','enable','oam-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','management-ip','not-applicable','enable','open-ldap','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-pg','not-applicable','go-active','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-rabbit','not-applicable','go-active','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-cgcs','not-applicable','go-active','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-platform','not-applicable','go-active','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-extension','not-applicable','go-active','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','pg-fs','not-applicable','enable','drbd-pg','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit-fs','not-applicable','enable','drbd-rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-fs','not-applicable','enable','drbd-cgcs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','platform-fs','not-applicable','enable','drbd-platform','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','extension-fs','not-applicable','enable','drbd-extension','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','enable','pg-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','enable','rabbit-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-export-fs','not-applicable','enable','cgcs-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','platform-export-fs','not-applicable','enable','platform-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','extension-export-fs','not-applicable','enable','extension-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','enable','cgcs-export-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','platform-nfs-ip','not-applicable','enable','platform-export-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-conductor','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-conductor','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-conductor','not-applicable','enable','platform-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-inv','not-applicable','enable','sysinv-conductor','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','mtc-agent','not-applicable','enable','sysinv-inv','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','hbs-agent','not-applicable','enable','mtc-agent','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','hw-mon','not-applicable','enable','mtc-agent','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','guest-agent','not-applicable','enable','mtc-agent','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','vim','not-applicable','enable','mtc-agent','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','vim-api','not-applicable','enable','vim','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','vim-webserver','not-applicable','enable','vim','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dnsmasq','not-applicable','enable','sysinv-conductor','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','fm-mgr','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','snmp','not-applicable','enable','oam-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','snmp','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','snmp','not-applicable','enable','platform-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','keystone','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','keystone','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','keystone','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','glance-registry','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','glance-registry','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','glance-registry','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','glance-api','not-applicable','enable','glance-registry','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','neutron-server','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','neutron-server','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','neutron-server','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-scheduler','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-scheduler','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-scheduler','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-conductor','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-conductor','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-conductor','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-api','not-applicable','enable','nova-conductor','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-api-proxy','not-applicable','enable','nova-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-console-auth','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-console-auth','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-console-auth','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-novnc','not-applicable','enable','nova-console-auth','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-scheduler','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-scheduler','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-scheduler','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-volume','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-volume','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-volume','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-api','not-applicable','enable','cinder-scheduler','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-api','not-applicable','enable','cinder-volume','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceilometer-collector','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceilometer-collector','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceilometer-collector','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceilometer-api','not-applicable','enable','ceilometer-collector','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceilometer-agent-notification','not-applicable','enable','ceilometer-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-engine','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-engine','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-engine','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-api','not-applicable','enable','heat-engine','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-api-cfn','not-applicable','enable','heat-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-api-cloudwatch','not-applicable','enable','heat-api-cfn','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','horizon','not-applicable','enable','lighttpd','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceph-manager','not-applicable','enable','ceph-rest-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-cinder','not-applicable','go-active','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-lvm','not-applicable','enable','drbd-cinder','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','iscsi','not-applicable','enable','cinder-lvm','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','iscsi','not-applicable','enable','cgcs-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-ip','not-applicable','enable','iscsi','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-volume','not-applicable','enable','cinder-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','oam-ip','not-applicable','disable','haproxy','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','management-ip','not-applicable','disable','pg-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','management-ip','not-applicable','disable','rabbit-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','management-ip','not-applicable','disable','cgcs-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','management-ip','not-applicable','disable','platform-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-pg','not-applicable','go-standby','pg-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-rabbit','not-applicable','go-standby','rabbit-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-cgcs','not-applicable','go-standby','cgcs-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-platform','not-applicable','go-standby','platform-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-extension','not-applicable','go-standby','extension-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','pg-fs','not-applicable','disable','postgres','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit-fs','not-applicable','disable','rabbit','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nfs-mgmt','not-applicable','disable','cgcs-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nfs-mgmt','not-applicable','disable','platform-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-fs','not-applicable','disable','cgcs-export-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','extension-fs','not-applicable','disable','extension-export-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','keystone','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','glance-registry','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','neutron-server','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','nova-scheduler','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','nova-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','nova-console-auth','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','cinder-scheduler','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','cinder-volume','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','ceilometer-collector','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','heat-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','platform-fs','not-applicable','disable','platform-export-fs','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','snmp','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','fm-mgr','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','keystone','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','glance-registry','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','neutron-server','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','nova-scheduler','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','nova-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','nova-console-auth','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','cinder-scheduler','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','cinder-volume','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','ceilometer-collector','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','heat-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','sysinv-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','keystone','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','glance-registry','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','neutron-server','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','nova-scheduler','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','nova-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','nova-console-auth','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','cinder-scheduler','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','cinder-volume','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','ceilometer-collector','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','heat-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','sysinv-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-export-fs','not-applicable','disable','cgcs-nfs-ip','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','platform-export-fs','not-applicable','disable','platform-nfs-ip','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','platform-nfs-ip','not-applicable','disable','sysinv-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-conductor','not-applicable','disable','sysinv-inv','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-inv','not-applicable','disable','mtc-agent','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-conductor','not-applicable','disable','dnsmasq','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','mtc-agent','not-applicable','disable','hbs-agent','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','mtc-agent','not-applicable','disable','hw-mon','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','mtc-agent','not-applicable','disable','guest-agent','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','mtc-agent','not-applicable','disable','vim','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','hbs-agent','not-applicable','disable','',''); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','hw-mon','not-applicable','disable','',''); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','vim','not-applicable','disable','vim-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','vim','not-applicable','disable','vim-webserver','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dnsmasq','not-applicable','disable','',''); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','glance-registry','not-applicable','disable','glance-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-conductor','not-applicable','disable','nova-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-api','not-applicable','disable','nova-api-proxy','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-scheduler','not-applicable','disable','cinder-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-volume','not-applicable','disable','cinder-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceilometer-collector','not-applicable','disable','ceilometer-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceilometer-api','not-applicable','disable','ceilometer-agent-notification','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-engine','not-applicable','disable','heat-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-api','not-applicable','disable','heat-api-cfn','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','heat-api-cfn','not-applicable','disable','heat-api-cloudwatch','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','lighttpd','not-applicable','disable','horizon','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceph-rest-api','not-applicable','disable','ceph-manager','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-ip','not-applicable','disable','cgcs-nfs-ip','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-ip','not-applicable','disable','cinder-volume','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','iscsi','not-applicable','disable','cinder-ip','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-cgcs','not-applicable','disable','iscsi','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-lvm','not-applicable','disable','iscsi','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-cinder','not-applicable','go-standby','cinder-lvm','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-listener','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-listener','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-listener','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-api','not-applicable','enable','aodh-listener','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-notifier','not-applicable','enable','aodh-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-evaluator','not-applicable','enable','aodh-notifier','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','aodh-listener','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','aodh-listener','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','aodh-listener','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-listener','not-applicable','disable','aodh-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-api','not-applicable','disable','aodh-notifier','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','aodh-notifier','not-applicable','disable','aodh-evaluator','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceph-manager','not-applicable','disable','sysinv-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-engine','not-applicable','enable','murano-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-api','not-applicable','disable','murano-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-engine','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','murano-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-engine','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','murano-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-rabbit','not-applicable','enable','rabbit-fs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit-fs','not-applicable','disable','murano-rabbit','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-engine','not-applicable','enable','murano-rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-rabbit','not-applicable','disable','murano-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-api','not-applicable','enable','murano-rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','murano-rabbit','not-applicable','disable','murano-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','snmp','not-applicable','enable','dnsmasq','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','panko-api','not-applicable','enable','ceilometer-collector','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ceilometer-collector','not-applicable','disable','panko-api','disabled'); +CREATE TABLE SERVICE_INSTANCES ( ID INTEGER PRIMARY KEY AUTOINCREMENT, SERVICE_NAME CHAR(32), INSTANCE_NAME CHAR(32), INSTANCE_PARAMETERS CHAR(1024) ); +INSERT INTO "SERVICE_INSTANCES" VALUES(1,'lighttpd','lighttpd',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(2,'horizon','horizon',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(3,'snmp','snmp',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(4,'patch-alarm-manager','patch-alarm-manager',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(5,'hw-mon','hw-mon',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(6,'guest-agent','guest-agent',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(7,'vim','vim','config=/etc/nfv/vim/config.ini'); +INSERT INTO "SERVICE_INSTANCES" VALUES(8,'vim-api','vim-api','config=/etc/nfv/vim/config.ini'); +INSERT INTO "SERVICE_INSTANCES" VALUES(9,'vim-webserver','vim-webserver','config=/etc/nfv/vim/config.ini'); +INSERT INTO "SERVICE_INSTANCES" VALUES(10,'nova-api-proxy','nova-api-proxy',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(11,'haproxy','haproxy',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(12,'ceph-rest-api','ceph-rest-api',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(13,'ceph-manager','ceph-manager',''); +INSERT INTO "SERVICE_INSTANCES" VALUES(14,'ceph-radosgw','ceph-radosgw',''); +CREATE TABLE SERVICE_ACTIONS ( SERVICE_NAME CHAR(32), ACTION CHAR(32), PLUGIN_TYPE CHAR(32), PLUGIN_CLASS CHAR(32), PLUGIN_NAME CHAR(80), PLUGIN_COMMAND CHAR(80), PLUGIN_PARAMETERS CHAR(1024), MAX_FAILURE_RETRIES INT, MAX_TIMEOUT_RETRIES INT, MAX_TOTAL_RETRIES INT, TIMEOUT_IN_SECS INT, INTERVAL_IN_SECS INT, PRIMARY KEY (SERVICE_NAME, ACTION)); +INSERT INTO "SERVICE_ACTIONS" VALUES('oam-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('oam-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('oam-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('oam-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('management-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('management-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('management-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('management-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-pg','enable','ocf-script','linbit','drbd','start','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,90,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-pg','disable','ocf-script','linbit','drbd','stop','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-pg','go-active','ocf-script','linbit','drbd','promote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-pg','go-standby','ocf-script','linbit','drbd','demote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-pg','audit-enabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-pg','audit-disabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',0,0,0,20,28); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-rabbit','enable','ocf-script','linbit','drbd','start','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,90,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-rabbit','disable','ocf-script','linbit','drbd','stop','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-rabbit','go-active','ocf-script','linbit','drbd','promote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-rabbit','go-standby','ocf-script','linbit','drbd','demote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-rabbit','audit-enabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-rabbit','audit-disabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',0,0,0,20,28); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cgcs','enable','ocf-script','linbit','drbd','start','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,90,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cgcs','disable','ocf-script','linbit','drbd','stop','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cgcs','go-active','ocf-script','linbit','drbd','promote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cgcs','go-standby','ocf-script','linbit','drbd','demote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cgcs','audit-enabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cgcs','audit-disabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',0,0,0,20,28); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-platform','enable','ocf-script','linbit','drbd','start','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,90,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-platform','disable','ocf-script','linbit','drbd','stop','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-platform','go-active','ocf-script','linbit','drbd','promote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-platform','go-standby','ocf-script','linbit','drbd','demote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-platform','audit-enabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-platform','audit-disabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',0,0,0,20,28); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-extension','enable','ocf-script','linbit','drbd','start','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,90,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-extension','disable','ocf-script','linbit','drbd','stop','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-extension','go-active','ocf-script','linbit','drbd','promote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-extension','go-standby','ocf-script','linbit','drbd','demote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-extension','audit-enabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-extension','audit-disabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',0,0,0,20,28); +INSERT INTO "SERVICE_ACTIONS" VALUES('pg-fs','enable','ocf-script','heartbeat','Filesystem','start','',2,2,2,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('pg-fs','disable','ocf-script','heartbeat','Filesystem','stop','',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('pg-fs','audit-enabled','ocf-script','heartbeat','Filesystem','monitor','',2,2,2,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('pg-fs','audit-disabled','ocf-script','heartbeat','Filesystem','monitor','',0,0,0,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('rabbit-fs','enable','ocf-script','heartbeat','Filesystem','start','',2,2,2,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('rabbit-fs','disable','ocf-script','heartbeat','Filesystem','stop','',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('rabbit-fs','audit-enabled','ocf-script','heartbeat','Filesystem','monitor','',2,2,2,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('rabbit-fs','audit-disabled','ocf-script','heartbeat','Filesystem','monitor','',0,0,0,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('nfs-mgmt','enable','ocf-script','platform','nfsserver-mgmt','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nfs-mgmt','disable','ocf-script','platform','nfsserver-mgmt','stop','',1,1,1,130,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nfs-mgmt','audit-disabled','ocf-script','platform','nfsserver-mgmt','monitor','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-fs','enable','ocf-script','heartbeat','Filesystem','start','',2,2,2,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-fs','disable','ocf-script','heartbeat','Filesystem','stop','',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-fs','audit-enabled','ocf-script','heartbeat','Filesystem','monitor','',2,2,2,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-fs','audit-disabled','ocf-script','heartbeat','Filesystem','monitor','',0,0,0,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-fs','enable','ocf-script','heartbeat','Filesystem','start','',2,2,2,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-fs','disable','ocf-script','heartbeat','Filesystem','stop','',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-fs','audit-enabled','ocf-script','heartbeat','Filesystem','monitor','',2,2,2,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-fs','audit-disabled','ocf-script','heartbeat','Filesystem','monitor','',0,0,0,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('extension-fs','enable','ocf-script','heartbeat','Filesystem','start','',2,2,2,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('extension-fs','disable','ocf-script','heartbeat','Filesystem','stop','',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('extension-fs','audit-enabled','ocf-script','heartbeat','Filesystem','monitor','',2,2,2,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('extension-fs','audit-disabled','ocf-script','heartbeat','Filesystem','monitor','',0,0,0,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('postgres','enable','ocf-script','heartbeat','pgsql','start','',2,2,2,120,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('postgres','disable','ocf-script','heartbeat','pgsql','stop','',1,1,1,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('postgres','audit-enabled','ocf-script','heartbeat','pgsql','monitor','',2,2,2,60,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('postgres','audit-disabled','ocf-script','heartbeat','pgsql','monitor','',0,0,0,60,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('rabbit','enable','ocf-script','rabbitmq','rabbitmq-server','start','',2,2,2,60,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('rabbit','disable','ocf-script','rabbitmq','rabbitmq-server','stop','',1,1,1,60,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('rabbit','audit-enabled','ocf-script','rabbitmq','rabbitmq-server','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('rabbit','audit-disabled','ocf-script','rabbitmq','rabbitmq-server','monitor','',0,0,0,15,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-export-fs','enable','ocf-script','heartbeat','exportfs','start','',2,2,2,40,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-export-fs','disable','ocf-script','heartbeat','exportfs','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-export-fs','audit-enabled','ocf-script','heartbeat','exportfs','monitor','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-export-fs','audit-disabled','ocf-script','heartbeat','exportfs','monitor','',0,0,0,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-export-fs','enable','ocf-script','heartbeat','exportfs','start','',2,2,2,40,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-export-fs','disable','ocf-script','heartbeat','exportfs','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-export-fs','audit-enabled','ocf-script','heartbeat','exportfs','monitor','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-export-fs','audit-disabled','ocf-script','heartbeat','exportfs','monitor','',0,0,0,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('extension-export-fs','enable','ocf-script','heartbeat','exportfs','start','',2,2,2,40,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('extension-export-fs','disable','ocf-script','heartbeat','exportfs','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('extension-export-fs','audit-enabled','ocf-script','heartbeat','exportfs','monitor','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('extension-export-fs','audit-disabled','ocf-script','heartbeat','exportfs','monitor','',0,0,0,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-nfs-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-nfs-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-nfs-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('cgcs-nfs-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-nfs-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-nfs-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-nfs-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('platform-nfs-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('sysinv-inv','enable','ocf-script','platform','sysinv-api','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('sysinv-inv','disable','ocf-script','platform','sysinv-api','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('sysinv-inv','audit-enabled','ocf-script','platform','sysinv-api','monitor','',2,2,2,40,90); +INSERT INTO "SERVICE_ACTIONS" VALUES('sysinv-inv','audit-disabled','ocf-script','platform','sysinv-api','monitor','',0,0,0,40,90); +INSERT INTO "SERVICE_ACTIONS" VALUES('sysinv-conductor','enable','ocf-script','platform','sysinv-conductor','start','',2,2,2,30,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('sysinv-conductor','disable','ocf-script','platform','sysinv-conductor','stop','timeout=60000',1,1,1,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('sysinv-conductor','audit-enabled','ocf-script','platform','sysinv-conductor','monitor','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('sysinv-conductor','audit-disabled','ocf-script','platform','sysinv-conductor','monitor','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('mtc-agent','enable','ocf-script','platform','mtcAgent','start','',2,2,2,30,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('mtc-agent','disable','ocf-script','platform','mtcAgent','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('mtc-agent','audit-enabled','ocf-script','platform','mtcAgent','monitor','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('mtc-agent','audit-disabled','ocf-script','platform','mtcAgent','monitor','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('hbs-agent','enable','ocf-script','platform','hbsAgent','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('hbs-agent','disable','ocf-script','platform','hbsAgent','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('hbs-agent','audit-enabled','ocf-script','platform','hbsAgent','monitor','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('hbs-agent','audit-disabled','ocf-script','platform','hbsAgent','monitor','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('hw-mon','enable','ocf-script','platform','hwmon','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('hw-mon','disable','ocf-script','platform','hwmon','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('hw-mon','audit-enabled','ocf-script','platform','hwmon','monitor','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('hw-mon','audit-disabled','ocf-script','platform','hwmon','monitor','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('dnsmasq','enable','lsb-script','','dnsmasq','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dnsmasq','disable','lsb-script','','dnsmasq','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dnsmasq','audit-enabled','lsb-script','','dnsmasq','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('dnsmasq','audit-disabled','lsb-script','','dnsmasq','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('fm-mgr','enable','lsb-script','','fminit','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('fm-mgr','disable','lsb-script','','fminit','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('fm-mgr','audit-enabled','lsb-script','','fminit','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('fm-mgr','audit-disabled','lsb-script','','fminit','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('keystone','enable','ocf-script','openstack','keystone','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('keystone','disable','ocf-script','openstack','keystone','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('keystone','audit-enabled','ocf-script','openstack','keystone','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('keystone','audit-disabled','ocf-script','openstack','keystone','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('glance-registry','enable','ocf-script','openstack','glance-registry','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('glance-registry','disable','ocf-script','openstack','glance-registry','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('glance-registry','audit-enabled','ocf-script','openstack','glance-registry','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('glance-registry','audit-disabled','ocf-script','openstack','glance-registry','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('glance-api','enable','ocf-script','openstack','glance-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('glance-api','disable','ocf-script','openstack','glance-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('glance-api','audit-enabled','ocf-script','openstack','glance-api','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('glance-api','audit-disabled','ocf-script','openstack','glance-api','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('neutron-server','enable','ocf-script','openstack','neutron-server','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('neutron-server','disable','ocf-script','openstack','neutron-server','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('neutron-server','audit-enabled','ocf-script','openstack','neutron-server','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('neutron-server','audit-disabled','ocf-script','openstack','neutron-server','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-api','enable','ocf-script','openstack','nova-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-api','disable','ocf-script','openstack','nova-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-api','audit-enabled','ocf-script','openstack','nova-api','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-api','audit-disabled','ocf-script','openstack','nova-api','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-scheduler','enable','ocf-script','openstack','nova-scheduler','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-scheduler','disable','ocf-script','openstack','nova-scheduler','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-scheduler','audit-enabled','ocf-script','openstack','nova-scheduler','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-scheduler','audit-disabled','ocf-script','openstack','nova-scheduler','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-conductor','enable','ocf-script','openstack','nova-conductor','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-conductor','disable','ocf-script','openstack','nova-conductor','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-conductor','audit-enabled','ocf-script','openstack','nova-conductor','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-conductor','audit-disabled','ocf-script','openstack','nova-conductor','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-console-auth','enable','ocf-script','openstack','nova-consoleauth','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-console-auth','disable','ocf-script','openstack','nova-consoleauth','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-console-auth','audit-enabled','ocf-script','openstack','nova-consoleauth','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-console-auth','audit-disabled','ocf-script','openstack','nova-consoleauth','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-novnc','enable','ocf-script','openstack','nova-novnc','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-novnc','disable','ocf-script','openstack','nova-novnc','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-novnc','audit-enabled','ocf-script','openstack','nova-novnc','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-novnc','audit-disabled','ocf-script','openstack','nova-novnc','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-api','enable','ocf-script','openstack','cinder-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-api','disable','ocf-script','openstack','cinder-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-api','audit-enabled','ocf-script','openstack','cinder-api','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-api','audit-disabled','ocf-script','openstack','cinder-api','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-scheduler','enable','ocf-script','openstack','cinder-schedule','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-scheduler','disable','ocf-script','openstack','cinder-schedule','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-scheduler','audit-enabled','ocf-script','openstack','cinder-schedule','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-scheduler','audit-disabled','ocf-script','openstack','cinder-schedule','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-volume','enable','ocf-script','openstack','cinder-volume','start','',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-volume','disable','ocf-script','openstack','cinder-volume','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-volume','audit-enabled','ocf-script','openstack','cinder-volume','monitor','',2,2,2,30,60); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-volume','audit-disabled','ocf-script','openstack','cinder-volume','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-collector','enable','ocf-script','openstack','ceilometer-collector','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-collector','disable','ocf-script','openstack','ceilometer-collector','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-collector','audit-enabled','ocf-script','openstack','ceilometer-collector','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-collector','audit-disabled','ocf-script','openstack','ceilometer-collector','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-api','enable','ocf-script','openstack','ceilometer-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-api','disable','ocf-script','openstack','ceilometer-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-api','audit-enabled','ocf-script','openstack','ceilometer-api','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-api','audit-disabled','ocf-script','openstack','ceilometer-api','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-agent-notification','enable','ocf-script','openstack','ceilometer-agent-notification','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-agent-notification','disable','ocf-script','openstack','ceilometer-agent-notification','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-agent-notification','audit-enabled','ocf-script','openstack','ceilometer-agent-notification','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceilometer-agent-notification','audit-disabled','ocf-script','openstack','ceilometer-agent-notification','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-engine','enable','ocf-script','openstack','heat-engine','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-engine','disable','ocf-script','openstack','heat-engine','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-engine','audit-enabled','ocf-script','openstack','heat-engine','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-engine','audit-disabled','ocf-script','openstack','heat-engine','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api','enable','ocf-script','openstack','heat-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api','disable','ocf-script','openstack','heat-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api','audit-enabled','ocf-script','openstack','heat-api','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api','audit-disabled','ocf-script','openstack','heat-api','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api-cfn','enable','ocf-script','openstack','heat-api-cfn','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api-cfn','disable','ocf-script','openstack','heat-api-cfn','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api-cfn','audit-enabled','ocf-script','openstack','heat-api-cfn','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api-cfn','audit-disabled','ocf-script','openstack','heat-api-cfn','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api-cloudwatch','enable','ocf-script','openstack','heat-api-cloudwatch','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api-cloudwatch','disable','ocf-script','openstack','heat-api-cloudwatch','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api-cloudwatch','audit-enabled','ocf-script','openstack','heat-api-cloudwatch','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('heat-api-cloudwatch','audit-disabled','ocf-script','openstack','heat-api-cloudwatch','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('open-ldap','enable','lsb-script','','openldap','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('open-ldap','disable','lsb-script','','openldap','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('open-ldap','audit-enabled','lsb-script','','openldap','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('open-ldap','audit-disabled','lsb-script','','openldap','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('snmp','enable','lsb-script','','snmpd','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('snmp','disable','lsb-script','','snmpd','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('snmp','audit-enabled','lsb-script','','snmpd','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('snmp','audit-disabled','lsb-script','','snmpd','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('lighttpd','enable','lsb-script','','lighttpd','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('lighttpd','disable','lsb-script','','lighttpd','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('lighttpd','audit-enabled','lsb-script','','lighttpd','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('lighttpd','audit-disabled','lsb-script','','lighttpd','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('horizon','enable','lsb-script','','horizon','start','',2,2,2,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('horizon','disable','lsb-script','','horizon','stop','',1,1,1,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('horizon','audit-enabled','lsb-script','','horizon','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('horizon','audit-disabled','lsb-script','','horizon','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('patch-alarm-manager','enable','lsb-script','','patch-alarm-manager','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('patch-alarm-manager','disable','lsb-script','','patch-alarm-manager','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('patch-alarm-manager','audit-enabled','lsb-script','','patch-alarm-manager','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('patch-alarm-manager','audit-disabled','lsb-script','','patch-alarm-manager','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim','enable','ocf-script','nfv','vim','start','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim','disable','ocf-script','nfv','vim','stop','',1,1,1,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim','audit-enabled','ocf-script','nfv','vim','monitor','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim','audit-disabled','ocf-script','nfv','vim','monitor','',0,0,0,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim-api','enable','ocf-script','nfv','vim-api','start','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim-api','disable','ocf-script','nfv','vim-api','stop','',1,1,1,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim-api','audit-enabled','ocf-script','nfv','vim-api','monitor','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim-api','audit-disabled','ocf-script','nfv','vim-api','monitor','',0,0,0,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim-webserver','enable','ocf-script','nfv','vim-webserver','start','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim-webserver','disable','ocf-script','nfv','vim-webserver','stop','',1,1,1,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim-webserver','audit-enabled','ocf-script','nfv','vim-webserver','monitor','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('vim-webserver','audit-disabled','ocf-script','nfv','vim-webserver','monitor','',0,0,0,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('guest-agent','enable','ocf-script','platform','guestAgent','start','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('guest-agent','disable','ocf-script','platform','guestAgent','stop','',1,1,1,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('guest-agent','audit-enabled','ocf-script','platform','guestAgent','monitor','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('guest-agent','audit-disabled','ocf-script','platform','guestAgent','monitor','',0,0,0,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-api-proxy','enable','lsb-script','','api-proxy','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-api-proxy','disable','lsb-script','','api-proxy','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-api-proxy','audit-enabled','lsb-script','','api-proxy','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-api-proxy','audit-disabled','lsb-script','','api-proxy','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('haproxy','enable','lsb-script','','haproxy','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('haproxy','disable','lsb-script','','haproxy','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('haproxy','audit-enabled','lsb-script','','haproxy','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('haproxy','audit-disabled','lsb-script','','haproxy','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-rest-api','enable','lsb-script','','ceph-rest-api','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-rest-api','disable','lsb-script','','ceph-rest-api','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-rest-api','audit-enabled','lsb-script','','ceph-rest-api','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-rest-api','audit-disabled','lsb-script','','ceph-rest-api','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-manager','enable','lsb-script','','ceph-manager','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-manager','disable','lsb-script','','ceph-manager','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-manager','audit-enabled','lsb-script','','ceph-manager','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-manager','audit-disabled','lsb-script','','ceph-manager','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cinder','enable','ocf-script','linbit','drbd','start','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,90,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cinder','disable','ocf-script','linbit','drbd','stop','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cinder','go-active','ocf-script','linbit','drbd','promote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cinder','go-standby','ocf-script','linbit','drbd','demote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cinder','audit-enabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-cinder','audit-disabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',0,0,0,20,28); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-lvm','enable','ocf-script','heartbeat','LVM','start','',2,2,2,330,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-lvm','disable','ocf-script','heartbeat','LVM','stop','',1,1,1,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-lvm','audit-enabled','ocf-script','heartbeat','LVM','monitor','',2,2,2,60,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-lvm','audit-disabled','ocf-script','heartbeat','LVM','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('cinder-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('pxeboot-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('pxeboot-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('pxeboot-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('pxeboot-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('iscsi','enable','lsb-script','','target','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('iscsi','disable','lsb-script','','target','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('iscsi','audit-enabled','lsb-script','','target','status','',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('iscsi','audit-disabled','lsb-script','','target','status','',0,0,0,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-radosgw','enable','lsb-script','','ceph-radosgw','start','',2,2,2,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-radosgw','disable','lsb-script','','ceph-radosgw','stop','',1,1,1,15,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-radosgw','audit-enabled','lsb-script','','ceph-radosgw','status','',2,2,2,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('ceph-radosgw','audit-disabled','lsb-script','','ceph-radosgw','status','',0,0,0,15,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-api','enable','ocf-script','openstack','aodh-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-api','disable','ocf-script','openstack','aodh-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-api','audit-enabled','ocf-script','openstack','aodh-api','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-api','audit-disabled','ocf-script','openstack','aodh-api','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-evaluator','enable','ocf-script','openstack','aodh-evaluator','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-evaluator','disable','ocf-script','openstack','aodh-evaluator','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-evaluator','audit-enabled','ocf-script','openstack','aodh-evaluator','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-evaluator','audit-disabled','ocf-script','openstack','aodh-evaluator','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-listener','enable','ocf-script','openstack','aodh-listener','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-listener','disable','ocf-script','openstack','aodh-listener','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-listener','audit-enabled','ocf-script','openstack','aodh-listener','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-listener','audit-disabled','ocf-script','openstack','aodh-listener','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-notifier','enable','ocf-script','openstack','aodh-notifier','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-notifier','disable','ocf-script','openstack','aodh-notifier','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-notifier','audit-enabled','ocf-script','openstack','aodh-notifier','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('aodh-notifier','audit-disabled','ocf-script','openstack','aodh-notifier','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-api','enable','ocf-script','openstack','murano-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-api','disable','ocf-script','openstack','murano-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-api','audit-enabled','ocf-script','openstack','murano-api','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-api','audit-disabled','ocf-script','openstack','murano-api','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-engine','enable','ocf-script','openstack','murano-engine','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-engine','disable','ocf-script','openstack','murano-engine','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-engine','audit-enabled','ocf-script','openstack','murano-engine','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-engine','audit-disabled','ocf-script','openstack','murano-engine','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-rabbit','enable','ocf-script','rabbitmq','rabbitmq-server','start','',2,2,2,60,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-rabbit','disable','ocf-script','rabbitmq','rabbitmq-server','stop','',1,1,1,60,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-rabbit','audit-enabled','ocf-script','rabbitmq','rabbitmq-server','monitor','',2,2,2,15,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('murano-rabbit','audit-disabled','ocf-script','rabbitmq','rabbitmq-server','monitor','',0,0,0,15,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('panko-api','enable','ocf-script','openstack','panko-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('panko-api','disable','ocf-script','openstack','panko-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('panko-api','audit-enabled','ocf-script','openstack','panko-api','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('panko-api','audit-disabled','ocf-script','openstack','panko-api','monitor','',0,0,0,30,30); +CREATE TABLE SERVICE_ACTION_RESULTS ( PLUGIN_TYPE CHAR(32), PLUGIN_NAME CHAR(80), PLUGIN_COMMAND CHAR(80), PLUGIN_EXIT_CODE CHAR(10), ACTION_RESULT CHAR(32), SERVICE_STATE CHAR(32), SERVICE_STATUS CHAR(32), SERVICE_CONDITION CHAR(32), PRIMARY KEY (PLUGIN_TYPE, PLUGIN_NAME, PLUGIN_COMMAND, PLUGIN_EXIT_CODE)); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','status','0','success','enabled-active','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','status','1','success','disabled','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','status','2','success','disabled','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','status','3','success','disabled','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','status','4','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','status','plugin-failure','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','status','other','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','0','success','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','1','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','2','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','3','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','4','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','5','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','6','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','7','failed','disabled','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','plugin-failure','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','plugin-timeout','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('lsb-script','default','default','other','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','0','success','unknown','',''); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','1','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','2','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','3','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','4','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','5','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','6','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','7','success','disabled','',''); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','8','success','enabled-active','',''); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','9','failed','enabled-active','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','32','success','unknown','degraded','data-inconsistent'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','33','success','unknown','degraded','data-outdated'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','34','success','unknown','degraded','data-consistent'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','35','success','unknown','degraded','data-syncing'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','36','success','unknown','degraded','data-standalone'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','37','success','enabled-active','degraded','data-inconsistent'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','38','success','enabled-active','degraded','data-outdated'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','39','success','enabled-active','degraded','data-consistent'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','40','success','enabled-active','degraded','data-syncing'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','41','success','enabled-active','degraded','data-standalone'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','plugin-failure','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','plugin-timeout','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','default','other','failed','unknown','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','stop','5','success','disabled','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','default','demote','5','success','disabled','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','Filesystem','stop','1','success','disabled','unknown','unknown'); +INSERT INTO "SERVICE_ACTION_RESULTS" VALUES('ocf-script','Filesystem','stop','plugin-timeout','success','disabled','unknown','unknown'); +CREATE TABLE SCHEMA_VERSION (ID INTEGER PRIMARY KEY AUTOINCREMENT, MAJOR INTEGER, MINOR INTEGER); +INSERT INTO "SCHEMA_VERSION" VALUES(2,0,0); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(78,'yes','cloud-services','magnum-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(79,'yes','cloud-services','magnum-conductor','critical'); +INSERT INTO "SERVICES" VALUES(78,'yes','magnum-api','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(79,'yes','magnum-conductor','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','magnum-conductor','not-applicable','enable','magnum-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','magnum-api','not-applicable','disable','magnum-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','magnum-conductor','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','magnum-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','magnum-conductor','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','magnum-conductor','disabled'); +INSERT INTO "SERVICE_ACTIONS" VALUES('magnum-api','enable','ocf-script','openstack','magnum-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('magnum-api','disable','ocf-script','openstack','magnum-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('magnum-api','audit-enabled','ocf-script','openstack','magnum-api','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('magnum-api','audit-disabled','ocf-script','openstack','magnum-api','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('magnum-conductor','enable','ocf-script','openstack','magnum-conductor','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('magnum-conductor','disable','ocf-script','openstack','magnum-conductor','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('magnum-conductor','audit-enabled','ocf-script','openstack','magnum-conductor','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('magnum-conductor','audit-disabled','ocf-script','openstack','magnum-conductor','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(80,'no','cloud-services','ironic-api','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(81,'no','cloud-services','ironic-conductor','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(82,'yes','cloud-services','panko-api','critical'); +INSERT INTO "SERVICES" VALUES(80,'no','ironic-api','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(81,'no','ironic-conductor','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICES" VALUES(82,'yes','panko-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/panko-api.pid'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ironic-conductor','not-applicable','enable','ironic-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ironic-api','not-applicable','disable','ironic-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ironic-conductor','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','ironic-conductor','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ironic-conductor','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','ironic-conductor','disabled'); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-api','enable','ocf-script','openstack','ironic-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-api','disable','ocf-script','openstack','ironic-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-api','audit-enabled','ocf-script','openstack','ironic-api','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-api','audit-disabled','ocf-script','openstack','ironic-api','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-conductor','enable','ocf-script','openstack','ironic-conductor','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-conductor','disable','ocf-script','openstack','ironic-conductor','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-conductor','audit-enabled','ocf-script','openstack','ironic-conductor','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-conductor','audit-disabled','ocf-script','openstack','ironic-conductor','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(83,'yes','cloud-services','nova-placement-api','critical'); +INSERT INTO "SERVICES" VALUES(83,'yes','nova-placement-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/nova-placement-api.pid'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-placement-api','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-placement-api','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-placement-api','not-applicable','enable','cgcs-nfs-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cgcs-nfs-ip','not-applicable','disable','nova-placement-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','nova-placement-api','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','nova-placement-api','disabled'); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-placement-api','enable','ocf-script','openstack','nova-placement-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-placement-api','disable','ocf-script','openstack','nova-placement-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-placement-api','audit-enabled','ocf-script','openstack','nova-placement-api','monitor','',2,2,2,30,20); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-placement-api','audit-disabled','ocf-script','openstack','nova-placement-api','monitor','',0,0,0,30,20); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(84,'no','cloud-services','nova-compute','critical'); +INSERT INTO "SERVICES" VALUES(84,'no','nova-compute','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-compute','not-applicable','enable','ironic-conductor','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ironic-conductor','not-applicable','disable','nova-compute','disabled'); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-compute','enable','ocf-script','openstack','nova-compute','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-compute','disable','ocf-script','openstack','nova-compute','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-compute','audit-enabled','ocf-script','openstack','nova-compute','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-compute','audit-disabled','ocf-script','openstack','nova-compute','monitor','',0,0,0,30,30); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(85,'no','controller-services','ironic-tftp-ip','critical'); +INSERT INTO "SERVICES" VALUES(85,'no','ironic-tftp-ip','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ironic-tftp-ip','not-applicable','enable','management-ip','enabled-active'); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-tftp-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-tftp-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-tftp-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('ironic-tftp-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); +INSERT INTO "SERVICE_GROUP_MEMBERS" VALUES(86,'no','cloud-services','nova-serialproxy','minor'); +INSERT INTO "SERVICES" VALUES(86,'no','nova-serialproxy','initial','initial','none','none',2,1,90000,4,16,''); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-serialproxy','not-applicable','enable','ironic-conductor','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','ironic-conductor','not-applicable','disable','nova-serialproxy','disabled'); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-serialproxy','enable','ocf-script','openstack','nova-serialproxy','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-serialproxy','disable','ocf-script','openstack','nova-serialproxy','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-serialproxy','audit-enabled','ocf-script','openstack','nova-serialproxy','monitor','',2,2,2,30,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('nova-serialproxy','audit-disabled','ocf-script','openstack','nova-serialproxy','monitor','',0,0,0,30,30); + +---- distributed cloud services +INSERT INTO "SERVICE_GROUPS" VALUES(10,'no','distributed-cloud-services','no','no','initial','initial','','',300000,'yes'); +INSERT INTO "SERVICE_DOMAIN_MEMBERS" VALUES(10,'no','controller','distributed-cloud-services','N + M',1,1,'controller-aggregate',''); + +-- dcorch-engine +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcorch-engine','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcorch-engine','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcorch-engine.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-engine','enable','ocf-script','openstack','dcorch-engine','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-engine','disable','ocf-script','openstack','dcorch-engine','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-engine','audit-enabled','ocf-script','openstack','dcorch-engine','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-engine','audit-disabled','ocf-script','openstack','dcorch-engine','monitor','',0,0,0,20,5); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-engine','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-engine','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-engine','not-applicable','enable','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-engine','not-applicable','enable','keystone','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','dcorch-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','dcorch-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','management-ip','not-applicable','disable','dcorch-engine','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','keystone','not-applicable','disable','dcorch-engine','disabled'); + +-- dcmanager-manager +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcmanager-manager','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcmanager-manager','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcmanager-manager.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcmanager-manager','enable','ocf-script','openstack','dcmanager-manager','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcmanager-manager','disable','ocf-script','openstack','dcmanager-manager','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcmanager-manager','audit-enabled','ocf-script','openstack','dcmanager-manager','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcmanager-manager','audit-disabled','ocf-script','openstack','dcmanager-manager','monitor','',0,0,0,20,5); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcmanager-manager','not-applicable','enable','sysinv-inv','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcmanager-manager','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcmanager-manager','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcmanager-manager','not-applicable','enable','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-inv','not-applicable','disable','dcmanager-manager','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','dcmanager-manager','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','dcmanager-manager','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','management-ip','not-applicable','disable','dcmanager-manager','disabled'); + +-- dcmanager-api +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcmanager-api','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcmanager-api','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcmanager-api.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcmanager-api','enable','ocf-script','openstack','dcmanager-api','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcmanager-api','disable','ocf-script','openstack','dcmanager-api','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcmanager-api','audit-enabled','ocf-script','openstack','dcmanager-api','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcmanager-api','audit-disabled','ocf-script','openstack','dcmanager-api','monitor','',0,0,0,20,5); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcmanager-api','not-applicable','enable','dcmanager-manager','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcmanager-manager','not-applicable','disable','dcmanager-api','disabled'); + +-- dcorch-snmp +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcorch-snmp','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcorch-snmp','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcorch-snmp.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-snmp','enable','ocf-script','openstack','dcorch-snmp','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-snmp','disable','ocf-script','openstack','dcorch-snmp','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-snmp','audit-enabled','ocf-script','openstack','dcorch-snmp','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-snmp','audit-disabled','ocf-script','openstack','dcorch-snmp','monitor','',0,0,0,20,5); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-snmp','not-applicable','enable','rabbit','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-snmp','not-applicable','enable','postgres','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-snmp','not-applicable','enable','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','rabbit','not-applicable','disable','dcorch-snmp','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','postgres','not-applicable','disable','dcorch-snmp','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','management-ip','not-applicable','disable','dcorch-snmp','disabled'); + +-- dcorch-sysinv-api-proxy +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcorch-sysinv-api-proxy','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcorch-sysinv-api-proxy','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcorch-sysinv-api-proxy.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-sysinv-api-proxy','enable','ocf-script','openstack','dcorch-sysinv-api-proxy','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-sysinv-api-proxy','disable','ocf-script','openstack','dcorch-sysinv-api-proxy','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-sysinv-api-proxy','audit-enabled','ocf-script','openstack','dcorch-sysinv-api-proxy','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-sysinv-api-proxy','audit-disabled','ocf-script','openstack','dcorch-sysinv-api-proxy','monitor','',0,0,0,20,5); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-sysinv-api-proxy','not-applicable','enable','sysinv-inv','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-sysinv-api-proxy','not-applicable','enable','dcorch-engine','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','sysinv-inv','not-applicable','disable','dcorch-sysinv-api-proxy','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-engine','not-applicable','disable','dcorch-sysinv-api-proxy','disabled'); + +-- dcorch-nova-api-proxy +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcorch-nova-api-proxy','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcorch-nova-api-proxy','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcorch-nova-api-proxy.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-nova-api-proxy','enable','ocf-script','openstack','dcorch-nova-api-proxy','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-nova-api-proxy','disable','ocf-script','openstack','dcorch-nova-api-proxy','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-nova-api-proxy','audit-enabled','ocf-script','openstack','dcorch-nova-api-proxy','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-nova-api-proxy','audit-disabled','ocf-script','openstack','dcorch-nova-api-proxy','monitor','',0,0,0,20,5); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-nova-api-proxy','not-applicable','enable','nova-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-nova-api-proxy','not-applicable','enable','dcorch-engine','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','nova-api','not-applicable','disable','dcorch-nova-api-proxy','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-engine','not-applicable','disable','dcorch-nova-api-proxy','disabled'); + +-- dcorch-neutron-api-proxy +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcorch-neutron-api-proxy','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcorch-neutron-api-proxy','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcorch-neutron-api-proxy.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-neutron-api-proxy','enable','ocf-script','openstack','dcorch-neutron-api-proxy','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-neutron-api-proxy','disable','ocf-script','openstack','dcorch-neutron-api-proxy','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-neutron-api-proxy','audit-enabled','ocf-script','openstack','dcorch-neutron-api-proxy','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-neutron-api-proxy','audit-disabled','ocf-script','openstack','dcorch-neutron-api-proxy','monitor','',0,0,0,20,5); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-neutron-api-proxy','not-applicable','enable','neutron-server','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-neutron-api-proxy','not-applicable','enable','dcorch-engine','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','neutron-server','not-applicable','disable','dcorch-neutron-api-proxy','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-engine','not-applicable','disable','dcorch-neutron-api-proxy','disabled'); + +-- dcorch-cinder-api-proxy +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcorch-cinder-api-proxy','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcorch-cinder-api-proxy','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcorch-cinder-api-proxy.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-cinder-api-proxy','enable','ocf-script','openstack','dcorch-cinder-api-proxy','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-cinder-api-proxy','disable','ocf-script','openstack','dcorch-cinder-api-proxy','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-cinder-api-proxy','audit-enabled','ocf-script','openstack','dcorch-cinder-api-proxy','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-cinder-api-proxy','audit-disabled','ocf-script','openstack','dcorch-cinder-api-proxy','monitor','',0,0,0,20,5); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-cinder-api-proxy','not-applicable','enable','cinder-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-cinder-api-proxy','not-applicable','enable','dcorch-engine','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','cinder-api','not-applicable','disable','dcorch-cinder-api-proxy','disabled'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcorch-engine','not-applicable','disable','dcorch-cinder-api-proxy','disabled'); + +-- patch filesystem related sevices +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','controller-services','drbd-patch-vault','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','controller-services','patch-vault-fs','critical' FROM "SERVICE_GROUP_MEMBERS"; + +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','drbd-patch-vault','initial','initial','none','none',2,1,90000,4,16,'' FROM "SERVICES"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','patch-vault-fs','initial','initial','none','none',2,1,90000,4,16,'' FROM "SERVICES"; + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-patch-vault','not-applicable','go-active','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','patch-vault-fs','not-applicable','enable','drbd-patch-vault','enabled-active'); + +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','drbd-patch-vault','not-applicable','go-standby','patch-vault-fs','disabled'); + +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-patch-vault','enable','ocf-script','linbit','drbd','start','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,90,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-patch-vault','disable','ocf-script','linbit','drbd','stop','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-patch-vault','go-active','ocf-script','linbit','drbd','promote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-patch-vault','go-standby','ocf-script','linbit','drbd','demote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-patch-vault','audit-enabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS" VALUES('drbd-patch-vault','audit-disabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',0,0,0,20,28); +INSERT INTO "SERVICE_ACTIONS" VALUES('patch-vault-fs','enable','ocf-script','heartbeat','Filesystem','start','',2,2,2,60,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('patch-vault-fs','disable','ocf-script','heartbeat','Filesystem','stop','',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('patch-vault-fs','audit-enabled','ocf-script','heartbeat','Filesystem','monitor','',2,2,2,60,40); +INSERT INTO "SERVICE_ACTIONS" VALUES('patch-vault-fs','audit-disabled','ocf-script','heartbeat','Filesystem','monitor','',0,0,0,60,40); + +-- dcorch-patch-api-proxy +INSERT INTO "SERVICE_GROUP_MEMBERS" SELECT MAX(id) + 1,'no','distributed-cloud-services','dcorch-patch-api-proxy','critical' FROM "SERVICE_GROUP_MEMBERS"; +INSERT INTO "SERVICES" SELECT MAX(id) + 1,'no','dcorch-patch-api-proxy','initial','initial','none','none',2,1,90000,4,16,'/var/run/resource-agents/dcorch-patch-api-proxy.pid' FROM "SERVICES"; +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-patch-api-proxy','enable','ocf-script','openstack','dcorch-patch-api-proxy','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-patch-api-proxy','disable','ocf-script','openstack','dcorch-patch-api-proxy','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-patch-api-proxy','audit-enabled','ocf-script','openstack','dcorch-patch-api-proxy','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS" VALUES('dcorch-patch-api-proxy','audit-disabled','ocf-script','openstack','dcorch-patch-api-proxy','monitor','',0,0,0,20,5); +INSERT INTO "SERVICE_DEPENDENCY" VALUES('action','dcmanager-manager','not-applicable','disable','dcorch-patch-api-proxy','disabled'); +CREATE TABLE CONFIGURATION ( ID INTEGER PRIMARY KEY AUTOINCREMENT, "KEY" CHAR(32), "VALUE" CHAR(32) ); +INSERT INTO CONFIGURATION("KEY", "VALUE") VALUES("ENABLING_THROTTLE", "2"); +update "SERVICE_ACTIONS" set TIMEOUT_IN_SECS=60 where action in ('enable', 'audit-enabled') and service_name in ('nova-scheduler', 'nova-console-auth', 'cinder-scheduler'); + + +COMMIT; diff --git a/service-mgmt/sm-db-1.0.0/database/create_sm_hb_db.sql b/service-mgmt/sm-db-1.0.0/database/create_sm_hb_db.sql new file mode 100644 index 00000000..e1378316 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/database/create_sm_hb_db.sql @@ -0,0 +1,4 @@ +PRAGMA foreign_keys=OFF; +BEGIN TRANSACTION; +CREATE TABLE SERVICE_HEARTBEAT_V1 ( ID INTEGER PRIMARY KEY AUTOINCREMENT, PROVISIONED CHAR(32), NAME CHAR(32), TYPE CHAR(32), SRC_ADDRESS CHAR(256), SRC_PORT INT, DST_ADDRESS CHAR(256), DST_PORT INT, MESSAGE CHAR(256), INTERVAL_IN_MS INT, MISSED_WARN INT, MISSED_DEGRADE INT, MISSED_FAIL INT, STATE CHAR(32), MISSED INT, HEARTBEAT_TIMER_ID INT, HEARTBEAT_SOCKET INT ); +COMMIT; diff --git a/service-mgmt/sm-db-1.0.0/database/sm-patch.sql b/service-mgmt/sm-db-1.0.0/database/sm-patch.sql new file mode 100644 index 00000000..1f891da6 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/database/sm-patch.sql @@ -0,0 +1 @@ +--THIS IS A VERY IMPORTANT SYSTEM FILE. MODIFYING THIS FILE MAY CAUSE UNEXPECTED BEHAVIOR. diff --git a/service-mgmt/sm-db-1.0.0/database/sm_database.xlsb b/service-mgmt/sm-db-1.0.0/database/sm_database.xlsb new file mode 100644 index 0000000000000000000000000000000000000000..8c0a3f96410a3625efb71064b848148f1c348cd5 GIT binary patch literal 122233 zcmeFXbC)JTwB}p3ZFJeTZQHiZE_A8Owr$s2R+nwN%eL{>^qDhr=iYVCnlCUDf5ghz zYp=|V$Y=j@@61q^1Bbu>fdYX60RbTeQ70FpI|l;+DIo*_K?i{W(-U)YbhmJHH&XX; zws13G^mec(DS`l_E&%!G^ncs`$ty6Fso=CBj1qp6`c6!5MAyyju-F3TYOPwC&Z(;U z)V&7Y-sn}kjTjub3y8Ea3(nLDbOuGu@Hts0v}Bz+^i3|^!Ansr$#^$meilGUj6rYA zdG90Yjji)n!e=zilLb`^gx~1P>-ov%vvyn{V8`&dWQ3a>Xd*8~H`b11jx^BQoIrap z(yK0)_HdfW6l@SPnogfI5X4NT_IhiTjIVuLzU1A8|8ZhK{viIkv$}l(S6Mmxz_0Mb z(Z0Z*VV`7?Y)w1?$`{fY%&vc#bIiNsuy*eO<5H^qX#nY6E8!d+te!@a2_hIkA2L@> zzIsD{j2gC|djK(dwG!(I>BGR>p-qlD#Ogb7SqQZPl)SU@3zjezy4tQHhq{TQdkC?5 zCRwMnm{k=>J1Nt7!@xROMY*m9-^D+G@Z@?h7-}FL*X~+4Z5ugDA;BIDN-)n6-a!Tz zO>zNyV@80H8G$`KU?w5QrAnAI5te3EB*_m4B^~Du)<^tLAO8RDLr#D!Cc5Y%M(VMR zHJw{>5H5P&#h@(B>quQPvk4aV-wi$g!*KmS4SoM%pvEv8l{P*y!(pFQDL*M(P~a#h z#EocKFDszI478eO&N#)?LfOT)fM&@$`9{QtaJ^U$>V!6fgVpqlr5TwHDVf2%ZO^G{ zVz21%LPk*2okhbbQ_iDcmS4Z1YLK=Zc7nr8mjBo_qa}O6_=7PT5X>U8LCRbf`V6lB zp}SfQWBGVS)j%7~ygPy91jhE`3EY35l9_B)2TV+X`Ab~$2&PQfGlPt@jNnWtEplhm$l4ZC{&Q!kjMK0zH&H&BKwaUm;UhgysCt2+a&Fmd9%v<2Z zOBNVBwl`9_R3x+KKId5Q9*kio90 zy(n1o89^bQvpkCPc*X_+`Thn6QU3oRQta2k@XNozm;XmV_{{litC`#lPjBKlUv8t{;v> z$CVA$1v5J4@z4j;-9>WWF0vS{=X?0QixwU-rc6-7ml+aGToL$h=KudVDgAC?jRFM$ ziG&9M!2^K-^|ojF&rtDlaBPVFUUvqxk3he|GCmoBSsm6p0tFPI7F_L)NwbiO8q!oc`tSsOYE@aR1S^3D6H<&L~@`qfdp(K8z4$uzO|i=0VfK zO50qh%pu^_UN_^pc86UnD69`?og_-jdNRMZ-U(sX4v)OMg0qEth=a0VyR%<{V2gUw z9CYUS`Sjpa&nXJ6LimsNo)91)$p1Y4Df$1cVRtnHIdv5b13fp@rL4Jysr~`~ zThd2fwoHgpc}}#f6fqLfm>GE+UNX1(LMKrX0f;xOeZWh<5$OUl%sZ^W(~=)^ZI4BU zp9f<)+sUQdv##G&ybseFrd9p-`iT(3IzY?8VN|JE>Pi8mwGruWUehkQt~Zgyulx|y z%gH?u;<5mE-q(g8F72@Bbn4^Mej`1wP6yBd{%%SnWoLt=! zU#OOCJp|zqcEJMJ!Lhx|TQ>6{j39au=7g!zd)1jk_yMOrP!t%r6X}~RbAuXQF7l5A z`47~}xlCTmXOd$!2v;q3inwxvWF@}{!O-B^@xaKPBcI_}HE-jt>G(@w*M#FV$M@yw z!*(}ll~#x zuTkeC0&a!dvQ$Z_mZ9E@C7sJ℘O#HC}c`vSS2aURIiYdPio@rayCvtXZSaDX~N8 zG?3@{q%ijE4kCMQ6Q1iO9;zK{=mfI6^>>u`?ff0UpWh#Do<6`rq&++&@mrBw;{S?? zQ8bO4xc@k}^G{9W|4T`3))p4-ZvO+1|9!y1`Tx+dCTU)AkOU+AM!`QK+^;a#(#6s} zQb*pm`T-P0QO}eIrGLG*C!^HGfY+;e(hceJdo)nn$#>Dh?^Z&pJ0t~tx<)nURdzeso~!-PUuSa#kk$aWp9C4fg>U8BUWvYWY%ihp z2Tw$o&E$O?nD>`h)EPL=#9B3XH8g|xhGLmi!w5hxr(&J?>%;y!mz>2|U))-_aNSGB{_?YwW-?GfpF>MmN1pQnuz2(`bcfspD84o= z03Kx=Cb0PJnQ02K3>@A@k;%}2VWHC_DY`?WHcH>be(pxLlUnYINCR3;^O{7)5jE(Y zqrdDdoTVeWRRH!gtnxA`kbQ>t>-{WzWI9I%heKk;nJSQh=O^w0CY-a}bfCIN)76aL zX^bZiXU-=v+<3ga#ubb!(lu~~N)A(PsCEa%t7abVXsx$J>ufkDcgB$b&WcTK++tNQ z)Xi2^+$-lfI3~zZXJgozGc>VWNGBVQr3c0S?5r2r&nE?5BWElx!<@5d4SBp>X2E18Ad13&IL=o!ZB6dKFSfA z?Pz!7ix@6DGejbBi)UiOt8Tj*i9TexrRBcPgAjU#SmXsc{9YQmPx{a z>|#&_gCE|W1IV#Ro=G8a&j?$4f5$pooBT;<08C!BWpVL}y>H(Ut4KM59xyh?D|5~B z9R(tpb4X20iC7ZUPH2>|jry6_FbE&iPOXX%VpP@slIx)9v%D+|BQJ*hYs?_|Hm>V! zPi&3f1RFq1X9CK!mwkBm_w+yKB6=6a$0$INgZK2?9y&T}GZXsUCifQfRnuk7R9JT+XsRjMNlP33nNb@pv)@g$oWArBZSxEaj7@o!j$07rw z@_cEN(Uki`Nq)8|8iVMu1P5w^j{c;EAIueIM}FbMry6(5nf-=-`t+Z&2OA zK&x`XS!FSgXUEA%D?i<(JKyFMF8$CY-Ml^~dh6^rab}cA_AW}@`O8gp&>@ve^a#4y zt>mD{3m3E0eJ3_RXT|4XN^D~52sd{zl8MDf(=64qu!N8O*BEQD*H46ezVsnjiZB)j zo1@|}>w&s`@5?@#U_8W}7?wFK8&@rh7NY7sC$Sp1HbaEzKQeV3$iKGmD{J|vD|F?k zHs)}HH5*XYTYYH4JOk7p5>z6fu_WzOxG&j?8TbiLc<}ewr{BmuXO3f%61?y1yXS@~ zSTuQU*k@N)Dss`~2&!f_YnKwy@JH9(@r-8h+6ZE1*gvXbYs$as-K-I>T`|kex@y2uGHO{K6fCUbq=Inm? zlq7{B1~Iz#`H8&T_jVM>>L?slBJgd^duPyjE=g@MIAslln*$E`*G5mY6tdh0$k(l9 zkedyZnfaT+W{r?5QV9qlhy7Y*o@Y4i?wn4=6x_3hHGBSyUa!aTz5Q$54O(Q|qg(LP zTQWURU^-%+I!FpA5mg>2cc;ORoRMdeLk^D>6KoDeJv*yn2*JepQ=I25{{D1VG!t~x zJ{)_2U=UKA3Z5NgmZ(?g(1-J9u=Q~uMZJVC*mqg=zgOFTk?+r<%Rw0YQ~9s|Er5Cc z6Tm8Vo6INy#Fs)aPozvPW_}7>>YK{E@2!Zfe~6+@X&QBPtZJeU9#?P7d2IMbGDs6W zUd|SO?h-PNtgycGFoh@G_)+<9pK89BaCjgSwPq~MMHK=*zq)W?zeNW;?Q9wL?_DiF z`BT)1WA6G>LMMhXPgT;v)o;)?v9 zS-2Ya5iF%ApbzXPHBhIiT(g~rKAyQ{lV|yC`=_VpL4}>#RE;z~T`erTQZ=!Y6({GX zl$U>Hnx&X$4(8G9?37;`StUy$ezabcvTpn>!OWA5`#XS_v&a$7E4Q<_DKkq4YQ<5X z`bs}pznU|gjP3L|Op8V69Rih;fRF4M|4vz9YthHX*ytPmLvEFDX9_h`(R|&4NEEub z0oA9s_Y064MKel^S>!p2Y1Zq|g&Dw=5+sH?wncEZfD%#Cs$+SMSbC zR+eD4kK-R=Pd?}OQWZq*;1z8JRU&0J$|JcoMCL7N2ZYJ+}0JTY0}RS%4ep( zdRkm_qXXKl=Ig%W3+?{eO>|LnNwv|-)P`b_w`myL$+OEnErv=#YUC3H!(QC#I%A>f zYPWG^l^z;+`wxE73Y*QnK}b;Y4~k`T5#{fQ|CK7As7Yc^<^BowUwMi8um6|3dzzXk zyE@rgn7RK)j&M4Ns5z4fESoSY5dvlm#uHty{$q3>9sjxj#6QdkTRq zg#~sFE(hD}O$akXhwfM(b{277dBd*0=lS5WXO`!~`Fa?)n2JcIv;WtCF4h3!2bs2ZkUogg z-k<&q7)p%x%a@N11R>*ZTp%={pXyd4K0puZ6y#j#{K1(7Yz*Q@Ff|GIZ_qN(MNn{N z@ZXS@U@raiBt#jA6(D%WJ{Tltt{cr^!+ORcHnxJ+;fPUV7gp4530vKwjiD0w>3~F%NAclV5 z0<<+Kbm?h9BVQ^=}23Tu|tRTDK3y>-~wo}c1IDO<65Uc`BYw!(F+*1%< zQ2aemN07^Y#sYX}5XF8-cW}pkcx7CHg3Vw;VWv6gO9(;eEtrHE$JAd>tACQvJ1Ca6 zK+lhP3Y^18iO9k)m9^iv?qAdB--LlHlcF$>lKxTml#fAgPKO_MnEh0Y^^M}B17^CY|;f#EnOh}X+S0` z2@J?lxgaTO2PRY~xGxFVZ-}BGYZ9moD0yfE5P%OoGx~3EYyaVp87Q{*P63|LvJZ55PXeL5&EP-hO| zgCzS}C z*&KvEygsx&R8}wpNUD#3HM}vXE@%=UWI{LsudV74YR)0ZAeK-49PA2e%XX`J;i`Zy z$dIE~t+Y$n3Bt45g}8$GV^c8rrMo{STEd0;SI7RqgxDHUBH&xJT7RAiSr}#Xpos3>rzfU(N#_HGR$z3bo)x9nY z>S6}=Vs`S|WrYcXWk2M;CRS5>$EBNO@oa|Gl#%6><$DLO0ctcxIc%e(nPAuX$eRz( z$eSc*pS6Ws@pSMfAOG~z&pgS>vb(C!V-y~y2%oFk2Rm9ha?9&G-Y$AWy{5(Ba7-vU zTVCEM2M0enTkVMWbwdjWKiTW2>GnY?gp`Kv{e@qqW&x;^hKAaKYI1Np6oC#dS_#Z&WZhg!vxR#vRcz3lZpzqRm{&Bar{saTOY-XHv@1gJ>? z7^yGG6^Dsy2r&zyq%W1dN2E9o4{#Es>=%_w5%|~AbW2P$7-;Z=bn|mNqLCVo412=*yw`1>CS)eu+c2@nTJ;=udk-`E;q;RpQbA83$_tQkhJU;uUsvSD{S86Zv z9W#5MCQY)~EIT-W!X-*qjb+hSyp21AZio5C1wqu?0^mF$%|M~#tZFOZ#JZ}KTN z$OrTD);R4(BGh`+j7{wKn$VH^nkVob(V1 zzK8UBRA2Yrj4A9Ip$R#tbazaD`W~Fp%1yvGPpP(e9kxFpm+7Q&>>^BlyglB8mrlvr z)L2|5b_z)i{X|pYqWAN?+}Rk52^p}bx!zV-m0UrDC0co40(|XsMg`{b2ychzWX)#bnTTyCqS^U?8pu+{NzL#-5dGo!r$PT2#XdH@aW19|g3 zIrcAVtHC%T>DTx@dn?ZnaWJ6}U&h|I+feCx#NdGKSMxVcn!#qh9@pAj{%1$UY-Q z#k;or{K=UDM0(}La=<*Z;(2e?t?vEU%;RJ^;>UJPk4{Yw19=w&jh@ZiCPsG&Ya%`D zPR15LtF(|>7=_HI;BS~Noab1cW<`feXYcN`HUhsm{*I%^zt@4y?L~dQuU}MR=CjFq zhXQQ^MEB;0kyK=jWB#As=1a<-{c?1Z4n*~f23<$x;B9F&v|Pj4gE>>a4R68CKSqj9 z2{UgTJAhN0?`=;R94|eEf#$qrBXn@0-9b;P{f9&YYfK5lB&?onuLu23AaK%_E6?!p zi)aGGiQvD5pbQH_8!fW2s5gYS8b-3zy`FU!ui|I7G(IQ0^QC<=#Bu)i`Fp5xKc&Z{ z%<#F7_Ieg@2`8}VTv8j#*cecp*%G@t$8W~Y_!Oo`UMkZid&Tl9obbd zSa!h#s7XK40$!UxLtgl6U%wf)M*F+rl>FY4l~3^D=sDIvIL(rm3xN!hW=w;UH@5C8 z8VM>>V>_DNO7Pu;NKJV%N5f-Q1c;kh}0@tf)<0LQI%DX~ zLd8n4x};Ky^O;=DSej0CubNeDw_UsRcP!f)8lpU(g+pex(bcpUE?h-f7&}C+UDp`| z>-Fio95#pDNj;5_k2@GQXHX1Wq<2!;ML9SvuKZVhC^nKkPJtmC67b0!lycVMb}z&l z-Je944vp^enqS#y;1lJMie1-0ODJmNT=R%CSFv`Yz$YAiK!GIVo4t^FuclX#RuUhi zEHVzpbpQSL&byh%(TnZBq=EJ{ohBXr1K~o8{5reN{Oi4};iGOcQ>en9+|ljQZ&_(K zfZ`&Z>nv|KU%uA6d_8%WxKQJ~c1e9Y@3Z<6MZV`r zsq?&Jt2dhczA@~(|L)W8b6z!0__nGwy0-JjF$(S6fL=m`l*N&KG)Ov9TOgJVf3!J-z zoVV`PLI3)_c_s;Bav&de&V#yUDfrE2?0n+RKL*x=e5AIxWn+9P_kiK>+vPhcnqu)L zf`cgKBOPjnE7HZASrR!JploDF={NqR+SXiM)Q;9>Wci%^r+&XM!`gJzN_dv5u6n6v z>5S21W7DE7lW#AA%-B7s>}|aQ^!$)P!(fw0d79GkydtF!?=>%;3y}kb0}>K8@NnZ$ zxLN^AiBw?N=PE#~OOI84LMH3L#CG!F?3S-F!|pd5MpKe|I^4ylj8uX{4i(uj#IP-}dM^eL~~XrnYQLIDa$)Gt^Zd z-ozV31`qaDg)Z|G@D3+I#sWintM*sgkUov9XmD5Dr*aLfBM(S)V`Pcli*hJ3<>xkBXB9 zdZuhA(DqDiQm8I1Kdeb2t4o`m=MO7%_UL8)KH6|Ea`#i{QEG?f5u=yP zrKU@U-;^#j@tbh4H{8kVaun6h9I4P(1{~TQ_M{`~Y1F?;{5PY(6Y`EhmDf^<#F28s zbE~UR773m5#NYc4%F@rYo-6(y&@)}W1kuSIB*ywMeLEou$0Jv~Ui2fb-)NWh5jocl zGU=k~HG1~J`Of8G`_jk%uBAC8t)#!hNl8`Bj+LgYL~1l?$iy@or@!GL^``smc;ZTT z7#twy_tD->c#m+nI-no(0?EJ2n70%4C@iG+e2pdbH_$Dir(!L;T`);^3@gcpB<~mI zKtKXBAgjDCm`>wX5k@sXjmH{3~xn}#+hYZPw zqaC?>o?%(L5I>7f<|)N#*i8yh97HyL^M;?jqd>2^@~LZq*P7bKxhUFfcC^b@m_DN@z#{1ZoBMG2iB3#_kpBaDWpPk4ysAs% zG16}+`I2&eSiW;Iz?QOzLAv}Re?#%tRKY~;m>v>O?6hzP^8GKG!_mqbnnNm5C71-O zis$?YePWW;3Bs^XG@?I{>F^rgexR=Mc3Xi-`N#=U{YF*TVOk>8ia<3IAJB6@MrlKM zT)-K^sVblK+pOX9s`Zz=$Jfdxyl^^Nljn%U`Pp5Qln>& zUDxOu8VQ7E$)5NnM(*Q=KJ`(5@ZyjizU>1PTZiPL9OV-zDh! zV80~qUkd8s6BZj5KHmw$L&}_#k8m5@P+e;SI|R)Sjrf0;K_>%u^`FZj&UFgK-VXjI z!*{AHGVK#X=$EGi!myr)klzLajeBM1>#T}S3dG)$`|X~D!o2rBB@SX&(Ot8&THfbe zt%h(4KW+BLjo={Lm8J6;v(!M}Q_297U->`!u89Oanyu3j9hAmEJF#RI#{j1r}6=YKg^D3L5M%#y?u0%FpE(LBXOxqm? z^-~VS331N=)ZYo@27V72;#Lgw(|i9~Lw2b}nc+zaQjdt4giloYpIQ7~$Gv-4llbqfY@LEOTEc4PEgLEMgj^aeek zZ<3?QMMNH26AQo}ap4CGCg&KsbH$#CvtHm3&*;+<$ICQ&#mt(C(J~bQuBikIYR4?; zTc@Zn2~}nX)*sBe^K#W5&(7!G70JIIqT(1~+a|Fw1!KC)VtMV)t*5A{`49iftG=1@ zn@r;@qUv-^jGE{#)AEmipG$NznTmGIuVFq`y^p)sR(`U_lzl9Bv+pR<@Yjepq3(lU zL6Fr;^ZH{PL8Tk zEFV2SO_{LZBXW`}6^P@kpFX?wmtC=6D`kdLXR9n}Q)rdLlHxPm%r5mTKXmq`NZ;(( zUSSm5q5|*`Zk{FP4blPPF*hW`ikSHqibpS#@FHX!+fqbUO}#vQo5*uu6S_6m$>a#l z@~#@zuMWbb9XrH454JMseR7i|?jL=+UDMU|b$nz1R4g_T({>bmNn#^3{K$&%vJP13 zrOTFWJ`PP*y8_sibjrNbX{zy3j_JA|-cYsLu(P|Vr+@mwZfZ$8H?Uof>|-3Ir#=jT^0#ctjj zdl841%H4;vZxr$NQhjlJ@lowGT!hJA(o`l0fhBBryOe@?m>tn_NY3M2?X5$)!w8!6 zs(wRkl{1lsSISY^WSEnA4u<8?bgZzWiVK+r7;EVrdn{8~Ph0TrVM!EHjhZu8@%s}w zf7)kdiRBElSL2fNtm9pmQZ8-Yi@DeMQyDSEkw4H1zL^J$J+H5PuN_#E@!s{j4Ms-s zN5U4I&HFHchR}i7Cc{L-TSCc_+0dhcDL~C`QNN3dOWo+r5SOsvgJUY_busU#6h2&A456%?L~@)Qi1)q(t3N)r5#rImW~F=p}q_z65=+ZzA~lZ zC=`zBHaw?hw}IIF+cR!7K+Go2Sx;ZBFfx8jB(3*I1QTqN5|lkp>r+BG_$w zSU$^{P;AMX*J~u>iB-9Vbkm{!zBZ{Eh#dk}jBMHd4N4~1@4>pi-;cN}hy}Lj3`cH= z?wA*7G_42B^f;usy#c?kRKL)iui=W}cq{4UGlEwZ8wuF4#yuk+)>hYbV!+`roRY{} zs@L7oB{7G&3TpxPd0JO|ekIKg&*$9!o z5VV_qf?Ep!rI4`^s+@@t3OOgj%?*}N*}k(tXhDFOKLL}e)X>qTVaX0v9SEkg$2JqA zX@oJEHjw0Sl;kG-8}Mr(uI<*7Kva(q4cXid-P896pYWy}UzxC^ETZCymT{_Ct!iO)2GY&0g0;2>q-M{Ww?uHn$y%8$lg#}6FBo6R?x6nuEhpcf0Tgm8luAhV$JfIT6(~? zyGVtGmY+e|kYNGtK=G(6v1bsYIH`YhXFr=mnAHYa{U{z&$>IVdOj2i4G*-Tx&U$83 z%c!_4fP2#FZhK{Jw1F98Wtn}YIVtLV0naA!P%Zsk;30GlaE=xT;xrW&k%;{Ab0v!q z$*6jr43{=HZsre64wZDnD$jZzlen)ZRy_4Z`0Gt?MuYG3d#^a(3=X^aX1BeQyL)`k zl4FazFF6)q*V^lhm!R#mF-N--%5ZL-wv#^h-mS9`?J{SI&g{qJ%6pVWj;#A+Dc_Uo z&yF+OETPQjrhK1n)zVrGSu>()`!=S@NfyB7mCeGF1l=@c*Ytkk!i+@rPa9Q9lU>Tm zF~kT3iCJl#g+<=kncz?!@Iun#DYP#Sco%wO2r43H#)2`{PGd`p7N6j4OtdI;6d~8F zlj}Z}d_44yo5%`$Cd)mNP!zR10cxbJ^?~%6MB;a%qz(KclX6!6txn!*#LTQ!wxl03BwAyn5jnk zt#(OPMuOh!>rSMIcub#;@^zlqpv3g9tu7umM6FhmNid|Al zM80FG%`z>H1 zkJ8h-Yp-Xt)2x7x)j$?e!gU=}Un#ShlK8RpYy8IUowijztR6X{6Fw0hiYCqECts0r zMxSKWD2?iRN?s#B7t;gb{8vPI(f4ANokM56gl;YoXE*x-VeSE*p-l8v%{(HmsQk)p z@%3Yj!N}Bp!=g^v>8)6=O)9KwgqPFl*{waz3$mYBVD7_>iOm^ZXiudM_L^H?cb-GQ zlTOWs#;gq0z^cHDy7+~%QuX%ANXdJirhT0Of}I)5OkFE$w3MT>X==fxx}UDS`*BwrB60HHx%KnB!@3o= z-CiX@)L@E}wmv~`UrQbL$uxs9cQsq<3KDuXt#dLPiee-$I~%F^qf`g%)_BdyFqxzj zYT(qr8ZQd4o{oY3#_@$8?Z&nc0MuK=*F3BB>t-5}(4T8d370A<70|PsB6gOL#V7xAduT`jdibvVUlL?FK{m{6^xO_qwc-K2khL5yOn@4HU=lh3y>WyPOXK^Ld~ z!zW5+%w&Iu-R97@vTW4P^?3{T;g|{TYGt{ciyI&9(C~(=kgU1qI%W&g)G|$-_eHF6 zETH-!@h89+IXv)5`S-WAcU=nam+3Jqr}>BZor4MRzTx_JId(U8tBSQA0bM3`V-jO} zTm8Z@PR#b3h-5M5t~nv5=(*U8`6`c>dfQ8@K+)!|>S4s!$V@D6$YX@=fF5>d$;p<1dZ5ytCuXEnZH)f_i^bc%_El#cx z1-NFLPTuh%)c1D|h%$|i?VV+@#S}EK{OJJq12rRv@mqJUS@d-?9V5=&jDPk|yVu^e zAMtF~7g-Yf;`PanuqsrfQ+qvmJB^@$lv*}VBCU@Qz%%FJcd&PZ8^VZ;- zRu+*X)(WCOT{qnp*7~@yxozwVE%mgHICTJ9UO7xM8C@mO%58;ko)eH4;$F7tiAjsJ^deFV`X5R*Hre|IUhckwG2w`Is6;D<|D8${#G)^RRWb z{n=*AdAtAR#n~IWJr!ui-EDH`@OqC-L3@*QCLS?DW8`bf6COiEfmSY@s3ISEV8VMM z&Tp;E?VDZUypJR0RKcD(awkTFVoN21;m2a;i#LiaS>a1+TXk8b}{h3pD;xd?G)he=S~? zvwI{Uv-|E{)KQlX;zvR4KDE9~Cs#5c?*q--5l< z@He6X(N?b*lCMm35~GoFe-7xLH#)PLcpt92kBhRZs)UfK6tD)c>P^u`6|!}Ge5FFPvz2a)p23X~Qo27sY8tfVUgQx$2b zXi58b1GK&OTcwvm4tZv;K&JJOn%CM+?KOtrf%2B<`)Q#sGLUujIqA>pz^mfGtL*Oy z*=d>5J7&utMyiA=IqLktVp_fmc3ivp&jSoz7WX`DQTd^I#^~Ot7^s9I{jB8pwPMS8 zb_Hv%?e?=Wq{uwT^%Sc6#xA%U&6BlF4OuHG{W0O-iTzb)pE=Z@uS5dqa8G|=ExR=d z+SbcwHqG6BBmC%>N%ZtUH&nJxEmFc?)|0+MN=ibQ(@Jty3-$YP4x^9E@)^pxkP_q> zUqspf&jhNiPT2m#a`+`o@e>>p*WpwmhWe`yldrg*Xj?z3TzJn<#qRS4(pqLrEBM8cdbT-jEMl=+y~3Tx~L6lf=QFafn$cV<%jclcIOZs_VYZaH$Jx6ju)-8%sYxh%m`G zqM%fe_@DOt34DLoV{F7ol8GrhlE1QRGD*e?Fo%XQ*ABfHhln-+K~IfTldOdZDT3>z z3@Rfk9LOy}!Th+al45n&3b0u)DmaI)zI~m=7C0=7+8>n1=xE+HLndQ_1A?oFbJBjd zlqtzHlh$$-PW#vk0T5Y& zr+r*k1->xu>)5205t7*ME&SQW>E^6Qk>Qk<3E;`P639;R(BAl;fgly7zl09Rb#A|r zN!DXbQ$m>s0(EF&!Lp$6a<3gSGR&DEJ_k5x;9g7Z|KvL+(Z4<@CdF!ck@o-(ug|64 z{k(k8$OK8&w}@vLI#Rr()_1t_SeA0SzIl?q{=RLWVDEaEJ)PLWf4g%|e_AE=czSL| zAb&YNhfDSKF@1{541<&NWxI9=`WvYnfgi=LP61!NZjx*6FW=g<@I~cEHT#r5j^@c6 z$UovG=kImj!m8@2Fary33tzmFYZfg8vv;wzo>Sqm(fU}sixbUtcKO&D4xY5+9Ob09 zo^?|_*v6Zj^gsS=C_GO*cy3Pput}NS}xX;h!p^7U#o!@iUKo5C4 zz=da=G1vF1iXp8mDe%j59{{`D%%31S~&qO}I=R%@^{#7=v8Y>T7v*uygp7uc~>;IIe#nk1-K73 z-h5(1seP{rzfnB|_CW$0S3HakLga#lBd&HzJ@FKtH?V{YNxcgdgY$+$Z@QB_aIqfl`}coFXd9y#wf!&SqIwf3RPVtnoG>3!3b~Z zM;41S$LD5kKlW~i{I-}4#hd6dnD(*w#9R-(FM7Gv!&Qn` zH3Wn{Ju4DDube;*?=cGS=Fzt-XDZ8;l>1HULbmIh2&yNY!bu*q31@%*!wo610Z*|}$y;3KAQc?!A- zbwLAe_ry8tPBipfW!fbSH~dff#htxX+|M`9kX^&GU0(E6>R3W?4@6)e`}|zx6BEa) zPD#(ocY3EecVAFE-{FB6CoR&TL$64rKJXB`?n(bAu=NSJ3%l!$t@&y^GJiUzh-e&3SAn&8)I<1&pKjLmxe*AOmwvr zz+iZN)Tv%|Nl=rJ>_v(e9=R}FZ7{$UsY+n@7nT2-@PSkj2?oClj)KWUR#xv8Bl7k7 z?dnxfQBm=`^WpnvvbmR~XB(d$N@L&xkTX+0iD{hNh&A)@BjsU)n!e1n=9lQ_;i)Un zirDP>70*eus4nMhAqXo6f^sQ`q_;dmHrpr?EX2@T3nU{vETXwq{-&SLm zE|o($PjANE>&8@?JfBT|hRo?-*BfX@arA1YzUX{_{N%!xC@_~*2nr4{lT7h$%!}lP z;ShV322+S?g5pOR@99MzJT6WjT1sjuj9E<0G>piv7qgUA{%ro5WQV9<_(ESv%#v>% zZo9F06*zO{_bov$Ogi-8t}c8>`%vnlAFNe$_?DiDX`r1}i^-16S&0iYB`~dsIMKYd z;<<{!2H|dSNKcGbO=f#-!)AYEe!y=+TnfJ;gvLU~`POjr7!MyKj5M9yY3qEVmaTxu zQk_S7GDyX#n6^sg4D*uqO+)3HSoHY6G{1e#56eOyzlqd-RI6gZ;XV-_=hF__yA1t; zGapaoo=wzWC_z!-ZI&}Q z@L++kQc}_0oS=!CE>$lwoka3Uu$veGz}e8^Zf?=OdVX~d0dqGwVUlt%yi;S9%?>Bq8FNpUqv!u>lx?G`7zA(+ z{I-fb++^ui_S%(p6)NV>Xw!WK=JA|?ja6KcWTN=Wa^U5*%M&cY{#zQkMJ&S zmWbu`Xs6?ZKJLd;lj?@~E`(k*Fe;La$SYH)Et@xEDUY}zqwl(sT3iER>u zwCcrt2!P@{LpY%KG!lNtDsOXkTQsiQs+s_A-_Rwh&`H_|_XNUvM_j~!DS`N$8fZ6C<8%J< z5c{_g7&?5DTe@FvMBr{xX-01?&vR?i6{>9(lM_>YhK6iClN;{oK3aod_!mNeltw99ZrxQiuU>R(6N8!28~D{`4E<~A8@>q1;_GH{ z>FlNtn4SOQDPD}nmg!l*YzGKRh{CB=Qe2u(`Z>^urv|h|fl&ueIm1LZi1%@9dG_1CZNtz_I+=V_oEw{e>yhqs z(ExS>zl+@pwv=(3gLnUZAvGNa{m2jNVLI1a37mXRQ3J9Ee!Z`@eyb{S*X)k8e4iDd zRD3DHM6)8xKiZUBfX=ybCJ)I&BwZQl0V6Gc;195ueKsdZ7Tl-fE^xZZJZ_SbaNso` z<;ONOeRex#d^k*flAU9m1+s7t71S&7e7i*fDL-~Cr~u!Y)jmX3EKf=&mll`8pYc0{ zj-ta;ppH!;O*$`@a_28AY0&D@Sm{l$nC`5AlfkWU_=nq(-9_2 zP(b>+?;n>G4e4OV8q}bK}tbN!C(D>LEm8C;7B0qUip831l$n*p#HG_kOWY@P`#kNkZ~Zp zpu6BgAX34^!DjtRAf-?6>p@_9n5XTr>u-Vh1hw<%$zL}k&s#>%eVF@rnGRqN@hhb7 z`Mrt*eQ;s{H>uVK0r!4@10$c;LzWwaKwu!*sq!Xyaj8(GU)Yn} z?3IE2uO92Ke~DGx!`pw~T{II0pbE1UKnm-S6{q*$+Qe9rPv=|71j~cakkSC{R614- zZ#bxKH@}`GTNN*e6W*cUtI?XRhbpx$N+ZvR#|D1fJCz3RjdT1#k}{QIDE{hm%!#wd z_rQ>asaX|)1|_3_C<)mEqbB_wiUw8}LZYf6D$EPx7>@Rf!QFSt)ro+HlscYqvU;47 z0-_4(7q6;l!8yqovG$1O-wHT)l%Yg4Fpd9l77|SjQD-MccNA`E*kD{j2+I>>lpIuZ z;BD_eV3;Lm39a?iB)1!Kl0YF{{ovlVEt!uOnrTq8nRnIXq&ce+qP{~I;+yQZQHhOtI{?rS!vtW&01@}bI)mK-Q9M3e7N{*^eL*}(XADM^Bx`dO4lTn;IE$GzLmE#N8O zKwauUdLi*qLhs`~!_jN~m17pM>RUG^AjHTEIY%!2>l|OXog=2M@zL`(9F0H=NJpG_ ztJXdSCU^Em%-}_ZSVDguT`t7y>Jf$GvpRQ5ABp3`G|0OD^2q<8s}|3oJY=~wu-M)8 zZh{n7D`T+w>5z-i`koRjngJBhRc`R~qqQu5f}|GD&+v6A#m7JGsGT8-@)N8Oq4f>f z$tXc|n;@{{@d=du$y zq>`Af;d>41!e=&_%BPlG+{@(@=*Ug^(y#8I4Asd6I z%?b&AhEHnv048{;JLD}M@LVkRuOkN#B+ofrZwV8Bk5>ypkib6qWWzRAz7HGGJ=jF@ zCv9NTKKz8w8AR`)&bnOO2YBAF;L|2)@CW;?%dbzNUp~KUetfPz$P=ygvqqVHUiwRH zJ>;O!xut(fuQ>x0)S#Y8_`lu*|{IVc+ux&2zjm>$Q1A0zM6 zJxI=BTY7bOSuNg#AM@cVvUI$jC4{#l`10co(rFM9b0?qu*X4tEi&mfomzU6{Z9q^7 zS)5;n;SzMlj-BviGIl#X?6XA6BHK&HR-9~hpJ4=h&Gq87IbM@pTLwuXjrb85OGV*F z@TQeoHRQuO8c|ScA|*@A-Q`q)e9LX>41P{s#@+DRV96Rz&Bs$dM>YS)IwBpmSBDD! zy5`YZ)ywfB)%~#ina1e-a1Ex0LDI|aIPEtd&vUXo{;u`THss=^UukdlJExnx(93nIz!M8PQ#`6L2liiVXNE27|1uUT4rAXHZZ{rw~679#g^zR=fL=$`x zL!r7V^|U*v5LP=E%>Kyy6lnM-RBgH)un}Fl`^%V zS7DEB;!AP@H0;NS`FIK~d?E~Fg3jP~`WTmX^TA$gs=4kik?kG14$*7mZzReszwExc z4%fMd$FxJTMzDzVE>62 z2Hn_UO3(oeoHpnlf-$l%akDd4ds1E4a-1yCm-o{J1n23ZL`gL(v}plMg@0dNhV zVj-W4Zp&s1H-pWAegu36`T`gx;IqZk1IPg=MUCkU6$@1ecq{-G3z-T30{{j<;$k?c zM^u0<7I+WHO@L3p47HCADBRDlXRwDrmq7st1~3??-&fjqy9Yv-#Fml)3IkR_Go|+f z*p`z4tre&h2?IP5T*?o!M>c`N4Y!a1Y|mIA0UFx?haE|@KFQ;*}8 z`4*Ng7z1)ES}N!d@E`CBnhknOfVLlEV*96-1G+@=N&|?_HK%+RLgP3+T6a5=R+~U& zE<@L2VNt28is3Ov#+xna#47oKlQ*_mrPtv%V{NVs&6~=#)oLC7tHFfs+Kwu%-JuN0nj#6FrM5M*>1Wi78|K>oWv}wsC4ZBC3HvAgT@Xa%ebX zuA4BnV!x}826v`82_PynJS(E-`yj>p#KdcaB3C*ticBQQ-f)0b5p-D|6^U+e z?PjqvODwq!wphPGCA=Xw+OcsMWhyB;o_LM4FH6uzY6E%hC7EuQ7azsdvkRi}HfJnb z0!R+e#IW=gJ4)vVSRfwsqrlS~k5}N;cEe+xK3YyR!=6&lT%0!_c4Rlm)6D9LqgXt` zu5Am7n&SpBoKf!mB8P(GcFnhY+CeJITufK=$_A`cLf|$jzG`<{qMYNA0%0ZiJ2*DX zXR06)@v#DVFf$to%1K=_1vXJ9L8IJSYh5IJ+z|J)!ZDhn1{wn=wZdj6niC_KlNx}g zIUOf-U-Mi?D1nf<+?V{+_c(qjFQ8Xq&$i0R-dujc$s)T!ci|qigh&>w=@R4_A`0}? zbgU>GWx=mDe2-&+BXO<0oK3v2A4}8E#(cR)Ng;~Cnjj0HIgD^D3V|^D87k9BFRT+y zKBuPRh#ZtlW_ckCDv|X=VtC5Zei4}-hwTJl^sF_z9V)~T@%FO(OwLy60!65gRv)Ae zyah_~vi5iwr5uAJ6FDTllI@rc_$FFnTMG<7m(y>BGB=`StSCD%FYfb(r7`* zrUUyU!zTH0#?)e(;61ClngaH6%nD|}(P+R!=5eEDXOu?gw&7IE?jj!dnDaM!NUo|# zCrvm$;d8+C0|A4IDDFlIuu=oxdS@gV?*({xkiJPvk`W8Ob0Ucz8{G#fCVJ6dqv%tH z*({K}RD84XDp|Y{g)ZI@2wNgDVI@#3f6!}@qTmI{gRk5!E~KbIyFTOaTsdA6a1JJ* zR_dK7E`{c1J<3)-nE*(0TgTGo3cq1zpO&hlr>+aGd|GS>t^Aa3$iExBov-PA+M$4= z)riNuB(`&&*&?MlWl2n+%1Ln$@UZZg*hW&F0Ug^^2RqbWSBl4yX)nv7yfP}=bR8@i4LssZjX&P!HD3PKlZH(c33H~sh_iKo$p&GHUTS+ zQQ@-$X?Ze#_iq40{`z!zVZ{@?0}YO|aiKygqD-npsbqbEZGq8d|M?O4nQ$a0LU|$H zqh8Lax-Ct)eur!{f|ZtcDj9rv#fz~0!kwOJ5G7_bRqVlTlej5Y;!V%tnm+#$KrO%` z9_W)gDDBln48)3ApySa*gUCX2;;8#f1x^lgGEYLB8FQF23b_|gFy=@pM<4c`J2+wF znFBI#_-wMggxTeiGFff5pxaImaz7r~bd-HwizhS6v27Le=+ub%J4|nh!TfCE8B;+A zl6YRZTiy?u24F+I6jsL{qQ@V&g|)u%q(_Bu1&8PZ(4eV*yto@_Oj_Lc#`gOcxWWq zKjkw8+egW|N;}!w%M4;Sfn-}j1x-;b`Y`4>HI|zAqsvoSD-Dl$r};BnXM4Qik+sqf zt9XCYTbqiU{xqp}`I(f;_*#3{Juqu-wZ6R)VB>AHUHGIC&=vOqzkYigTtn|uesulI zfd4esORWyrsKBv!Q&YW@+Q#gHn$+R71mD4E?CO%P-ROOvn>>Z*X=rGwCB~Ik>!s%R ztJ5%h#~Y!^t`YwF{7Fi|_rlNh>XWF?=cC!*C98*bWg0Hh)pwgNwoCDf;4!GQ9zVya zaf2ruB|rHuFQ2+yDh{=IOq2%`OZ&vxr9atInopTpJk>|5ve2hwGas|q`QgvnsI8}F z4y7(ue{}jh)dD6MK6MetM7>k#Sxc^8G)t%Oa&48~<*XTREgqO8A6A~}uf6QA)7zwc zWDL2`U!<&C92H2r)0=D0J#!t)KL9C9WR&O^oZ1I#doC3VXW+jb9N;%TmeFQ+drkf9 zx2qG@e%Tu2Rzszgp5JiU{@ByNb>45h)NCwwI+z`<>Ga5b=(03%UU+R++?+~_V|~C_ zA1+!YTO#nr)zYPH1hQBXSE{wgttu}pJGC%DoK;A_?I(9$oM3Y|Phz&Zh3!krT+nZ} zEiRhyW$ptT3_Q(l7S5;4FRYS6sJ{DUE4mt}if^I}&TWA=nKbog_A^Tq5zx+Im)bGr z)Sc6z9T!Wz7K|*VhpPH@VM>#zLMkvQin_JE(Vk1SRR7UehK16a>k3??HcpB#4|a6D z#Ggrm?_zP6g4Iq~rT5M&Gb=0a7Lh9&>VTl*CfMT|b0l8&SJ^So%;?nW7&jlO%&5zX zhQ%?hG6OBYZis}gV9aY&syg#873u|sbMCba%Q-<3Y6%jb1BVh%IF|_1JaaRl@5)KC zDtZ;>wO$`g;UZGz;}%fGilD-Rw0HBWOW7*HXUn{b1+q?;kOl7~4o*G>zseVw3Jt!%p?MA)TIM z&JysuJcT)77pB5p4S+UGn1P^ePA_w=A5!iQuiY+Kj9yZ3W}AVXthc6k*1iKp(k=I1 zI-*Aei7&MP%TvrD9060vV15+M*N{Nvd?PO(K~(5bQPTXb#rz3M^}uS~~X zwv)5*(*9z}DESNXSdQ{H%?}Q!wYlPQ%Al#ao2r(1;r(lzp zl-3__bnAZJ`mNlS*BgQ}DGKr@xUDYQ!jgxA zSOr&N;1u-a>&2}~tZm}dQkcrhPQ`Bcruj;oB7dEmAs z@7A*}3dPIK*`0nwiBnw=zTR#M2OG_tj2+LHpOm~1RbX!NLsW&vxzC-|P>AdIcIFeI zMI}Uy;~rL5VV1C^$X|OF6vAsxHiGP>RoBo}VX|Y4dDHhcB*9z!@P00wJ5Fly@l-($ zEtSCzBctOC7z@jk=Fc-%fzEUf<>GZI;XvQQ6kP#R{gu2VL$vRZ!((h>A}QD3ROO~J zP5Z&E8T9k;7mkaDcp_c8y6y!4Y|4(^y3@Y%qV~|Xw?8BuhJ{Jp3pZA$wOx?&qFAz^ zEze;TZ&?Zgh=|TGi-jPF_6~`|FE7wuq zlmLfy=H_n__8xaoJegZJI#yQnR|4Jn6gLCN-|1Onk}C0FP-8g zPSE3sp=HhL7Djb#k!OL(-`!5Dry@+I?lE zZGZOaUaSE(ODX+boDF!+&(fT&fY`CCIQ|~u{_-I`oi`U=5{Kyb4RB1n^vaPR@-F38 z49A|AM%g_V-}xC@z(-Qx#c#0}drD9~ksng9bUKyx6Jth)@W>)x^4UiWHQD%q9;4}I zC5~=mmQhkqJ6URlITN2zj5+>b`u6S_5v!n&m%koT#fN7XJ->psoV^J7;bW~O{o!f< zb7fZ|A04AXV3bkGsY zx=uT`j0aZyRs7yx#-)P!%8yU5*lI05XZtTg*&x)2^w z@-*r0_-zMwr>6xXP?`q&2twK7pKeFM5{RCm_9z+sd6OgdyVlhRnLLKn=1LC5;=0Peq{2cm(;@^JVpp>|W&R@jF?-3uP9EPv}j@QA^pv3PH z@@Y%NoAd{gJU>@*%3bl4O!d?s?>4#nl6U+_BANcpI_nskP~$tqMiWf{^P$2ti1Ufn zR&ey8ZRF*k+U3=s7A9V?$bef53y1NRN;A=(n$BHYr`WxO)kLfoPk;H?EwhvI=!(2VKz#&HEwhpPn02FV6e z1*-7<)uZFb+M~H;ri*(8b47E7BVbk)@(y%GbcIw4=!&@v@e{}rhz+;~$Ol*(SQ~r; zU<0HX;5(qysnznDuZypX-=pt&&uh=7pAP`HFT8J751lT1E%+0{6T}m_fZ03tgZ7qz zF8&qd6=f~{6a1CVmQN4h7Qq$f6{ju46VMaV6BGxGC#)y1Co~Qq#rvh+CjbtpH%K%f zKOjGFHvpahAcJEp;Znl=DDGtz5AoyTcRn5VBfrD$rvB-Hw?T}_O_i5-gavkxIQ+q#)wQcz$u77p)i%GrRm#dYTV z!QVf7sl&x}R<}Edms8BbeJ~3!C36mRR@0tFwfOsxdEh>ps?2WbKW}47kUsO@!7a^E zb9~t`KSU2FCnvhWZPq$ne0hmp{Qzy?zrS63Ax~b_(2ISSc0s$Ob}Lu7r?S5iRIy=E~0(*#TM|{F;!1jB*wSovL z%3}lScKq>*(3k4d2{nuB{U+W0QK9t-Ln0YCWY}pJdOt1WIv{uZ%Hj*hS~>QWp|=F5~d zG$9EOv$P_uSj%Sv2{aJ>E+L+A-eB4;1KY!THVhtNgH>W4L*NLzs@X7R*0;1S-9EvD zpGA^cFl2C!*b&8WM&NPcNdQ5*3Mw9gp@;BgbD?(Z73%|CQ6_g6i>eVdXLPlH+Cu<^ zVe$u#lut1?1~k+E_Tf45f@TmCUrX3)y~2iMimUm%6p8XEZZ8Cog#?18)lOhp3yz zH6y7Z7MD3 z-x~1b!L1(q+EtB8;(MeFyMeksiV=*JGb^t~eo=Y1;B5y|Ld=OwXVUI72uj&<#IGS4 zDr?J?pm2|QJo-Ut`tmLI%+(|Ax~upT!=@~t{-wZ5R1maRC<*{8QSFM_pgsMniL~Er zZ>EB=-SKBtrJvy&TardCH~iS!<`lSUm(`M-kAQ- z!2-YWN&^cbcs004Rznc3nnHCGXoiJ03;Ab7HSrUyg7yxvL5VdY%8NpO=Y}T6dWT+Y zHZOUicicFmby?=vKA*@~nfQroEpJPvL|-S2ZOorGIJQ_91;=Jb=d>6YqM6TufHS)1 zWEgg4T5)+qznsLPVMFyJ*#P<`*5E^Z27MwKv^sc0bVn++-$c167UY(#3182M<j453)lY&IgYn7;LSllxxrgU9g`HcAF4)ND>XclG= zY6V<12J9@!q%)30b%6XS1(nL87z*-GX;726!9xFP0He9Sm1$)ANOqJW_DTZd32_JO zP?;fnxUwx~jd||S=z!0|BiyrqemnQ)eK1_6BfV?P4_uqso#YiYYFD504%D~$6$|R8 z7*jvlwiMVyLG8fLa_8FOmgHLcC(wTyJ2*#IP0cURpwGVr4YK_W8kDv9oAl~~upmrl zhg_l)V2(|}b=M5L40fhYk&IN4B-*c!Q_}67xL0`20K*(BL6(#Kga?UkV1fCbi7q_q z(uv$Pi~%z1ST z_$(GyC`R4B3TDW01pC+6g;p?SSpD9TCn6=Bi%x-+P_zzmO%wGVV zHwU6Ao=H0NDYsA4n0Ahi4m}DQl?ls zdVTl;y)sAz9mX59)`A^6M&(V#KQ?loxDjs^9#kRuWa(_!Cc|ZSCZvR?I&HyX*$P$j zF5{l85tJvrFSbscz=rd5b9T3#TscD#Iihgu1kG$vSPl#tEwis$Vxyo}B)X6O;S9Qw z;QR~oYVd`5ZN85^_gFEiL-5}&<2ZU!#V@d#vbw7^&~)Sk(eF@@kv zm5d-tWQT4TQqP;P1qpUYWdBa?U(!&nuE4evK1e{eddC;;fi1Sh97Xrq>`nBLQ+KTc zSYoF?NYT}k>w{@|(bU9e2DgpRQtJb`+1BpIhdOk_IbL&MnU*}>`h9l1M4vIdMPjFe zSP>)bNsi`k6-lK1s^40= zy$cOXWOYts3)cw&f2@&+CM=*QPZdsq`U$H#vN|Of6{^J7@l?BW%1fz~1znI*l~nxT z$l+&AK4Fz^QojmR^k~;n>ehp;Kqkw?Ra=tII@_DzSXPbM_U(u2i>mKZriJS22t=TN^oS8=Nv5Qg zy~>i3_%1LqDXBEe5T}z=tNE>4Y!6pPNSbmNb~I1Oa*{aq^9lu5P!eR&P}2I7asb3+&LaFpD_93oo6Ls?w$5 zAT{5i|LOPiYZjv$k{ad9;>d{Xut4)4zX_q~MDhcvN~UIk_$HW*g3pss=i8+6K(4=4 zIO*8|TB226U8bbI50wiMDme)!vJ_e3Op9jz5Y{_Xsi(oT^i-O;XXBx2Q;uJ^Nd&t) zC?}HzWQN#P}c&j9zmalOSn)1!I4bwS3~7 zOR#YW3gbxU0HZ76yB!Z6=y5&wmDkYxBo10ro(CzI@lNYv@y`CD(q}a$GW%*6tSsKI|`Z zPFOP41z!;d283fcS3tl$Se^Q0T>={IzfL#Iv|R6u!#M}q>rEzzc`vas$-wCl<{s_p zyWXN44(UbPP}qf* zvhKsxgXY0cBj5u2u&CGXv)u&G|9$G8+2OjLs^)*twch`BMPd1SMfo4>aM!xdLW}k86w5#q5T?_d)x|WJ| zXnH(tn}6ykZ!Wp!I2$Oi#;Br-rw>nq{?3vS+FwWa z5{DF1Wh|ETrYCXi*26Q&SpmScKiNR%maSEM%=2L{hC{oK!=Q|2LApq4bKpGj)p+=N zpqC$%Y*o zM(*!n4cA+P*lq@h4QM|Ff#pV`z&pgfkVRPQ*DzDmJ4Nfp)Mz(k5Cc^WInUw6^k{E9 zp9zaCtejcHD^BfRGcii;2T7$9el!W_*ju5P5uhhxx$SM+HE^!RRzO>Z~g(vqK$rE4)g|wiDt^UO#JB z{pRUmh0jJ6^i)*`#HxlvXFacR@(nsPekd-R_*vh zxv^h9(+-lo)_9O!rG+G$qx&y(t#}V5(+SRi3rA%`EM&wNy4JYN?$jt$ z{xmjxt)a&k4sJk?ThD)3DgAN0M>=bPhvj^)8worTkSf9R)vNsd|&SI*M0B}Q4k+^ zNbZa@5Y|1_vjbNMd5FbsPYRK@)0kh5@Le0cpuk6?JRj7u*l5Nl&1`=MA#XVkD`*1& z-2{!s+x8jIig%h{vD_W1S4UWc?jSiNI>&I#2I-QgWGQi(eh|DQO$Ghb#MwTD(?`%q~xIZL;m4klI$+EbpVL*z9OxSZD5@< zJ1x12rVrFV2OS6?A~q!-_Yyn*1P4A!f(#0eU?(l0@q*NkDH zJ*KrmlaUIe7=bt*m3s(6t#I|fgV-SER%xY3Bix%juvM1=k{QSp6VBo^N3y@%AqKX< zdW+fOKl-*hg%`cMOOv%ig|p`+eH{dx0}(Cn12?79u1TxRbb9APesvr`H8 z5SfGpiVUgR5ULQq8v_3j5F%0iC{aw^t30izKL4e{omQwBAw)I}{FNKzgv9&g_ybTh zg5KS7A&T8bNEh1~UUU&`Tnc*^h^lLLvKpaUFyzN!Sg{HJY3?!J)E!_Wq7bSUix@{* zACg=RctqClPyj%953${xE1PY0T|Io)2x69gSp6y2B~a+$+DMt8*lL%h2-!5n*z4=E z|8^*A@e*O7d zLio6wf<$lJottmyf$I=^1#@&c*E}xKfgOI<#Qs{GW??*6b0T=b+APU|t^|oaa85*R zB}^ku;XOg^6KSi|1DSk93pJQw70cctTLaOLbRezvWv0t91{O7f6 z@pULqP1E zL~^6eOO?+ZogT1Cjbxf#_T-ZZ_L7w!lN)VlfS|p*k6UXC?p!qCqhOHnYst|#yg_jp z$$eXLkEa023z`7QknUqmN`#E4^%*nL9M5sATS5A_So(Co#fbC0;@#pxT8UPN{Svqe z$RS3spdZb}-jV5tMMvl??XW=wD+SPUFKIpZZ>%gnT>85}-B>ghTWJKqx7Q3Z zL@8Y>R`ozk+U9~+1UGbBsg`VZE!#G{;wvV2Uu{z~Jh@t=b=!gfBqG;xPatZ@TVqJy z^4_V>rh~CEngF4wQ9oVkM$IiibQ$f>(oSKP#W=!#A0VP^$)|*%i(f;1p;%plo1=9iU zEJ`308guOgUd#+)ME-=6(%r9SM{gujV$3bdanHbQ8c5WSa)ZXUoOb7{ zEEH}wbcXOCkVr>Vap%vgfHWyEcLWy0qym!-vXeXyEPUZt4saZWA}{k1&O$?NCR8aM zo+hvnnL>5DFwTq6C7%ctq_wt}wmx34#jxOwBAIn_I+L2;B{Pn!u6bc?H2$VJfY1oKguViPuTT%zs2?i*OCe$)nt=0EE<7uf zDoj_fc`vkT;G6sL_&a`;;7&&j9t)C2QZUZ=0FimI7%DtsOX?TzS~|S|RnRT!Mv7v$ z?hAuO_et!s(?`N@c~9eq_1?PC&ah0i8mMz+{-m5m$-l@}-!WSis1oA|=?D+B>HCYYxTd&SI1 zw+30^?OwN$ULxr2ii;6MG8(c6jH!5y2{qsg5RD@M0M7xPHKm(LiaBBT)&;l^lQ-ien-^9DxZx(H|%@jdwv7QO0To23g6Tv~*l16zS^&Q`NExdZF?dBX3=oROs zljh*{u<7Gg8z-~%R8VHZEK;=By5kW&{@4;F6u&G>L0nYz|7q14U7h}8|LoHLD4=}W8kCA}K zmf?2;?9nzBzzCa*9sODtUUIPZ5Yr1~*5YFlRaLB(?!=6ipC21Lt<&jcgdN z^~i!8kh0=&sCqX;-H?pi|--CGm)$*Yr@>{T52cglMV z%g+59!Dl#sR1fQ(_F%1s+c2UXk0C}%GzLrZ_WsiHhH5^2=yed#Df0E%B3xu)X&5e4 zae+ld8k}d7TuI8tZYr_MX1uTtTRj%t9@&4|=b#|`9P{Qc%4D`DE06f0X1%@ZSUyfM z&L|D19Cl(ROGmAc!;$Z1TzKB9p)mv?#}UP_Dp6A#ZF3egz3p#bmy9qX|;-9+|D)KHa4pv#BKF7W=f67TMM5PCr5Z^ zrN{F1jN;om3@zDWaT^OB@XS$6(K6rE@iQ2>8O>%I zjRuchOJ9X~QC7S|4Mw|65)>6%AYcd?sVxF+*5-xjq)M-Mv6jx!Z6r_!loAzg%CntgZ-pOVOvoP=_b=p!#n= zdvZVylPHGCQHZ|o*MWgA;7EZ3lO@SxDv>8+Nx(9MTxL!&)bs!;Cm73|iKRi8DmU_^ zcPs=%S05gk1?L?`-^cNswcgZL?$CsWB3s7I&dN%~V8)ikIb_|=OeDkk+I!8JZXHLH zAAYm*@x?ykBRK)c;S;rPJ&y_CIBoACI#lzdiK8sp98|sQ!P67&_KLW_pIA;!7XYF( z#xX~|Rc#3HYXY5DY~aS0xD8vY$~9pdh~K3#y)6kCknP9>t;+0)EhA1Gew*AxsE9;Hvc3Yc$bO*5U74KW@wITWm$ZaDMWY7f&EUNva0E^aJL@ zk{*6}IGw`y-BkqM>u{xjl&TP_hHDxq-_;TmLD7tvxgRiy8Jg6XATeeIX5q-$>lMkG zE^+o8T#E_@7maVPX+fUfLS;+>^{L+tlCW{*gDgz`+%l|r$KVAJncNZ{`qrAZQpJZ|IKz~346VAdbT36%bb zIo&3ahDr~2K$4qT30;-PBmsI4`-U$k3a9J4!a`RA$?s}B2Jt5Aw3YwoqCUn z*C8D|MTLdNs1IZs-x(f}Q~zSKug`j>$&xF$=jVi7J%s_5n0ai7k?$83)l+70M2;G# zU(m&{)IBqRb4)@w6si4P6W`^JHVxXH9C(|0#grPpR(KI|-C(MT31j}t+C!V+^2gef zNw35gfz#kZBDx5h>1xWtOm!&#p2;WQno9pKZQ9f`QD^pa$#n|zj_J|yA8ikD-IyD1 zlW-Sqt+Tp2uc|n`9yEPAZ-5;he6qSlKszp#fwB~V{+cRP0j^lpRlEZXeDYQ%9pggU zZL+gCuL+Qx`Bc)Ak-J0Fj%BOcwcMt{U?HH*j4!hNdGCe7Ca6l2Wy=t$s*S=AS{pj_ z3b4x|0wLl#(5y!>J<{akbE6T}RZD7=3i<21bc_;5`ZU3U^>a5umIU(bEnrJ~!?g2{h^%W~=GWf7hlZ z$EapwU4^W`WqMm6&dpTinG`q)1~BE}@97ZHhAV84L}D4FF|8wFTqtf>WTJ4BTC4QdD;}2cf zOMAKi(u)M3U!)anh91jUbKf@7XtshFrmWucOV!^;grSVp(FPVL;%Vj=4_RK* zkrfSlt+B;aOHG~c#T3DQHhXWqd;92Q!eqI%mUCS}q>3o|b8V=F zaHoM?aJB*GHLgfcXhQa5>tObNvm~lFQzvX?lB51@;#Y@#kc%=MRmBXAm5F z4yCxzF158LK0?;)h=fN+{V*m@0rb*zuf9nrA}O}-%#1SJzhYdf-*l8d zDV7NwQWh<<>Uuj)B?fl4*dM5=p~}xd+=?X|DR>zE`XbkgyDk9q41!{*pYK$v{teHe z+Of-uBinUz)Zo+SxCv+wUv7lJf%-^dld~cZ;en&piJ zCiE2ffI2B<=BaPQQX-!MGafFxibBPlv*E$pTI=GrbXsf;jAJ=xpB++X#D*y&dl+pDIk4bK!WLzCW1X1i zRsbI&dJ|#_>=V5gJ^6PSx$6aGbg^kB+-Q*S9mrz}bLJa#@HLUgEH016#M|HtOn=_~ ztC=skJn)xYG|3&KmA$H@TVu_J((tmSLcpV5;&LfdN1PPd0-BC z6SK$pT>U&y_e;$2m69Q7C!rGrIaa;Wmqna*&bv4xhSY9Y;7iy_$>b&L?Ot_5tD#(M zBtgUiyCh#(>=uKKSVs2z8kPUu!JYR+CqMWa&EBtZBmTRC``=C({B6VjTle~B4)k99Yj?2#T<2At1W{x(C!}vI>|aAt`9Iu@QJ{kRIHfVA#COSiw(b zh;W%06rY8|FGZokB0F%b zP_9D;Q!=vE$Wf z0~p3mq&$|5af{5f1S~C@!9!#bd*kV>-EuRCTxvD?06)5A6-^39V+C_EZ!>O@cFB|W z^I^~Sxvo4+XY$h3>E`L;AH!79Kmhk2h3T&&8UGZf^Zz_dwF$5gB-mLciv73O+b3Wm zdcso^aSHw6pm6K^gCB?{{Z3^ve5i_)$}BPy$Es!e=b_PXUneq>1XldsYuwrI5Dls!FnE2TV zdTo+|NS_dUn`PLN(@(O&h>kDWFUCd?Yw4H`21_3@T=5+t2$qvsR0tLtZMh`{y@Nax zW~qqjMOmasVU~fZgu5slmob&dK&U){??AUT*-c?|xd2naD&s(Ge-p-3J~iI~%l@#L z08YAm^s~WW(<1_YwhNR*J4}JnLw{m=iv^;!T&z(4A+Zx?2J<{KaC$kNGEoX9j@b88tVc53=3{q%w2i;)_?m^SdOG|BAKh# z_2hMQt@7_$w$deymJm?|g$IXmu2ZX=1@@v~B7e(*VFd4QnkbMO>dHX;Rc&Ui@-gXq z5lQJ@LilJ6zSCNq{>IM@7tr#AaV{>f69th}Pd@bKKXKplZI&!%1gr38rq-er^(K$s zYP02MEzHJ&`cBW>P;M7!%RusTZ^EdBJX}hGs_dIt_RX)A(+>KtF#PZGq>I;7|DV~Y z|8L?|#`nq%5PSuStP6OXuJIS^5Y764rOclKg-}de2Lrpc`emb*-F2RKqQ^4<`}o|& zU(D!rHiYNH2=PClDF9L6w5mnCvwHNr6_5-?YC6O5&m{(Fr>v=2q@Nj0r3+fT^CLlp z@o#2)h{**1<)7r&hQ}alepnS*b_aV|^b!kuMKpfV#=n@mFO#6Gsi1TGUCP-YCzIZy zqn!<^Sdt`U=O$J9rLjU(43Xa7@D+!iuso&x48LT|F;&8=aa{ZnFFRa_WixEqpvf zx|Cl!YnYi;O$o;H;S0X-kD+akl@a~VLi>M{wK85-uAc!R=uzS~VLGq#Ts~ADSCT?d zB5fithDW^m0Drx#q;-rU>Z~&4dTl1=Yv;7h&-MHE@#v#~`d~pp`;i$4>LfFapSanV zcm&XK*rVJQvAw>4&im(+51`z5U!rfSFVVL?P{5byTfz*1)*LU?$#kx;S^G9sYExl& z5ZorV`o>fEy$$S-=sO<9lXNK-7c3>S#$v5q73fjb)11X_$RE$C^?_kiW+&gTmLJxGCg$0clmUSds=CvWBPvIsJE?Zok;r3-Jz`L zD!V+s1;6GoA-(EU?s2evK6L9`Rk>ztVy#AI$Cpdsu0^$Z{(|NnNV$MHVp(n6&-L?Q_oQAb7PUUsB(h)W42 zs*g?)L2wD=X6!r|ze8n39)B}!f+i``MQDtg<+a08h86=e#??(x>zd`X18 z5>4i{^{Et$2qUAU7WC3sSE|SUVc%70b*f3dta)z)up0@wnPGjp@8bUBTT+)F1%<)S zzZ~j=a~flZ|I49%oxr72|Hq+z`{hul{^L+rTDGX@^<|ncc?Fe?@+)0N2`5T_*?wHgO=srpzVLQT9GU9dtVm!{akM4 zKURzMX^5mUhyZN0kN7!M*+nQ#UpSa9TS3k(GnY-oFy{gqorDEg@0rI``&3RP}cN8MJr1$kMwNgW5HF4(7vfflmSC)feeOr)9?O0 zLX}E9&nNHV*WJP~u^(XcRO|UKeWivHYOQprgSn{rSd!Td+7X-PTu+_@f;khp`)E@5e_%GMf|1%YwS~^et@1XtkZ_tj)c78+)IFj)Q3~L2-c8x zD>-}pUiQUm8^N(Q&sIm%xw_vT@%{RAuvs7elMPD(F4cVqKl7dg=Hy> zc7MZ>pGD_a`wcRcmG`c<^uRtM=u2yVdE>-tVB#1xjua*p+x;eQ6bx;Ocpl3Ow1JNr zImbd_?-0G!du=TrkM!uShyRMTZBl7HOsxG3(5yFclSuz)wJ|E5%l{QG;`kS`&nz3v zi=J7wyj^|Tf^VUviGXloNjZ}I+<^3qndU47696D^U)>)BB3Zxl?6u|#lxQ)a@SA0&XOOv^goI8 z_$iZn4z%0Qo@GW?iZNx*vJTevwPB5Qaqc`^Y3uh0pyJ>kS#P_h&+ zyAm^^8u8VsX4hY9_{MHkpWUhg-QLvFHQop@x}+Ec^GM85c5AN~=i=J%1;{}oQ`|BjP+=O-{uzOBBao=&r!6gjeALIujTu3n{=k>poe zT3V3+_&R@Q#E0UMW*uEg+;!rTorE`Di(|9?&5KN3ICvNL`O#R{2hiTK(5Nqu=;|G0 z*f44*^ld94#|esb{z^TJrE==}{5|w-k?d`v?~3N80I7kTF@LR9vR0foQznnW_aU=i zX>&g8bVX!O!{MGsw7kN1=#eg@f_eMF41C1)JU^6cdLgQyDd|lTE@b~poOu2NPPQbV zYD_S9oCl9S{lE6w{;_>|@zjw2;i)tKr>Fk5bRRc@ITp}b&&}lM1s|D$jU&5wMeiIz z0;iCPk|wfj_?5p7+;ne#;6w&D-R9t?+vi&hxasavkEF#!E_D2ArloMkTM3nGXd?1h zM#p{s7*~ODjgHME)oDXJT?5D`Xa=(KPp`RBDy!XO_?YPg(BUFQrJkFYxTzlo#`YQ) z3)P}4f$u(?dn-RXszsabkBl4CgsXUQZ#7N?6H9c1cb2E*{r`MJywB7y#eW6tzqc;` z4<|as=R)8UER-cx22cKOyy{6OK|lHZZ=A>h+`71DEV;Dq$Rr%J!&pVdd>E8~rYIZx zZF35AZ*(Qm2znE@P4k8v08<&h4_*YAImW?hC^CE#z{zpX zWe!4TLF(dU277jeE7-FO*H(Sm#HU@o#2$+NMatoR{fpjwBo4!}hZy-73Cd?JrI>k~e&z%*EWhx(%$i>KtM7tC%VOQ6Kd{Oa4MqF_sQ z7^)jfZx1D~4g>qd_q~gr+0FQ)Q@htD_^L)Nq6du~=G01!P|A_s44SroG{Bt#@NP12 zxYU7p^$G#p_&hIFba1sadRe2Gt0H4D!H?+`E$vL~BkL2#6NI)))u2;fM&P2{be@|x zwpbcCMW9 zzp)P>kgvXF&wuNpACvuz->=^BCb>rN{5YCK2n~HMzAJi~sgiAa1H)lUAD+&Z|A=B_ zh_Pp{q1Rzcp(wBBmAIL^M9N2_?%dH#ybd(%hA_zp@L3wvk-NqV32^xLo(=BwT?!uZ zE+rGMbkz2kVTXc6P*Uq1nR0Xz&3TBLy+1@yi7dHa96wsFPBfV8 zeT9g@CKt&#l09%67iFgtYeT&xR8|a2z9%8y9V0>rF&EYwz0NvZNRmU=Ybpz#d`d&M zlveDtuCEf`a@cNigmdU)8VzoN?{y<~G8&_Xy7b;5jiH96zk>-OE=INK@5D}RU3WY2 z3IAWxqqchF1l5yqF7L>$R8DEp^DY>Om^lm9RQnTiBAG_Yvy{TY2k3TpoymMzC|??l zZutTXwlr3nCrL3T*Xar9sQ5_}xAgiEa=atNrPr(Zr&888tQwcZU*jUWA>4$j?9TH) z@;RDBYE?1z-c(x5muO*jV%;NrDs9lx=jn<#ZivZXfEiMG$6B9s%hV4goR%=E>7@9O{w{o_<6Y|bhX78v#nIi|t+=lkEERFrDs|fStoSW1!~h!oDIYe| zpKlvaK3^49_!f#fajl`0)KgSBr0JGxwxs*Omi>xPP$P8s^v>dBg^BjBb>5C$yyQKU zJV7*L7d~EhlXa= zz+k38ofUW_9m|H@80^Sph^HRU__~6-F*p>wyj?ng5gXRvF&Yx=G>^1874Z66(6|4P zEu!m@sqO)1nOT~Kpi6E0g5LL{tZphIS?C%jY)`L)t-Lr32hL!|ZishKgVSW@Lu-xJ zxSL3S#LZvJyoI6(Q*uPttJ*c(r$JpAb}B+O-?RM>+awxgrd+$Nwln$r|g@; z-hAuW=K*LacMWJ_L`C^d#QOCg2`%U%?e)D_!&2@nwO*}soK=gP6Kf|V%^}|f6F`*) z9j=5Er8$COOJZqpr~&mw0Xe}d2Ko&NnCYZFuYydQ_zs(rHQ{BV|S z-K1|kQANEO-XWqk5Z<)>{YD`{XXW*7G_?o+U~>oDq3hrWugvnM?_o{Z+=z85X{ZXH z%$z#lo*M7xd>_%M#z5zCWPnhj4BrQe5YwgpaU>qED|=Zhu7-l&JM^v|Y3msqZ`d|? z=A%wtEr{Mume0!Tgj{Cro}ff)R~58Bf-UNQ62<5pJNi$^uU?HV|7Tl!A>R{eZ&Pta zJ_NcOC+u5evc49Cd}B(28Y3iS!67Ug zIBX9};5q4I$*8)g~?aADey!BvEJH_S3-rTna2gGTCJ zlB8T&(N+w3(JErqaVCgr(|vUV__&4NY}x0gT2J3X%-mmKS45R1A8ZxZz*{iTCNF9R zgz5JkU&;&e?$hVbO}C@8Sw^NalqLI=S#x7v*vdAxS~w!wXR+g5 zCfeu7hSBkB6*~;nhI}K8)C`Ljgl~&1E`O+i@#X0~kEjw1vJ*lP46^QyT{1Va?%PQQ zWg!Mj`+4v>>6!_V-$?7)n?&!k;Nw*T1pHDbu}!rnjWt>|A!Mip!&Ut}e@4^HRqA5( zP!sQdY?u95B#|kNkFxLT98FF(EAhTo{5_?_u_|GaL=S~Mezci#IahF=Y;mn|n!L08 zQ6UEND-xE$saOt1gxdN#bWw#8-4XP;JyL#O=+FsY=n8iznV6p#%mySZ5@wzPlSD-l zk_T|f@1v9RCxHC4x%kZLo}@CIdWbe0DQo@T=*$W90?Y?bHa==@ff9S>G_H8~sXMf( zH5VXC=cTX>Mn(yX%t%Z~uz$^@UO(`q+9Y9*_)g&BD8464gw<3gNUo9#Ab8B||J*$ZshzGC&u zEhi|_i_z5j8gvT^ z&|%9voSVA(>WyMs=oOd+G`U52n2uQ&q17Gzd9SuC7RDJ#pN7D?P#mX>`(s8M- zGA{qzbB=~uVdt(+rbBpIK3-z1-pc&tx1_lI3C}sDGG?&gbmKfq&n4D5N#$GM!OoX# z3(AmkfYz=ZYehZYe)i>_)x#o}I*m@+?7Sq=g$0U)-yH{aw*^PTy+286$SG%3OO&|H zM$QwbSzCDZkF#PJI`0<*?Z%kPSD5KPUjj3#8}Kt{#yZ8BrxoHQmitvzqsMN2pnXYd zKIxL@f#)CsbMq-{>E~Q9gE!s!vd@ef`)6?Vh8z?IPK?T#f!v*vL^niH!kBuycj6>- zni9F_WKpndAx&cGIJ;39Sow|ZwXyGbRs(QFzv*7t=AJ+uls}CsUJLhW&%TQO%u61n znJA2s<=-pzX$@akPH`9Cm5VxTJw%zF!Q(A{yCp$>V^r0)n_+Oijh@qw=-8Nw#eIC5k+LryxZ`~}lg zB}L{ABJHHk=uq+5VajHYv6UIR6!yb2^!zIknHUD_@3W>9j3eCS(oFms9l&Mv1Nj70 z;~WH4-E%iJ{}?c4We+prluW<@lm3lCTk1c+>c%)MMy}ab&vhJA;Bd_ja$X5G8B^V#J5UNf=U* zhi}NagVKdhMTmk|q>fP?9l;n#$zs>i3nVXeGP5b6FR&AjcCkkwd(L!9Dr)MbTabb) z1rBT?mm98MlC>zL@b%&w?HE89Cw%qkfEN_>L+Ocn;Yvx|^w=ftPxAV`ty@PVbDqm; z@3A9TO(AVhZIlEFZ29#pP}lNVAbsUn>}*0pfSGj;4X0jwbL!w(0 zr;^mcix{$s4fO7s66ZjhXiVTSwIm#ur)ylC=ut?r=z&z^=H!>;IZALL!kxf5suEtR zj&eR>TKy#l32@&kZ}cuZKX|L(qLbNKKAszxy4gp1w&AFX(n_D2Yon+8SD~Y?Pob&9 z7BN_4xb+q>^V>0kHcpI$)aa7v0ael4o+~8&cc;cL`b2jnc$PA|=}j=7c(_U>Zrb#X z^<#Mau4D{#-)hj~P{zpxVaoue8PyggQ-o0tRqWm!eh<&Kk-NNj@AmF6I9xxLb?j(M z&sXf`PD7%B*fXZ<%;4!$Z(3~kE(oeznvpMFozlU}=6lD3OG=#J7EFQoDrl~Zgp+TA zfc22^;jVyt9{?QHP zFgTs0=VZ#qZSF$<_A)Pgue-mLc|MMU*<8ltN_Mnm8-B%}nU9{b-_Bj)m+=lKzg%7!X-E4_KL3lJA8-<8d%@|H2K z@7k`{qkWK)q#Z*x`z$X8jCc4YSgSPpG!hAqc7adPO}Y-iMAOxqst#}@Im)6@)w4ku zNRZm>XHb1f<$vd6jVfXKrA5{O=nzeEvY`X^oSd_6Vboy^hemP1g_Z=>t&?tWj+fTq z*>fr9F)R@!WU{aPW2AG!&fO2#T>@HAC}Jo6t~8D*@T;i*6bIMj#pvH%ZFs(z1W7Rc zQT?BCUw=Y~t-AHek0*u2pG zm@dJO7weJmxXFAmTC#Ndf&eocmq-xCvrK}28P}IT#ucG%b`C5wTfMQ!kf4qj*>IJpcyRi*- zn&H3fWc@r3ZqTHInfw`t=Ze26{bN$Y8h^W^$D(9)tpz~E4L8edUIZe{)IS7z2YEVX z66{PjZ>-QI8t&W}%ZAoM=o1DK=s6J~{x-8M4T&CY1T#%ca*5Ucgg@?gW0wfc#(D}a z4;XTfKalHH{(-#s59AnrW;S;;5%fT9Mm?bMp9#oatLO(N|&qY7Qe!nxP4-%}J(Hjs0ESD58*%UD73dg@2Q3;gECHO3Y^8}YF> z!Y~?H6XCaNe{o}>>p>pQ+rImW4arSVgqgiKkESZQ$nOYQaM-vG4jfSmRroe_guk<^ zAKQm^2qIOD{y~s-K^WO}27!PjVXCp6TIO}l*n5ASWbjFT`+gbC|L(+|+J6X1mawLn z^X`J<`v}=6fnv5P70(xmcqsP;y#~vG+mV|rvfwQceJ4qRJbDQMP+FP~ecFGC`7!P# zPz9|7il11#NQvr-kops|8fc`ebh{4&=~2g#PJTVGslH1iNF@p&AnM-u>oJ%>4eVN8 zg%Ybbwt3P%436>3AoenX;+1hIi*e?;jjjT?PgHky40vxJXO~oJG;;C9LeiM$QF&zG z)qI%M+%b6&u0-UR!dNGcI3yxBv8fT9$=-#{rhFW%{gNzW=i-aL+fRD2$w?hHlp>o< zvZxKn8+9F*i0MkfDP`saNHd?bG%`q6o5=z^8gm!t4f96bJI$h9?5n}GjZh%5I!FtS zY;54jwm6TSKcjsxXy?Z8q;tCsRp+n~?Pi}6CweNH4Ni8Tirou7n>3isS>22TU^muv zwkexr?57GKbzw@Fs&IWmHtNadB2MQ3pYF5_+@{cPAX1#S%3Ds~rV!N$lgSdBP^yJ4 zo?==3f=(!Afp;rNqoB`cnFC_f}78aJZ3r3-n~7-R`cknB6MW_H63=Y z*t`|Th{!=W{A4ny6=syvdq2c3cK5LwwG7t2%=Ds?{vo@`Cgbtyu+|O#%4y6-?wr{s zk8KbY^?*4@^ZB0?Niv_h+3{grc>OuEy)d@tLJ+eY_zSv?tQjIG@ZIms1{`Mj-C0>j z*``lvMRZGO$K=$=N8{&ZwEPp>bJ&MU6Lv73J?73+ACs4E2FbnSgO8iI3U67@jit;^ zr%4p7$<@kR0efeU>y7;y4-PkYKiWo&qul1X4s&-V>-|mjabaj+NAD*)x6Qy1)-Qe( z_MMtCSuhkxZqqPxYaE9`09#1&XoIdWvZgS#xhrb!jeDZ8t}GyaREqpwcEKCWH-^9r zWhki4>{{+6aG-Qz@J+5z9<}N0vi~hqTL`zA)-qy=pT;v5p@q(Vu zgGo2fTPYXLdM=X&mo$^W-=Q$?Pi!^9`_r5${E3A5{$}XU{Oh@8NV5Jr1{;BwZM?7t zjC*3du{sy)foAu7Ar_jRC|JOkzc`i#pR`iJ-z0^x^H1Xj{U>%amAy3Ujh-4Ry+hdZ z5W4QuI5b`Y5g?YckHErJ*&_N6&FnLcr_Pvo!07@5bB^w#zj={<{5WF zd4?(P63ZuyidF&{ceMw<2G2gmR6M+N+H7qu!!3j<&6SpY@P=-0@NCFG46^`SAFE@* z12CcBy$k>0bg`G2xSDt#zy$yM0F#6MnUAP9@{!_b%RY!y{IHsSw8HjKP}x~fC?ww@ zD8)yhNqjQbq_X($A%!Wfp*;NKqazT7le}M@?YkKf!0-}pY%L%THI>L}j9kw4Qy?Mi(K|S37s37&3W;*=Taf z3ul#m-B+tK5mC=l4GI)Vff3=y;bm#f+G8>K{%D@li8-|JU=xt#8Gi3cTq25C69ze6 zbxMMmznO##pERmyDd84|R^8slY>N zQ}B*hQsRY!RTq^uWOK+zC*)K*pCOR}>2;}6+*ozvFfs-$1A0lscfdk?((^1#Owu0? z6B=%@KZTZ}RX$~1YCvJ+G^@4;X#RKyRDNhwng38*&fC!|@*CFV^WH|CIg@>=J!fPG z$B7#DXw_*=W+Ux~(u0F1Vjz4c?S`1w_wO+Zf*)>}EBR80x5n@` z89bVCPHj*7AH1@PZ|}u*J-uA)S(YJiOUjl!gn$TXrXe>j%axiyYyYEM#K-BotzRRL z))EibEZycemu%}?++A#k57+e%o~DLnj(vnXhCUJ1e4xx}nUKxAJJdCk+T5S6!n{#VZyhgwW^s3jF&Ic`z<;&Z}&E8P`W77(t^}48k9-JO!${f3Z ze)Z}%?|&XJd|5?1FgFu{rh*22tTo9rj!?%=^M)7#{u50Vd?!sQ!~#T)PxDE)^Jo{0 z?k9m91vrfN6EL=~6NDe&gbBn$aYo74=nf&aLjqthwB>D|fK8Lia@J{FAJTG%3G17O z%9lXn)e5(9nw0nGmS=BwA_!6;QFgO0|{GheJfP3!N7p4p7_Sp~TGQsgY4 zCi1kGlEc}G*(r5DsNR=!KYlj0VrZ;zB84M7goE)JLS7riAlchH`hmr^6skIxn!-?V zQRxl%>;z@(CH1-EEty*`8fyyFW{F@@d9()hk*iueymUvMt))fP72$0|eA!uQO$1V( zld01z2u6R7jqqU2I(al8#7qwkeFiZt?$VZJEKUW6K?uty&9SL4Z{Q-vJj+h-Igvfd=oKOd7>cGGpb>oGB z+ttuorj!pRr5SM*!Ax|v^fD*9+n+DdG%Kays!diy@r~s`STX}P&<0XXi7X(j5~EAV zDAe5ZhEbZ@ zb1QBmOkJ%KQ+F7l$=Pej&n{L|PLE1m2ERItt|nEj%ajv;k&EOXbdBfuJb$Ub0#SK$K07|c-A;g4Rrc3SQ1ZCDg` zyYeJOgQlr(ohVLQ(>J)-A}Zw05vWgj;x|%~LDTfN;Z&!1zfNWP*R&{a^H;I6Dl2Gr z&H$QI7k%g4K$UDjbN0<#28*|qt4E2*5`zfPq}pR^RGA} zSn8YA_q=)}cTQin)vt?*9|IP{LcM=eR#uG<`U2as3Nj+Rx_iO_gwEfNZ&`!S>T!fX z9al?j#F4jNLbTxkWLwybVfbL6I|KNQ%wQe1Py>%|vf+f6@Zl#{@9=8bf!$q%9=!Hh z+jAjcy}dKhLG^xr>3#RCr5sqxcocA+0g=`Fg^1@QU_I+Y|4IV$oCE+)()3caYIbiu z{X+C5f#*y)F)L>xRY#=ocyJj<4+~Ftjpq+XM$c(Sd%@z+Z69@ij#M5$EL~l(PMlCB zuW5k+eZ~vpS=SHXgl^A5H}!2Fuc3@-fxU&@Cl{LO(-@O?te?L=gzvi0(5kKP^`BmB z94ATbZUS;Ew4y5b`lmBG!9qSDT+JLw9ba^Fu&HhSNRsMq+#9vjit9x0t#eGaDzX1P zV6@tDVP03(`z2)8YRCEZ#*HIqh1I>aV{49PVwHPqYV$a$e{a(|w?Zch;1mzgK?K)= zG1aM~;SIFi^}vVK`$47ky@AuR;gt}>B|%c4?Pr?4)00!Mz_RksDN#s{rG*;~awq);@Mv)stU4z{!f z7x%bd4lk@&;w<4n5B*Net7Fb7^NXJ~pHY8YEJ27^ZlQNZLa@~EESYhj8- z+veNPkJ>-=nv;Dm16ONnjcB+D5)J%+Oybfy=n;UX<7QhI_JvOsJ+sGfKv7IrAUK`* z9n~5O!MVg~w);MGp1DDE%SnSn_<^>6WPM@ZbfF%=gwO!ImHI!hzL#}H9x+@1Q~@;q z;eF0UDAlM=DM0;{JYy)FUJEkz^kf@wpW-NryN(&;d>ByLb9!)?xxkl&jo)_f8Sq6AZs{#`(+fxkru*r6xZa@upqQcqRQSw zlQjdSbS`&5qt#uqcX*H$C$7ByvUxgGyJN2ov2@c-({%Q#6 zYWUW*&Bf3p6N-V8uCa_m*Za!eJWi-9r`5tzcT!tFPXOjMi#R-z)F`&EY0 zK9^k7WUK_p$lc!1r^W~mgbp@G;{*)Dc4MH-Bcsvr`qPdB(>Catf|@1Y{e&D(EW@W9 z?&19TWzDFs=_0pPpr*~z5VvWw1|Uho1^f0t@4(R!PZ&-BcM^KF|1-UM*&tGrdXs>s zf(&XlAxlbN*H;e>fE2EyAoA<_*8Yl#h|abh3ZrWQ5)GqEftZA_g&#BeZJ{OfmCiiW zgbn*KlFJ(sev~&F#~3`17@AAPSNUd3d+u$HLnVEUfTkwE(r{U^JHT;xzJ=DvR?c;W zPc-0rk>Exf9*1fT_4ksH9eqz*t4h^yx){6G*uC$Lw~ciTl@0aUe$DvpfxoyZ>*KmF zPuD#=-2{0hDU}pid)vzQY2VR`^+=6!?GYw3 zorhQMEj0#WyRpvt^|uqVJ@qV1b#0ALDpnZOXQ_s!;!OfVLc;fI6iPYT!vofF%d<;4 z@;G5A`pVZz?6>LrvecBfUWsuy*f}E73C^&98ax{sN_KVUn$&12wchPzTvpnf%yi@_ z<;Bvb))SwD!bjk^-pqybcPUK2wU4##-1RT_nawdc&5Ea2LYS79RkkY3Y5y_G@ZQ#{ z$UIY!OOK@n>fj9}j{`G=Stfm?)S99wXyi@JLh%Z#DQfXI#6dTNTR}=WaV)$}4%7a; z^ATHOzx)i+1x!4H?WtiBJUssqhw8!v#Jk*m199pqd5Q4t)aE``I&f6ZYXbSc$O+g*xBxyri7xXD+Oy z`iECC^~lk=^ry3rxH3x>EHUQ>t>?bX3oWs^1Y3E0a^r(i61OM1w{FSS)x;8fgyGNs zc^ly_=*Q;LUykWz@&Fhl$MiPx2(ov;rF#HhukzhH?`M2z2@PZoil1_I4EZh^|ReX+D;w-Gj}TiH2QY9jV@f)v;;y&W-)*w%^up zSPp8s-b!BmM!+|tq_gL*)Ox@oD^ADQ#?t{7gX@}CWb~dl^QbK8AIV~05ePvPxy4j@ zk?p995+V#cwhpsu<(~c&UAXB(%tFmM^kL^@*nQ6qdvKGZ==wRmO&(m3jx#{`^IHz` zmL%O5^k*}myw}t1)ThEgO+`OosOG0Z4&XeG_qqPBTT~<94 zm1+wJd#P#qvoSz{75V1f-0F5$p}RY78m8mX@mT$6dOarT+M_JJCznh;ST~E7bB$!# z&?e{Z(O`wE!)Kiq*Yb{DD!J#ORreN;dEquGS1&!EKDK|YFGda1Q?F5pC6q!tMIHe; z09x^a&H!BZOXO_)*y)AtI}s8_bp71LV5_>4`T#4VC(s5;D*=B(!fXi!^3z2~6+JTA zy_Eqg2D7%^<^ce;G-AF zs9?a3lAFKsGncrHQ-l&6zKVOxDL$!b0#<=9-x9`?<)u(+-J@4UbAwU{ z=QmYp&FZJYh@Os=a5>DSK3taMXZjr2Y6#PrgM|SqXqs_rnKPc4jw7WR>@Zf1vFWW{ z8L=_%-6js=`(!xE^QM~&7M<{X!?C`GjtV`+rus3D>}fzJ4-)@IEUUuv<9smVP&yzz zlzOUB{suXc5oOGDKKzOng})-=23Y4kwTyiJFy_#6IqbR}bPzLZ{M4}KRy&1ktGAcO zCo&$~P;oYPHR3>YsOG-oZU(Mrix!6vW57H^{@xj$BV*3tnQoIvOxAP;)!k47z01yU zu?RfaI%{pgS@h1w28ntuA$IdzPlFvZE4JF!^9Uwbv2GDGnIxXWn6C^ zZO>EA&MSIG=Ui_uY|m+3Z>Lwc#m>%m*l$C?&uiOEuD5Kf+ZRhHS2}w@EU}EiIUsMi z?$d&Z-dx*8p4O)R)Xmmu9q|YL!Y$WzDw_kDcT>`Z0b8)9w3DLis4N6(v`I$Ru~d<- zZjsGc&kX&AA>U@AVmals6K{W_F}TYIJLMMzD3oPaqE2g87sysx858aZM8P+fMFx!2Yqm}A%XUO=v`?QRP&vp_ii4m=QM;SfHEZWaX^aYiDk~*+g_9) zK5n5v+|<+R(G_r-GSRUZHP5zTdFbtfj3R2+&PC<)3-K4GsM1&rPCH0 z6B$qsJ+D+?9mzDm7#*gG%9;}gWPOsP<2QBFqOw09d^U<&WiWOY)iZ08h%k3gZW6Zu z_@VIwv(zj=Ts{*(8p&mcX?FALcH70+%a{Fgk6bT>ojW^Ua^I<*B@XoWzLk`egVw-a=yQ@w}pJfWYXw|gZy)(WWds@vaxP+hH zscU0voZ{Ke<14;oNcWZow^&H7J9Ss-Srv)y#ij$c-~dpRR^m8JFfjKx&E90>m%H_} znOERMGi_CIImqhvc%*xae?g9Vb(_8dWU@{GzlB=2J}r~)S$=P4=cKvP5;fx75nV_c zaRRmiS=T(G8Q1s|>V+=V2mzJY@tVNh>d~P}=#Rku)nCUW*{jFL-z}6Md1fBWCLft* z9vUS#W_k~Yb2_&&M;#T*V@I<2z0E2CW9f8L;$?B&5X85&4*BI&)|4Sn|F{ZXZ+pRh z6#NVPf9?RhY^}14VX#ns?f`fKs_!O5FsOYo(Nw9C6>tQ8tGubI1#dJ>6jrqKqnH(K z4{{=tq`5~1r?)YtbEjHasOmD=t9t#2tlvz}ie> z&n;VJ!MV0D5PL6uCb@hsDno_GhUaoV89${h4Buh`KAgBGWTZs>T0S=yiHGinvJ$mG zlB2iNTrqO*YV>K((}E!>L&iF%74U;e0H?)tyFw@>tNK9RQ5okb*<5z(Jm=8vP;_g& zFQv8|&l&JtfqJVCyZW<-X>ldx?_F7zd!L71s+NAn&quj1Fte#lzxP~iGHcTWyp3DK zIezo)w+ra4!Ha_AM|7v$n0RJIm1;ei2e-_2%xoimsyK`xnrJVuWPia&N7&*>qmqrH zZrOSVYV0s6w@IMpR*0jnLn>E4`w}JYto>^OMy=M+p=qF96{Qm{G$MDr8);uw-^GWP zJOF%^M%S_Em7xB$uZ|3SghO4+q&Ke_G2(Hsmj2xDcLz1rBviNws74#hCrkL(1wZ|H zH!})a0y`H*>YH|VEIe&VyN3mO8xN*4*ZV1f@REm3<+_W#ZoQc;=)Tk|#MX+f z^|7s{Hf>xl@hB99NTJB09=82eWd@61!S8z|> z8BJKvdZb4P)2`IUkFXZB{+(bCc(bXN4`!jdH5|HKiD+rVB_EM=!IyWo7QQ#YtZ5Do zig@kkB<1ROF?!>H*T|+qU}ZfT@{S=uAfX=hguz;%nJf6c`}_X2?0H%2$y#l#_fie0 zR2^$WehBdo#m&k(l6>h>MYcUORA=ZHE+JGcP|fwxZRq>F(3SOx2-KGTRh1tYcbJ2I z>p~WMHZa&!jtS-EMu~yvC9)KXZWmuFcC}e;{e+~-D3=UFKQq4B9_rl3-Ed;g3b7x0 zs>ss&F`IrA2*my>aBCi9>G{C=XnBL3&m84{$-;lEIywE-xrf`Fg4_J7_0(-4p$i=; z+;E=uD1|THfp#+c-b|;u=RTUha+TCv_0edT?xiy}78F_h8f)0cfq zO2ytq%s$|tY-E}^o?(|s07Q^-)e+{ep`!at&hL&UDz`)MNN*H-f$kr<>dT9)F}aY~ zz@O^74u_#C$bUza&Lu^Kv^l7{TkLT|WT>#>7a3+?_3?5MU4AnO=!lfOgdn|K#gmv( z+Ur@o^D>z-BB!pk7q!siL3mJm9BlVKxPI41{X|X=-!9lw6N|@UBi1I zMqNWL&08mU$Fd1Kdv*UEUlOgY^igj-TYIE*&2G5&pLbOBoYAK@gAH8|d`S6!TDktR zN3t}bRSr!6vu9~W=TKGW1X36gk^4|eC}@WkgY zfD$Lsr`Hxz6S4+7-kC>C)ty5>44s9Hf4QIWG95jpC$%>692R9Jtd33p%tl6p`%stHluYJU+Kc%!ZW4Be z24s(jtPiAQaw&p${B>@e_7((0!|*e4hk$`8Nfo$~~FCh)>TAtXWU zzX{`={p=g9<;w41NgfWU19MWnR|`cOq^XfRUQ-EygbCADV;_^~#dqX6&NJb8n78$4 zIAgO75|V0>;^58uOG9$Dc@@(8Iol;{4ZcB`C$>0O)HZo(Kw(-~B z$J?4>A}YoED$Zs(MnbTvxp*Z92zA=YQ%%1H)s18su}f6L;0|db%5!YN zW{h=QT*2R_iUjs$5zq_qC5)UH>-^5Kh!Y~96Ut!PhC|1r3iQf`_gu`R*KhzUVa1o$ zzhSS$vm#fCLYN*+)%jK+{w6kkU10Bli^QZ0*<=D4#@()xex4a4)mAKZJe(ahoZV3@ zRYEM4QY|>_9h6l(JV2w~>n z$9FD z?b_F`l4V_a_sRUoXhq)NoQ<8Pxn@`-W?_ZRh)5S_wjLf6oqNdWBJn2)$K)U#_P{ZFj8f7BI$$eZmlUN zG+*~Yj7Pd-0?v-)4 zKvZ4VqIlWlwN5#lK%+5Y6U2^iX8H>B@dQe9%oX`nKzOvqcVJNb3gB+838IXctkMoS z_N0S;HNqe8AuKAH-0-{SuT}i;9v^)qQua+0bn~#;%({2p7l3gObMq4y-{m)HI;Tcv z5*9wW^rqRIi-A8Usrhwzo*pO93brTD$U#UMczpLe*P}UWfqa^}h%1QUzCk#u6npN+Il^8v*#};hZi`pMg-3fAD?w9M`Y8j7@3v2JLRMIZgtSF-YN>@LUge2 z$_2%$FxNx<)`Go7fL|zO+;6tTZxqkk7Wgonl6XdBmqKtZh)b&Sn=q`C=n}&973KF) zd^MG0a03zK6~MmiV%Bh^xaxOzE@~499WEIHISMe&CW@ba>wN0WZlWYDo$xK-==>z8 z$9sAL%fH+!yQqGV#j%+>&2m@k$7|KNsi9z1Ap8}9t}X86O3v!!D{q--d#!P z*NAlQe~)}@pA=K}?|e`GX?2=skR+0Fk3ZW_D)D~Mjua3UXzyD^J{iy3`Fn`4a&`l? zxurOvI!AJ-$Mi$unGKn#3KM(Dk4b7ur5^{5ev`F|Ch@9l#Yy?w;{7sHbgU+BHm=s# zG@FZljWF#skh;3Q)DX1TvOFMcYtvo_Ne>lxr!OLRL%jKAvBPM{oi=uU zJ(gsb41RhARKJ9H=Iks`jE=V=I>X zx>6Ow)T!)RhjO)1=C9NLiq*${8kQctd#f#9D(e90(V&5jxg)vbqFop%gdr)oiv$Ue znD5MA_w(XYOF*vAoz{* z(B4ZoYdBU~YB4@4;Z8eOO7Ai@xRGvCH?>c5!dp;%wleTxYhqP|lk4KgnniQn#N_*# z7}9rA#MGzET)T5EskNRxzx@Xhv_QFGZ95puRbk)vBJh~}ggucz#*5tr*sP7#bZfp- z{iHgsY}F)_O$@d;TY%I{XbHfFNN;92SEXr} zcU|}1T`!Mef|IQhN%BxJgjp}WPfC~v5bgmtnj2fr3*#>k?wf=qNyfS9zAkY~%Kq|2 zXlpCxGmpjDM%Ftk^J{@9K1u1n%@J*c;#pN}hW^rdbQF8Xo-mAZn)?eKO+&RXuobC# zYbvMW;OHr~*l`FgRjBdJB};}6doDB=<+dQcbjfacCXXV+XE(<;WYo;xZ-PXk%4LW0 zZ-0>Z>z%)QGZC*Que>{_E6~w+rYqpvwERIBl4-p3ORuARV=**V!cWa#h`U7y7yJRm zE!neQE<`R${q}=6S!oD!)}z%TvxZ!uu)a5aqXDN4(-$>-3Z4D+5i=g|SA)PnkaUl+ zA>{vJ@13JN>$WxFRBTpkJEZzdQO% z#@P8`WB%4&bFKZ%`OG;NCIbQG=^!|*p@8Dt;NeOS{e8`34I76$wZ$`+f5N=aP)_V4OCiBkf3K(fcp*Q&`iF(H&;pEs*ui>#F&YqWF@r42ZSrQZS75aE~LK@p}xsr{uAfXbc6zN1PA4k`)osHUT zW)X+ZjaO=7d1l&<;_gw2REf&i!Dkf28)MA!#C2E9VeT<04heUAdU zqw-%bCdB@u6o!GN(@6FDAOGX(_3so+9x$zw3HOt!B^MFPBWKoinWtFWCe?40UV8Os zcci33QcK|lG8E6_>Z>ps`b{66oTaq}rXRxiOEB!-W(xG?ASu?lsjlBcw;V$`$^8b*3E{5hRLxKl-r z-X&jY)G!jjH+-q=%f~f8zO4CD28T{5o&Uz&*2ZZhYWQ^T=qXk|u%hNFyiJ@f3#WA% zJIqLH893HXtvM-FmFU@zB(8t-XplM)RF>`P><0DIcpE1%Ry_SdD^%umV1L!jpLyM( z-1{zgiLSgq4{4BZlmPwehklVjAS657Ib}(|=8g+zNL_FEz3iy*MWX8yPMR(XSL56U zEfRV;5xr~(RSAYl@KPX3&wiu|!Hy-qxE91T_@+7mKXEl$ekFHUi4aPA89aO$0)x`z zuSYMw-0=cKU3LeukPDdu0_54|*(FE?wz;KqnS<$`6ZiAo^-VFdgIjOzQ5-72w<#Ew z7x=d`Y_-kDx82WOvncM+A)^Wa|TJ-Ga zC#mO}pHjd8lW97O3!(yPtNmSsi6o46*jxa1II5M;fjsDRNW5uO;#fUQvz&AWL*shH z@j^yVM)sJ!s4Ch*HxTr-Nfd{_B0}zJIXE)!hxOHRQRMD&Cq{s6HS4!u@{&wo^J_Wj z>S3-^+H2)(vDlhLpmi2(u^HqPn&LutISJ-CYIy8!Pjz$w`gTqofkbh2HCkbiL+hSx z#`@QINu(Yps3Yd`qw|wK)JJ3^JC35c>QMGia%4Zwqc!Uog=b?sPN6;N7)5M-IgO=r z*QVX^$=CuhSEwnv1iJ51E>oFJ!E_(06*a#ku6Y=vAm~sN%x7LP+3#ziJ$=b7cm`Bs z4y3KT>AwW&f6eYi)g#Vi>4pH~oZO@QEvcxt4}#rbGaXz| zPkZOXGAbsEytZtV559k2Sjc1lOv3QP$$9fJ0{%@%%b)NBd)YQIKVJCsw&z%PZE*aE z0_m?g38BW6M9L}s%V5F2g77(bj{mdjbddDb1#+3ioa7a?y%FsIsW0ZeqmiSP5$#as zro3S$QV{59I~Y@*F-V%R4$R16CrUlCLuD8Pd5xTN(cT;!urR&jUIZEzOa%3-KubKv z3G3bB077pJp%>L51j!Ac65j)d1M82i9@HkqP!qW`7b?Ztg|ZC)!+5=fbsB^8nfP_A zAr{ChRX3KMM&J!uO5yX#9U`^-wC2_dUsEz5c9{rZE0oYtlG*3u*lI3I^gDi`y=WP3 zeR){)!f#;{N)lYS3No>V7g2aKWyT>J_Su6NQ$_g4h-;WROj8;7$4H!L+pq#sfh;M9 zGHtYtB8lH+c5aI-d$|WTaJDf;(JFd6NHz1O%Qweb=rvzgo0p6@`zP-eqHMZO^Ko`s ze(p)Pd(455zMX9)oo5wm+$^I0eX+*wf>ImHkA5lqKy&}5Z~i#n+~YewW+wQ7gEP(Q z(uymBU|><{5Jie@1z%_J$|g1mV43fQ@Rwi$(x*AvM2>F+D8Bhw5vqChl~wf|b#hd% zaJSDXO~i#?4t}?%T(mANJ!CkYuIWq39>`JFEU$XPS@4;!)2vjlRTHbp+xJ^8GPaO8 zu30Y6%ocFz#mIPaFR7-w#JK4;&R%=GVyH>YNU+>G%mDu6ma6gM{H6YM@TF*&jGL-< zlYV$pBJ!n2zjO#Tf^>w$d`~4M!sOXaGrOvmaNUKmL9RvNq@E6iODezr+%k9%@muGWK2MQh)0gYt~`ehf`IjSfA^e zQmU}VV-SJ?T=yvH*$9q9=xjO% z8QIA7htO@6=tjnYZH|G6iy%5-_di6eA5H+BHY<83)~^XJhw6 zgh8HF&hRN_XVBb^Qqk4$u_fF!RMxte8%+a3YY-d&G^2ylfE@I** z7zc4m)~~0^;l%+2#l2I_Mqs>Xm~O5250o$MQD4M)jMdb83`J?#JWpA;$G@I3weQ?F zt^Brnq)WZVRh#qx_)WGARb2-0aOU4;ssPPuJaA6@{I^d}#t!Xezz_X&!Ta|%#h-eY z;Y%ZSf5OLSIPn=a!ME^ZqqV)^zXe9?dq)rGgNlU6T*+8|B=7GLJD&gIPRtpM==K=-`G~;VOIT1UELd67-kq}9^8YPXFPB{yzH6_-Dpyfd|Hv@X&wA! zQBmKCt2E8v1_`Ul2KMM&lpi7w-*&F!Iq-$+>ha*3)=Br)vY>>=w*+(fM@oItA?w|x ztzm}5H5vwPwJ?l)+wGZ`=6m$PR=S_Nc=nwwpkm+lBVc)>tNc*epc{`uY!Ix*g~o8wQ%kr z0}?f4L7B-KeK-sgA|r*mR@^BU$gh;!2(=$rBakY@z_8Y@3U4b{Wio*fI~1lS>$-4q zliuOP@@f07kbzq)=9Coyo@AzKG8)wzWkQ}f6@&qbGV*QGH$K#Wr3gPo7hO14ac+8h zi$@>~wb|X$KI45}7cL1rq)$`E?4Yg}=c(PE(Ydtthl$D6f7xRobi-b0wA{%*tk#}&j} zJC@hk`Y{RHHq5O!cOv4}FX|h7t|;=HR_`r!Tify;g3c`TTRrle`tB_aTVL}UrpohM zPf)2y5Z0fqd~Z=42zK6198R#{=6z!b{Tr#c{#94yw$91^ZauL z#!*`l68eHw=?wHQN!OS&3&PgmJITd$$L=^kea{7REALB!c{kP_3A6G&&qZEm+u+fQ zgz$y?H%y|B1K&oSEiO7T{7Hj`UJ}i%P^=}&%98Yk-N3B@L9^Gj z(84PDau+;h^cE?v==9`h-UAeAEjeAPrHD^!9nz8s= zP0@#(-OR0Mw}vz%9u3;o(5+_g?-4#EXz*m7Uo8A?4PRRK?2c=(yBTrasb}VOMmUjJ zS^v@xl{+MBQvE`EC;W0;}3{y3`H zQF4YI%KA&ms4evjo8;rR8(LUJUXE93w)MHOM>Aj#vCc|9u$vL=TYjrxm40VA?A*`& zE&NoAN|`SO*rW>HvMZ)@D}(wzJ8i*n>S`;l{!2k!U2|QNQoCu>lh#uj6`rh!Iq7%9 ziD1ft%+9q=&~p__h2m~L&)Y}Iynp481(q1@WIlkG;l~3W0Ra4qzLlP|t(CPMt)7*w z!Cy23UJmdVvMhj)L;nB$=N>B~-t+Bizy`=W|Bzdn;YopiJx~HCE0(g1JJiq`iurV` z{>lA?#7em%8K0)@M3dHd8<7T<0ygnig zB<0#cD=S$|IZbrsv=Y!AqQ%a*+Wgk>$?>LCUGqoSuQf4F#Q>mq0FR5!TpS0;&{CC5Qt0ZANf zPT05;@^xm}qXi@1A-UO1uYehTMx(>q+p8FOmKJgu6g1z%|Xo-NfME7j{$(ktSLE(6G1mx8h_UirzlQG9B)=vJ=5&8WbhtquKvDI3u9?=)pe*rt}B0f&bqJr;fGt=h*!J z=A(4^F3V*e_%@|uZsm5cv|2%ARV@5zlspn%AEE;T&i>NHmick*El-budT>W^{9_Bp z^_!K3ofHJ-XO0^&>!R|M-#xsCZrbq?bxV>jg?A67zuJR{B&Zn7w6~SK-z09Y{FK?$ zya{0rtNgn{ej+08;PE8z(b#lW>JU}YB=rh6z?jDxgET0f*?#+~9<)W~&FK?@-%ha( z{Hkc9KK&lruQ>O1>7s#b&Vo3TGguqj`z!ps))vKrZ@r<-_Xn_sbY%;2QO1nCU^aNO zaFr~*A3Bt9$SAyk^^aiI!DeIeVr-$DJR6A6vK#65?P`tZbs>UTM-or+jKsi2MF}%F ziF9NU8rQ0GWH|sngm2jrOgc#`5qAg1ET(8!cPVvzC;mR|19b(^m-s4T!lYDi!Wt71 zVe>X-#yW^AcMtow>;02<>-_r|O%!uOv`U-91>Cm9VaV_`j*$le0#p% z$LS`BfziQTe&HtRO$VDYs2ik8Foe4DxnY*Rh&*uQ73!h&yObL=%Z@|pvOyO5`zb|F z8qf*rV_ac=jG+H~O8Jvmnm17{&ad-z;Ob({JV1&SqfSm+od2|s~6{(rjmS10Wx5Wj18QzuTR{F4h zkTFPDr|;-_e~0_K>fNp7Ow!%KspX4-=F9th1nuf?j;_D2gJ0}D5tk1I0MPmooIv&; zbG5atiKV@Pt(<|qy@{of9qm7T{*OufRLO-U-VD==n$%%1Rs(%_h|BO4m(QR$(jT4O zh^QZJ6z_y6lz(2{XS_7*$Xa!J(H!U7?vX3*iHRvf1F3u&e!}mjnm7l1fU%wDnQu^Z9Y+~>L z#E{sBcV>Ul761@!8{+|+{4&$gj8hL51M{u0aB2S*dea%5V+hH-w#E4Q{mbC#Pk|N% z6!SuWkk^^Fb)E-3bi&|U?e~#4mj?Xp*dwy%iS_sO{S|IsjqrH@@A(dKpy<)dq&J2) z#_X{XSmhHsfJoKaU+*;EGd&YYAyLsizhuZ;M?!9QD89E|cfNTUZXR&wesQOg-T3Xa zoVMhn+v(0-&^~Yh(g{Ba>feO`5n15Pfo5Q+QXJ6zz(?ThjRCOQh&0=5Zo&0xxW)P6J--QS5diW! zfI4{|INRkn0lWb`zMDzi5A4Eucm23@tYB$4F@}Sy<&lGCi78 zWo=3SwlgoyU+j{5n~}`6Dy*?SIy)E8ajsH0$N~5BWV%5%k(vXW$g_5Qg>%&K=;(yJ z{&p{nZy?eT3Xg9D{U<*)lHT$g0=1YF>qW9p^mn03JF{wTU=|ihQPAm)^dFL!6Sz=L zmnN@l2%APV(=V_yIgv+Qx?n-GW03TgQ2cgb?jl51v^3p0XEFC2t}mnC(>-VQ-h@Ka zt3-*n+C<{H4CYCQR%}HZ&ebjE3v11HdB#>jJ6AmSCXBRj1`G0`A&<%eA{2LzUD0Xe zfy>V`jP4rHsecKZySFs-P$2N^AJ@N9$=nCp#wCCCXf)`#Bzw1RdGPhF@*%=OW~G)X z_36kLPfsP%U2hKqCvFh==|dFIsCK@|9cE#XaplB$x)6GUuCdSQ~Ul}tdcK`w+VX^cQz6~~cRI=3GOAKU*sdiX#6f4WaXty_ivo+55sIdWA zqmkfpyp*3LBTv?M1tk-zyQZwSKXNFy`BTrfhV%RLjvS{!p(ih@qX#&Jhg`#SS0|V3 z-6%c#h56wE&712+Q2r|4j)$pwYPnr8IK2%-kA{p%!`qy#(fL_MUptAx8?(YhuUI16 zL{v94gMm>GxdU0p5(^zE3c^LzcJ56EKga;gh3xtHqL(qZ7OQYm{&^K9qe#Rso~~_! zUkjci^%7{JS$>I{+(NijU4SGiIHTh-l=#7Q&0P|n@tvM`C(rqDAC!T{Oj`0)WndY0|X%J=b3Zav&CH96b6 z)ExruAe93X<~E9xOUHCaNkfmEvbUz#!C1I9^bd>w3tRJQxwVM7_B5q%pQTy{dQaxm z_4)8yNt_OGLE?BrL!e*-I=LY4xUSzc5L|=Q_=sm(P9d1Gf5weoDwSts|uiKO3A zk{T=ZmCO`>2rkG@F;9$~S4O4GGF>Tg^ed05%DAT_Ja}qt7uzLt=Q?E&1`Jr<*_g(b zG#*%2+8ttQUJ=S6jA+O`^`p%Aa1gdR38mgJCh2h|7hLr1T|@wHS6}8^iA5Fjlj%aO zBD=6!*`YFOmkzX2=n1T89ay$CXKg%RMqBHIy9U!NjAwb-9CN;J~i%F zh?94cJJV8ZLh@_e5*#>lZ>t?0p1!d#dQ+~$+g6NrfmjIbnUAr=I*VSavfz@RI)vw6 z0NGWLo#r5&`({lj)ro9znmx#^m<+A+zJtlzEfPfR#js}}v4lxZURE)Z>2(D}t8yKo z6vNcecAnYrlt`m+nBiYl>en3nn|rkz^Ag&$n;QY)*v6@fErD&dLs zrAlZIwJ*X-o(>iV2sQq1>^AyI^nIOqt2yj4uPCOz-56%Zi;K-=uhU`HjBj~>vbD?c z7S7?UB-EBI+9#+8Rzc_~iy9*3N_X^y)r*Ran+{EG8R5HazdJ38knQxmw)1szM|x65 zgPsEq!&p+U9{_B((DWSF8rB20z&EnW^HCvT$q7mG;!o;aQVnEjf8M+6tIBzj(*Hng z3N~)T)seaP%%&@}DrezLVQh78YgPx6WgrAPC_R?zFp9Lvm2ol+HWv|f2b7-onS-!2R5VIq_YOpCQkMEk!lBEF|DTc}pA->#I#fzgWzJ&HxRu5#SUwBx8 z)E%!%!kd`6f2E3kIWfJN0d4^>KCjwUNdBd8JFYenm`SS-B)Q)k0f@<2-RBCFdA9>8 zYQ9jNt3qogo$q_tG)>2BV}eVqN^DFvc_m{}K?)j$Xhkvt##2c0l>v!~!2Gti^~M<$ z6!Va|eQ)tFf~JWaG4+Nanr1-{Rj!d<<9p#Gn^Br_E?%Cuwk(CG2=6V#lk=MDlmqkQ^BhC&^k+Pv%vQ#P#KSc#53JfnMMm%N6v1X1G=3u$5 zV$)Dq_&o+Cfnytg)d}yki!8L)At;mA1vL&JTd}O{BvRVldsQhf8AOFdn2m@?y43OnKob+2lQP&9uznmIym{Aye)$M9{#OsgGU~;x(T5FH{$WGG z{|D69v$C)-u(Y@Pj|`)jHL)HZ_yDQl&}B1RZQ54(jqG6GEO5a#tJGQ0Wr67e7eo-; ze$wlCFY4c8Bnh&k)h%%h>_+3Gtt@S<9*u3-qIF_p-=%Yk>Gxcnp6s6-pMQU?b4yye z-*2#&$~gRTD;BU{`D1rWyh?mgHra!R^tag?61KPerlH$9a=H_~;g>`|W&Z=gfE@CB ztOCHO11y`!PI`I;{NoOHmyryFpNI+|^AZ|${rI`X-$t%s7pj-s56ZsB?<1u9L|xs+pw*mi2|6(wFCJAomv9mK{`bkmib@MV6wrDV|Ax z^5Xfj`~%c2W;-zKXw&P#donAg(vD>u-Q;$0h$#8ck_`h+|46|!_|wW9|AAg1p0X%; zuQG$&kKU0byUt=KSvJ!i8HaL{G8%>3P{~Z?nebq-@iDw?MC!N^lU(@XT>WeIGq*=^ zhw_)qau(4J8I!m7Oz`JdeEsoY5Pb2yhO6&1{eRmi+()}A%8y2Ier!1Zp=p2b0Q{qO z)3MqBfFO8@fOOH`fmqDZPCf_(y@LS0%{=3Zc#$BXk_NgT*Z3QSPQv`I`(G0C$0zWQ zV%Vce2f-0^^#OP_@Qg^{YXAic>FNGn%%#)djxeP^mo z5U@oj%;W)n*oF}J;6nJLCGn`$L`gqhGCJ9O>;Z3p3GVU&r{=Ak15LjD?b_5hX8V<%o#>>9#+x(f3Qow_sS*^*3r3QI zV^wDn+6rmx`p0%6P`VNv)Cx!zhhoXWv*_~*?}j%I4w2Lz?Xq*d2N^QA!wy@{x7X}i z^oDM5dk**gH9P$4Ggqg!f0W{5&tH50bHC-^Pad8BOD$B;(f_^jNer@Z#eRrb|JeTN zDe_0%)FX#rxtMenB*^g?o~o7CLIYJH3re$%?aw94{EdcOm8!U0_%- z?8|SMZ=8CxB#NwT6s5IavpizAbYeNTP&p+jM-cZSh<3@8+28m31AP4JZG!N%9WMBv zUP#i9HheHf|KxT2=g)s;j!!4#e@iE1OftvQ);BbyJi^mW6gF?s#^94v{AEjzyhIw9 zov2A6fao_^0HC#p-?BbH0D!ksWt>a6aohl)3|%Wt+p871oE($)(iUn`YG}}ll< zzNO_C{wiFYPNIdxW>2N|2B$W1hpqb&Zt^T#OUAj^st3w9jn*|@KJ*5^xyeF|F5+cJ z&)UW9MYY;hcy}V;{c}w0hW$qvTLD-YHkK?iFO9DMmtOZtLFsnpB^rFX^He?c{M0Z zsxhS}2944PwareMa~p=WtvFRzXX~(~0stwcEB7@5OPIqFy0W)hi7-96FFj}LP=NiQ zvCi_lwF2d!Z;3P?9;INHXBvX|RRRyt*st4`O@8lG^>q&Y8+Vmjl;duTI+EqCsop=v zV$|OOXit5AE2P&_zTU=n3o%J$pnm;cXK=$1ipx`2YWR$p1l?$1p50O)F7{<^G(l}5 zh#hLr$%As#QDMK>C`nUDCj09EtpItbgI+`mZLXA$SLD#x{p4ws)LneW6Ntv*9e&ZR z#F`iw(6h)K!^mlCO}19c?-LK)L|dqchhiI(`tf{%!Cqo$C&B!+C#8{$rUoaJ=hXPe z4S7x^N|j>{Zb*jF_zalB+3Xj?o!)e1f!2Z0sBtG)WGv=Z@un8N_v}~qJ*>UN<^juD zJVpw?;Gs3xbKk`}eN5$wgc3^$4TknP6gCaKSrHY6HI*f055Km);m$d_Lk7q-(b6(m z->U|Kol900+qV&dDlCy9S0^NKo?j5;_tARQG)!0f6!m7|U&T!1*l^W`HiO-|-`IiP z!##klB!=e9BEw#=3^NMXZcEB~R&178Q|>~lpAN(b#JO$_cbP>%4-ah{y78-gM1Nr+ zw^+OyLc0l#v`{{mN(Lq*tFmpZW1y@V=6wZW4TBMb!Vw(2GFtAAeLXLF_`3s$6XzLdb$5yCLs^yT+4m%u zCJ%bxD|6A6BxKhl>bz9;B%!whQL!6t?xyJ}#U~mv9`)vYgVlKViPb4#)r6aEYWWQZ z>K~;);^m+(KkZMp*$v5Mn33jKwE08d&A!RW{SO zz4gJh>JKq%3NEkSH@mGLt2N7KJ0bR0z#bE9zgxp;p=k64nL29mlt@7mxWze z6NaRd5uNICg{IEx%r&mY<6K>a@F?QbMQ@D8@K>NX+pu$iJGCMRNVBqR9lew4dvV(C zx!-Y+B2%Vv^;>lN$+eAVzU5j1t=NY8x=#3YnsX!R!@6o)z6*Qj4)n1P+dvK3ilY&) zAxVJ|G;l`rxaXKTwA;qR8$g2rdf`hB8?LB$Y$8=P$4Cj%{H?#=@b~f0anRX0rB2NX{)Wbn)@M zrfaK3ot-MT-HtQHBM+SX0Nb^}Wxf5L+k`R$MKbzy)OQ*@v6jP6ihKi;+nY>y3`#Ok zioPs!U=2vMLp z>0U8^Ltp1H{j>^)--#KIww(8M&bd>WE|u|RUuxzMFB*M)X7~EXO=kw0DaJB-H~OpU zWkIFlNGn~dMj(+6MZ-Ju-1A0=>d6gNbXuQ1^X19AWC<=j=w2+22m8Q4+*@6e2$Ewc zC1dvI#d7D?=eK~>t#WGwP;@Hx(3k8bDb7nIv}$UGUnymzEOeQGJkQcz$5t|;@`;kl zcAX+hvlAG(%C$YH$}Mt+F6P0;WaW(=1l_m#N@27t)4A9&R~!jP@s-&`gUQ+MyMB{c z+3O39bG#FNhxW}yy|Qy_&x{NN=b28UZ~R@TJ3vyP#|JT6L{yVQ3OqX?OJksXMTyum zj1y$r{?LRxTVlt~n^%4%Q^|Avt8`2X=@c-lX&_cfr(JQ1-HH>_wLKb!B?XBY()@N1 zKmedDh17M7><*=G_7jJV>NKE z8;}p3&|uoy>Ah!!fUQ`QaR}OQyOqHLrk6?r?ZXH<48^&ICRZ{HP0T-P(=!BP)+sK*fB^k1#z38Xp=cKG{ye6ak2HG#hbsR@OH-_1AdWhtKQ0xd{)glv zPKHV~bO;f(Wn-Dz@k8r&cHk(Y=KcO|fHjlM(P43xchh=iqE9;kr#1AblE(w(57cj{ z`A5c;^*UclC83o)o=%NwsJKh8X*PkCF)2&){|fa>ArQL$ zvL0Lh)#3HW1agnzHUs2^@AHBp1pX+6To0}oOQ4Hq5XwVAEvqs_OzNyHNk`g6p{07W z;Mc06XU7K`xa7fpv)Swz`H^uyMYF=iO;fg4d>Zz1^ZQkz3;p^QIoiX<5grPRn zQX{*$u|ev}BxSkqVlyR>zmyOzy;4=}_a-k|dIZ{Aqo9S(#R}@4BbYXd}>|I{soI!L3Wx0{8IMuuHN_ z=;9>RwAs_&huE?o$7|g;?(P@dJT|;G_B<<|U(U~5#$7xQI2If%^#Gup0W7^~D^Vu_ zF0%}v7QGu$C&6|ky(u?AmX9|qE-vcI!oOUKFS2~8(9u@!^>&HygV6@!vTm`c0ka|1 z9vug*^izVJocUtp>f`6|tF4ol2O=6s(i`QZLb$66H~O(|lbfghCu2HZwcpdoyGIGv zlT_}IMu+gblh)xgVvBa!7XYePd}<#00orG$mjvmcbHLF$Rsdnf`I&ck6swLAenE*y zYVBx81PnB) zC;_ls0|CI+;~qd|0{|F*>%XSjT`l3b;%_+e7wD8`k)!fj-O+~|y4{saCeMr&siuo(%-o#3=$ zE*K3+z_G?g?oZT#4h^OUjF(gC`gj6j(g!>WaWMu;k|?_*9qaYCOpY!Hpy1IO3bsAM zJrKxt2{QQw;oP8vrU;)w$a_rs$=f6u(Dsz1(G$Bv~?*y;EXI?s#p zm=fkO&rul%E>^~GM65DTwpJ;8OJr(|J_>kz0jssD7&YFyUI2${sC=69^lF2)G~mrc z*W45H&=Irfx*wm}IY4WBo$14|>tiujyMq;shYHBn%(s_ecQ z?VPZI%hW%L8-;3U3f!A>P;q;qcqR`sR!sq z$?eK1&KzlrzXf}~+Ch<_0J{S_=F|Zad`yGwTSM$JUq_w2ptjXg*REzzmOX-)MkSu1H~>x&E*b;1znJe(nGm^qyA44S z&}p!f8r!7N8@DMR^TL&>iN<)t`U6L_z1Gt>-b(&LLslJFIa-Y-s_kc;mvwLf_ohnG{3Wxm7TF47kCvv&oA zGL)OmmfC~=yu_Uq(JQjDUm+H_&2{%6N^(u`H%_4#AN6A`IFDwQorFcO-62q9+W;HJ zW#6SdQzzros`#c9W|@ZW21|==K8(tUy`PE%K~c(LE~{=CXix4?hv4DleD!f1j8$8R z?diHeF1>{O&9G`4AN8L2`u&?dVMBZ;ta4n!zw3StPz3P z2#w>BoT?3_n1fI+FpStUJ2k%^>l@!BORP+PGgz0mJKbvfl8dl%%jzCsrYdU#z7zAq zF{vPuQla=ZU z9(TcIQSV*!1_DbAHpu14)ii5CWVLN&PSj(ULo+TREbI}d3Q|Zv*^gE#b?`Ih>lxCe ztuslMsb$h^9gyX-U*f830zk3tRdJzv@_M*Tl=*?v^L7V})B_ka7wR;(k~ppa4P{;F z4H}6p6PJv;8Lp-oIgTI_OF>0_s^29hzQ?u_ecKKbGtc2~B&SHrEa$-%dh_h{2)Pl1 zG1Ix1cd=Wm3cs{~AK8SZnVl0|Wl30&wO@C8tTdDMP#bQiq@bPN4 zi`y@BH{wy7>UQ_IexAFXFV#)tCt-RZHd=cz9BnL77{W~O^gsr#!FER{{^A@j%IhY) z_*}<-vY+*U%o{nGJs$`SDKFFohriKRm?u4kOc- z@}A)CV4#S-&~F6gBn60>jint*WmV}!{6u7kqjkioBdE|MVAx=kJJB&Tlj%u&*pF)4 zl0c}l?%3+2U>cKg1q>0$6efcfAyWzK!QBm+sbLRhvx;Hw!H_9)9gBg%O)%KY64(3G zJotRBsI}1$U@Jx~O`~e)4Y+kjM_ABO!nG$5`t1SvMrtOmBn9<{b;rd{6?TqnAj_F^ zkgFFQKz6eli(`711`mQY7)vfO(-VdAVQ^xl*9pw92-Lzx+ByP9b(;^A(FQ(>bx)+S z5!Y-QkKkZAd#06PEw^Px7rqRtti3@o>WDkP+&Zs=IbNao6a!;k$g(M6rdY#->&8ov zM5anT!wO}^4f5rjFk>r@Ft`(FD^0yK%9AbiTMm8Hf55uU>7yC9oGrensO>#)SX_;` zT+A~H_>C+|pA8sKpuLiVmu7uE5hMAfQGW|JWZ%1&Er~cjR*Bf5?;4Fe~K{8nYd`c=GT7s-oCOPX7J4c3aZ>G|G z&-pItz5F)QeV<)yi z4Z)m&=%J3@{-&diSDhd6gC-?7YcU|bJ)zsiEITXWp4d=V*<3(UD%ckz$A!b`S6ET~ zBy#rZ9#O+ctM;grD2jOKLLv>2|c%qHULh3;?ML z8rz78#=Q{qT#t}+p7Z3}FtcHF5@)E$X5iUTP2E*Y*|V9|$<62)&oz-zdWeN)PE(f> zcMby9`r}eiJ5$}D3!h&%?*;^ae#`X1#d;tNhp%^)5Asl(Yt-)5b zeqM0To^N1ku}THQOZnbk{VXpBM3Vuy2SC(5 zU3^%igI7r?b5*>P0f1GNwkGD139pHh3t+D>F1Yu1yn+mLPx#+kmCIIK(7`8pA=JQPW@?km#0?iId9(R;*~`YeaFd1w;;-1Ze`QoQRS~1=K4Q-Ps+jSg z2jKmQD4U(*6^Z*(i$HxOF-2{}7RHW%AKN}2z6$sXFPF~|{wT}2DmWM%j$TMC2o0yi zk5|AzKwuC<&jmikwHTHdrOkev8 zd`a=%5nGi>)Gs#+YjoK3G;%~EwW0tKfEJ)C1W-Iy0N4P_z_w}n-jZJ;0LsBqNKLZn zvOIV^a4z*>4_PKPvoxb|MG=jmjk%?9CnXRq53`@aAFtgGi(%h{6absY9O!F9fFc0y z{6^!5CebE6v$&$uKF$RGII|9qJNkg<*OxO;)t#92I8q*3pfkW@&?ZS7fHvS-q#~qU zQ*<`I2hnO?CpQ%&4K_0zMaWb@Hp$W%o;AFMLFh@HtTUdDSgJ{rEPfs}ZP;Oa@60b40L>EgJUcvuJg+=AL@I%jfGNb{_Vr01oSt1AWnXVEBykh`SPXF9XeSv-*m?wlQjFPWsA3+k1(dwaV^&V1+Ng}@JZ>rxC#BR)Bj?(Nj~%Oc zXwJ{nY=hl+dE*qqK~{4mXBen7Le{1L0Uq(ySot(X#r_ON~8oSX+Z%=>FyE% zX^?)l{O^4fJbHcJ@qV};&UPF;IL7)p=UlPp+;gwFkeU?G0~$mEUudGuy!iUXO-nYv z@VWfUP~wTBVWcHLh82`VGDJ!)J3M(gr5TatXdEh!3RvPfDjuVKDer`Dk|#Zq9fsB= z3p3A!y2Ds4im(SzuPYlPIt^++W-Acs*9rwATbvt z=7PjrkeCY+b3tM*NX!L^xgaqYB<6y|T>srMS73m$lOYfU!~v%pT?t1nN&pln%E<#k zmKR6B{oNcvT{P;cFn@P0_gM-56h7e&H6hZn=Vvwz*^f6E`5C3rTFi1%Q&;NUj*WG$ zZv@HnPQh#j!YMjN&0tX6-O~HUb~1u!5rV|!y_m6B5oUh3;;mhv$(=G5(J)r`wkmVX zJIztOVOFn9S>7~J4Rcv0unZgQ+!)2%iLa_27aXs7V=&Ru{o33B zO+PX98k4G$1ap|GA&;K;X#M%{EOF(;vU=i?C!vcs|H2vSTa(X6v^!1LZI|{iBdxq+ zG>A2<*QFFILn>%(i6l#UvjdROiDte0+BB@T83 zzY(?Rv=P0X7lv!*x?T9j#IgrtW-G!88?|a9CrS%k_~&8u1Q1rjyzR6dVv}}bY$76y zs5~xhUx0+WX!usq=?sekEZYqBdwd&y)baqKFT;W7phWMX*CK5whsECxGJ;+T%2B(V zr=4yXoNXwr#T(uR;h!}p2_tndpYfi3`Q*EPEx!6zqjc)lst>+s<@9<+EoTQOt#t4a z{+Z8UgPQe+^A4nwvmVnRT#LZkm(A)s)(VJs8#eOJ4bQ*mtub-e==JC{>4R9xn)Sm{ zPFaP}=GViwPKYyE)J~xhg{M#FjB5E&VHEJ0T_%idB;d5}b)#*|5_g}U z$eK2S?i59`85P*jyg$$5h|`iAfm(-$iJ1I^PW{?T@bSSdLWA3VQrb`bXzt+4gCb5r zjZM1-K4c3ZAz^L_L%8$NLo7q1@JXVHE#fqMX68;Rv+KMzybm6b5^h?0`%WSi6^)y| zdyFNqGnlrELHyz!;<0#ao7`YGUGCoTa$%7_vf6za*XTT9xgn#E!+{G^wCx(5jUQ%M z0#=VvcIMoiWtJZX((%;69*yG7`|>yXJL)ck!3#Iny62Nw^q;vu6sPi`^qGI_ zAw&1Mw_qb^-gNupVDDhB2AmgsCd26z-hg=j;w(k84ZQm~r`w(A*K*A+NxA`YxL)`8 z`L#`MrgatISGPQT;$GoahTLi~`hvE8zgxVXxeBOyoshl|+sCQc>&Bb_k5#|XBQQ%` zXx4f*Jn0^(hBz6cl#Yf@!!@6xdMCK_y`2~Le5N1NKtsH014ps(n;dB~rqaMpo}Eye zp#7`|us!HE;&*Cd(NJoqCc5z?2_AOtO8A_?4Dsq1m%1KWWaWCeo@)5`zN0{;5->te zX^%T<8W{6Wy=l_Y)9Zee`-Fe_NlC(xIg?xAJ{t7ioCQshvqI%tUgPGXo*bJgb@!PB z$2b}x`>-^@G*Y2qq%hGg1A(^A+IzOMn_fpaT@MfLP14$AaD6;7C0#L_to3}wFSq%& z!O@wFuXO6w7@b1qQG}UN-a!OV&UoUwhWBVHZ+Gn&Wr-$N(c$gDKFolqwUII+=<_2cO*e;$+>UMmFSW-m@@#zcy4+k0QOaf00&cyr#LY{Fvv(@vBc#VrxYl`T~2i zWNG>QRW%>?r8hI`B34J;Eh2ML>u+MM+M%L!XbaqKNE*6ZSMK@9#b+#6rar{X&#Hd= z&4GUtwHqA{^45Ch!9ua4=lk~kUZPLh)DDsR2*$5{R?^l(*_8SB+W4zi#@wGN9GOMr zrSLcu#osb4Hr9xDTsrFW^_DLxJbHPcllh=H-4G3tM2+`3pYz$O)Z?I!Cd5$0i@1VH zIQ`?4S~(r_Y{Gmx(|0)CU(YsnA*C8stlln=BJDBW-q|KJ>C4QF#7`NRV~Cniric(j zvAs3^`pLcF?wtpd)M#T&aqfx%UsRRE^_Hd`+}IqCAN=Lmd;_FZ`sBSd(Ob@VHZ>0TnrZ?*;R<{_!DtD@n$9%rT6iEuipq zKF|H`NpT*a@bwdgC(yDbzPsELQKTtkxzft-GI0wJW;=r)u6jc~5+)h=Z$ZJ0_j}u_w=Fz3ng(AK`GF z_CjIOYT7AIq2w)A?TSs##ia4~V|}le0@Zeg99D)G(`#9p(;^2;Ka$@0pn`+V+zBVR z6Y2l6tlQ+9vK6AL74`Cn`+3;+p&#;$#4;NSbaFD|YpL1|6jV)!jFt~{-TQpn zo4u;?;*0I7k@Il3)4+q|Tik+KsSL*)j%KoFX(umlJ&b)^^}4!HJP@q_U2T_V#-h)V z;K_N+!ZIIFgqpM2BnGQk;Z5><=2Bvn2;PeD?FOAEUZ$hb&L4-Hz#~QhIqB` z6}2$(zr7Q?uTEd1q}fv_U$UD$ib7ZLRsQk!%GW*Z<`F7;+Vb(FW)0ahRm!(tr|7ZG zHxUJR`^fK1nMJp|iYzHV-k`2)eM4V~*H}y=wUEFo-64hR)rpqZe~$0w+BUONt&5^z zJ*P6Ouio&ufvgv5*|t5gj}sA@`ID80X5SnWcEU+`qWZ1O8wZ=^`WpB~6fVN!?gg{k zMR6kOu^I5Tt2cJtj&Tx?ZwnfH%`>UU`=X|>0287SrqaKAm!ek_o3S*jjq-M2>K6mH z*UN>X9aE9D%kIS@vw^x`4U-YuJ z6V-}|vv_@zep9Y&oMM}Wsaj_#v+E?e=U|^0kIw4`6Ry50ua16(hgztV8INcc#%P0l z#QEGxj>n3ywR}^GYP(K{FM1cA z_v;$f+Q%~7T2^uMIIH-^E~GTs(`#k_35UZ>pkF;Brl^*JE~gLv{+q{K{nUPRc>%~p&uadzO2t+y6la}TCqL$|tCo47&AUTRfV z7t@z?T?6Gd52reBO2FEnqd#hOrxec$^Vh}ON2Le;;^Djgx+}~5uRa7*DIdfFwXX{# zO(>fYF;~e*R7cfZH3wGHL%G_&I4w~SAr4uP6%k{;dC32Si8fn7M?*&1()WyP)u42M z8NrNBqkaB;x1(6=E!0uAd_S6&fus+Skz6Sy?5`bvhkO=%=OYbPt8+g<<`QTG3=Vlu)QX zl^^!fXA`F=v0=L0;f+9Scv|)j7w$$Z5$3Ir?dAo;EtTowRk|nz*;V zof3cSoZ2FXW0|-hyEo0Y>8WoVv)E!xq-@_QP4%s1qESfMf#I<-8-}zq0>1-8+~SbF zFvFtk+WXg=Az@I01l(d&}agxef%!i6HEqnspst@4a(jAcp8=>&%*t#jN zB1RQvNn0`7Ft$4>)Z^C`%z17+MUc;9vX^yr>_Fz1IK<@0=;T--nT}--JD4SOx?Yf2 zCso6hHI`qO_kld~xFR~r2sgvQW8lc~(A7{zYfz2xXaM%vbjJ7E*ONf)>%2LfH`B^( zm5DA&(>1GTS(eF(~AwHT~Dbn5Pf%-fZ8-%&}Xc%ucU;tS^>eCZb(T9H84x=JMx7#ka$N{-KI zwhB#U{TSgYutyYiFMTSH1um{MH8uJfWH01bmO4?VdyB2fRdn7mjE~Kd2&3!#l5=QZNXj$BoSjOJK{H zF--~2FCV0EBW|4@nye@{%)FN#mVLrbwTmFr8CQe*6cKJvIW^+8@QKWw5H}Bz1?s-| zG2#A&PN&e2(9b(76N>~zce5SW21iqvbG1F9Rz`EwFeRBs>C0S__iaf~2(|X)Q=v3zF7?q_rSvEl64mlGgg~PHP#jDBLjt zVi;+-|MV*1Mebx^fK?V+kEnHP+AT3LQA$+ti4{3)eV_*-V=sC%2Ij>TgNciYiGeB{ zpt(Wr2~~LgItB)r9vN`y>C_Qgn|g%Dm~1^HO1k7oa*58gR9n`;d=OU<%J zs%Hd6CQ>~;j`%fh%v>~Wt|m(=Ia6>4VtLd4crV*^M*C!jPKUeK9mF1ziW%ZSkuz*! zs0T^wB6?wmtdYqZ;&GGnwqcG+1hwJziE&1gZ^LPd3FsN%o7=f#ZukV7KkiYVCrQeB z5#mw*@W9@?SE6Z(==>8onbXAfN!2qfjk2{aJ5=qP0@Y3;H>&i6CK#Ogzp*Rof0#P4 zdFer&e^=ZWJ_nj)+Ju0*HSUw7U*Z~B51(_i0WohITcnj?LMv`xrvVn-Qpr*;^Z&1S z3{u4b5|25#u`8)T;xR}(28qWY@fai?gT!NycnlJcLE^Fh?s)9~A@>3);{fsXA-?{# z809f6=e+kX^h_Wf(Os)2xdg z*wBVVHSFc9<(lUe98*EoN1Nq8oB^-#lG@aq`F-nFq9+F09&Gn{WvCTQ@>+LyC#oCg z!|*r`!p0avYdUwP*O#*Lg| zeQ)t0BB7!My(4R%_oUibCr3EHhLX7&`(CxxG#2JzoPD7whJ8_Ocb(yj1OCLXDTrO% zLn*yWyEdVZan7G>Th)8{<6` zTz2Sv0;p`!&*Is1R8kwdzUV?c(ShVIP(-^LN!ut$LlE%U9MPl5#l?lA$e)wxk_M7f z$;6#me@Z+^TRlxEpK7QaF-d*XGj+`CF}X8YGh97>O$g-YOX3Sv=(;w0^o8_P$%#|`72 z9&}Y=D=?tXJIS@sr3q&f=P%DuK5yDXp$6Uc4dy&uX+TV^Bw6%pGNQ))^cK10^N!AE zlIY|8b9NX(Z-U~+jwC`&{7)O5a0AesK7-7#pWtiX$v8pf4-opEX!47KQtLEOr<(gH zmS)T-U?;lz@$y!K#6XQIcQEz75`=>4XtBv{dpJc&`A%6^d&B|%be7-&uk;&H!)@AkILzOeXtammbU7X(k%Til!@(EL8x9A3s_ z<(neg=H;!>nFFHIDz%f3!qxjGg7BGi#g)uOmtW>2NQ-v$79qHLePRAU$d@J85~-)3 z9Il~rqqq$F#=hlfSRR6y&Q!SO)a}nIg4)P}LH#D91>jDj?jUon$VHW_eU?)G4dnwBMXar%wAvC7wy z%o}OBSJL(G&xiU-yM3FrxPMTjVN!phKBt~@`02j9zkYtZCnhnmsI}4tvmrNk345p3 z7tDw9LsRZB?8c%?LZ@ZqL-j< zaj3cS(Sr}fd50BMf%s*eE@u07N!ffv_le{Vb*Gmfy8C#cX1H5Kq`I!;_}`C(zNIhf zk3jQqB?;G4S7t~HIE6R;ER?yt54AXy;$BB)caNB9?6i2QM{yWaX~v$N=HBs1iyG}y zIo`T;3y&i{>WBdTbILbOC9@me+f-#Y;29iN zP<<{p@Rhr>1-kUD7=w!YJ9^YyOLL8AL}!P2R&I^)ud7(RnG+v4UYh!x)=Cu5F-uNv z)fXbaY-L6J!ZD2|SoCR7WYiXSb;{c(0zE3{W;qka?%~>k%)v^3C9F*ICM#i_(H7Q0 z|-_)WDE4@sA;@FWFm_i>Z&t*~K`+J(?4u)pwKfZtpv9 z$iJ^0q}(UZ*=3t=oCpGWP?+?G=9Yhq)YM6QFLUlvc?YX<-dYcq9>~n?0JppE2i5yTB-ZBSv*$ zDUrOj>+@EgArUHKD`JL}4ZBBTng%+AL+!CGuT;6hR3tgyMJ-Yr*<3>wXq_*JC`X8u zQ}5n+Cc#WNe<%1!O1Q#7iKsU1R~3RnJV`Fho_p%zAM>+GDKK-^8RsgozJ&7f@+hrw zm|MYMQA<|Cd%RG9E9w6-`S#<8qon#*<_BoJ0vx+luO>Q)1}&^9yx5vYuHlMb&w*uf zzC9|3EI<-oII@(-{3u8)`Q4JpQx<`@1$i>eIE8HRNtEO*X@Z5@@tvdYeZgt*_m)z% zYZ-{m%kU-Fx=Un})a@MAYb18eiwU=~Y7yQj`}Th|q5ranvpANo=!uK6U9?UX=tsjS1(t?9f} z*}222o5c5Tl4Zipj4Zf`5=7k;gm^5+Sa9iFx6-GJhc99 z|N3bF{SD^Iwws@rPunUw0$aUA94GkaB6yYaiR>j-L;5f)q4oHgl6?4!RPA?(uUR~K zn{M#*$m8DH=C|6AvT4kNo^r48LWkr|y)CS_-JDgd4-fME3fPQR3RO+5reoTJqwqGW zTZuT32YVJK-o(~l+tbEW#Wsma_$x5*v&e0Z;ucQHn&INaWxlhZmJ%cFe1S(a%d)D@zKWnvEzNT zEHtgAdoy$E9`~e=sf;n1WXhaM<0>-EV(zuDE-{OpLaOX*D7(l78BEwzND|v8Nn?j! zVl&IO0?{>Kp&8rU=lg9q#t9Gau`-UTz*sn@Du48Ct?{8Px*;O@%$!KRMcXAR$*+Vj z30sP*)6#?uxyhOQwitnMD$B><_y8f`WgU@NeqX0*2D%U^pBJru4z^hj^r%E|pz9JJ z*yJ{)-tF8gV)gh!PM8Z=y znp7jxSnnVNSKgG@lx16zRm5wz&L-X9`Wgm5ZHgLF+!>6zB2hkKD~A(df@UIoBc6zy`my z93C!sE|*ExVR)MM-1wZjgQwLpv7ob7@0FQms!83vjsGME6i2G1)oR1j02RKt@)Rk> zM?^|TX3ffR6?@xxx;P|8g|ZZiHgGjhwJdnXy|sBnQ*;c?^O2KLQQa0B(A8I~=tua; z@Ap4wXH~)Ey6e@Y(=n6mon06qbp2ruu@V>3t7-E+9bL~a>W!@BLijl?5z*H^?OiWw zr@mi4dZ^Q#$$m4lcb~>Y*|LL1b@;h)O^w}UZf$>Of1f>#|^(nOUdWctMK@$?krnXy_div zAe(1iN}KyZ@5uo}X-7U$D>Z$2M|%}A5{Q<^JQ-hC1UjqaYBNou9*i6l7swu|d~B z2tb%Z2KqTgLj(Mat0l9oy_vP6k-d_UqobL%iNn?3x&Mhu-0s9$5c)9EIJL!S6SRL6 zFkT}OG0KYwB;YlnY{Bm&U8M{a9a1zkl*N{b?+e8Dh;O@xZxOh5%(PRN*}bQ&Tjqfu7Hoe&XSuuy0nWj<4VBy5zDfy z#`O3cs%U?TxT+m-TYzX8# z)F2BJ)w%iXjQxxwqpJf|eU%jyp;1q8J>cz%yhgJY?qu;L!p`cTk}pdSzRl_^CTz5vy}vTlMvSipn*%a^984e*TL+EGW@&DO|4o5|J6QbG1I zK-7Q!!vWChE&xHk)S3d=UawmUC|$`o0U*Q_0HD0oSm*lx zHg+&IGIDhImpm80uwK+V11rvbhIl-EfaV8?LwJc;je0>ewAXXFNSHWVS&IGhor?+h zepR#uw;YZ_0Hg+g6{LdkJJ20)pdKt)SZx60|BFPt*uMjDg9Gi+l7@el{jL)f2oT|? zs~7hIRSiT2HZ z2f7Uo6jgR>h#eRtRxBW3hW>noSzUk}O!e%I43!*#%$tb=I1}sD^rh+oqWJzI%9h9P zL}3Ld3OqI2i(vq?hIrLDq29j(v4I0&dl+_l1D!7XOQ$FKU4X83`o+$!tDWBOiAS>p z7~~y5qWIY`pnCyVDgP`R|4h^0E*kl7NKwH9odW*=ycm&Sr+vVF7w$4x2~!^Z0eDeh z1T4_fDVFCuuo+O9@{-E$gZ=1dek@Yz=_B|051+|0}HgHY<+_djKm3GO}IP(VWa;5{C&6h5B1Q3 z2WrRs0r>k~LC%e{0@JQl$IUl zv>Je-1Gpxa#|&dTSPJXKw7-f8DE=~^4|LN!;A~xvG)THGFpj21Rz}PhKUu*=8rhUM zz0-g_x`5+9FUxV<4_*$i!v*`=VpAKS4k8d`T<&L#QLq@WL)U9*UCtQjpdEm8nSwR} zmIAh$n{x8)tN}tUFdZ*b@+ZMkz*?50L3a!qAh?lUHH-w$a0aiM>{Dg_W7 z=-InTTN@g={u4@Fl_ebc0~-P$hXSD1_mhWyTvRJR$)aa#3r-XR1!xx{Kny~Fa9I?C zwLggh*7wZw?RlCFM3S|@xTXCe2k@{x9->_poD^!s%xZ~Tb`eudL3Yw4s1VBZJW<#mA&3hK&2`STJ5c7(~b z-4Os>RnQdhxjYB`|AGB`27|TH&slaFfbioIfxZysKddTX2Sh$1#=Gyvs`+JEU_`xu z{#zul3W2cXaM}K~_3*MtGH8Dz64-I|dp+L~{tXnY@otp#eP{yojQT~-0-8&Df?Z~2 zG%zE}fo1m${^}@5p}lDR(<6zWM*&!q|6acchQHAd>>}}ds2kVcK*6qJzlR!%{tXoD znE5?aUjA>OU_0pQQSU$I29M?i^fw&@)|OX~RQ~}Z(Yk>Bdrtfxjn@26>;EuK!QL~k z9;^66q$1NxB7q%oSC0Vv(OSs-uS^bB(W_^B{GiqW$9(`kN^ux7iuh5Scrvb4XF32b!mv;8jL9jada4HfL&{b%T9^JP~24V3j?GXxHZD?uPF Q;LiY%N{Va(?hBy*0aj&qEC2ui literal 0 HcmV?d00001 diff --git a/service-mgmt/sm-db-1.0.0/patches/sm_db_ceph_install.patch b/service-mgmt/sm-db-1.0.0/patches/sm_db_ceph_install.patch new file mode 100644 index 00000000..7f28fe13 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/patches/sm_db_ceph_install.patch @@ -0,0 +1,31 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# SPDX-License-Identifier: Apache-2.0 +# +# +# +# +# Description: installs the ceph-rest-api and ceph-alarm-manager on the controllers. +# +# ceph-rest-api +INSERT INTO "SERVICE_DOMAIN_MEMBERS_V1" VALUES(7,'controller','storage-services','N',2,0,'',''); +INSERT INTO "SERVICE_GROUPS_V1" VALUES(7,'storage-services','no','no','initial','initial','none','none',120000,'yes'); +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(55,'storage-services','ceph-rest-api','critical'); +INSERT INTO "SERVICES_V1" VALUES(55,'ceph-rest-api','initial','initial','none','none',2,1,60000,4,16,'/var/run/ceph/ceph-rest-api.pid'); +INSERT INTO "SERVICE_INSTANCES_V1" VALUES(59,'ceph-rest-api','ceph-rest-api',''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('ceph-rest-api','enable','lsb-script','','ceph-rest-api','start','',2,2,2,10,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('ceph-rest-api','disable','lsb-script','','ceph-rest-api','stop','',1,1,1,10,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('ceph-rest-api','audit-enabled','lsb-script','','ceph-rest-api','status','',2,2,2,10,40); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('ceph-rest-api','audit-disabled','lsb-script','','ceph-rest-api','status','',0,0,0,10,40); +# ceph-alarm-manager +INSERT INTO "SERVICE_DOMAIN_MEMBERS_V1" VALUES(8,'controller','storage-monitoring-services','N + M',1,1,'',''); +INSERT INTO "SERVICE_GROUPS_V1" VALUES(8,'storage-monitoring-services','no','no','initial','initial','none','none',120000,'no'); +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(56,'storage-monitoring-services','ceph-alarm-manager','critical'); +INSERT INTO "SERVICES_V1" VALUES(56,'ceph-alarm-manager','initial','initial','none','none',2,1,60000,4,16,'/var/run/ceph/ceph-alarm-manager.pid'); +INSERT INTO "SERVICE_INSTANCES_V1" VALUES(60,'ceph-alarm-manager','ceph-alarm-manager',''); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','ceph-alarm-manager','not-applicable','enable','ceph-rest-api','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','ceph-rest-api','not-applicable','disable','ceph-alarm-manager','disabled'); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('ceph-alarm-manager','enable','lsb-script','','ceph-alarm-manager','start','',2,2,2,10,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('ceph-alarm-manager','disable','lsb-script','','ceph-alarm-manager','stop','',1,1,1,10,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('ceph-alarm-manager','audit-enabled','lsb-script','','ceph-alarm-manager','status','',2,2,2,10,40); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('ceph-alarm-manager','audit-disabled','lsb-script','','ceph-alarm-manager','status','',0,0,0,10,40); diff --git a/service-mgmt/sm-db-1.0.0/patches/sm_db_cinder_lvm_install.patch b/service-mgmt/sm-db-1.0.0/patches/sm_db_cinder_lvm_install.patch new file mode 100644 index 00000000..0d0b61ce --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/patches/sm_db_cinder_lvm_install.patch @@ -0,0 +1,60 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# SPDX-License-Identifier: Apache-2.0 +# +# +# +# +# Description: installs the services for the cinder LVM backend on the controllers. +# +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(57,'controller-services','drbd-cinder','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(58,'controller-services','cinder-lvm','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(59,'controller-services','tgtd','critical'); +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(60,'controller-services','cinder-ip','critical'); + +INSERT INTO "SERVICES_V1" VALUES(57,'drbd-cinder','initial','initial','none','none',2,1,60000,4,16,''); +INSERT INTO "SERVICES_V1" VALUES(58,'cinder-lvm','initial','initial','none','none',2,1,60000,4,16,''); +INSERT INTO "SERVICES_V1" VALUES(59,'tgtd','initial','initial','none','none',2,1,60000,4,16,''); +INSERT INTO "SERVICES_V1" VALUES(60,'cinder-ip','initial','initial','none','none',2,1,60000,4,16,''); + +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','drbd-cinder','not-applicable','go-active','management-ip','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','cinder-lvm','not-applicable','enable','drbd-cinder','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','tgtd','not-applicable','enable','cinder-lvm','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','tgtd','not-applicable','enable','drbd-cgcs','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','cinder-ip','not-applicable','enable','tgtd','enabled-active'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','cinder-volume','not-applicable','enable','cinder-ip','enabled-active'); + +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','cinder-ip','not-applicable','disable','cgcs-nfs-ip','disabled'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','cinder-ip','not-applicable','disable','cinder-volume','disabled'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','tgtd','not-applicable','disable','cinder-ip','disabled'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','drbd-cgcs','not-applicable','disable','tgtd','disabled'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','cinder-lvm','not-applicable','disable','tgtd','disabled'); +INSERT INTO "SERVICE_DEPENDENCY_V1" VALUES('action','drbd-cinder','not-applicable','go-standby','cinder-lvm','disabled'); + +# drbd_cinder service +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('drbd-cinder','enable','ocf-script','linbit','drbd','start','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,90,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('drbd-cinder','disable','ocf-script','linbit','drbd','stop','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',1,1,1,180,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('drbd-cinder','go-active','ocf-script','linbit','drbd','promote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('drbd-cinder','go-standby','ocf-script','linbit','drbd','demote','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('drbd-cinder','audit-enabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',2,2,2,20,30); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('drbd-cinder','audit-disabled','ocf-script','linbit','drbd','monitor','master_max=1,master_node_max=1,clone_max=2,clone_node_max=1,notify=true,globally_unique=false',0,0,0,20,28); + +# cinder_lvm service +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('cinder-lvm','enable','ocf-script','heartbeat','LVM','start','',2,2,2,30,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('cinder-lvm','disable','ocf-script','heartbeat','LVM','stop','',1,1,1,30,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('cinder-lvm','audit-enabled','ocf-script','heartbeat','LVM','monitor','',2,2,2,30,10); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('cinder-lvm','audit-disabled','ocf-script','heartbeat','LVM','monitor','',0,0,0,30,10); + +# tgtd service +# The tgtd init script blocks until it exports all the existing targets. Using +# a very long timeout to ensure that it is never killed while doing this. +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('tgtd','enable','lsb-script','','tgtd','start','',2,2,2,180,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('tgtd','disable','lsb-script','','tgtd','forcedstop','',1,1,1,10,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('tgtd','audit-enabled','lsb-script','','tgtd','status','',2,2,2,10,5); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('tgtd','audit-disabled','lsb-script','','tgtd','status','',0,0,0,10,5); + +# cinder_ip service +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('cinder-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('cinder-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('cinder-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('cinder-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); diff --git a/service-mgmt/sm-db-1.0.0/patches/sm_db_pxeboot_install.patch b/service-mgmt/sm-db-1.0.0/patches/sm_db_pxeboot_install.patch new file mode 100644 index 00000000..6adbeb85 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/patches/sm_db_pxeboot_install.patch @@ -0,0 +1,17 @@ +# +# Copyright (c) 2015 Wind River Systems, Inc. +# SPDX-License-Identifier: Apache-2.0 +# +# +# +# +# Description: installs the services for the PXEBoot network +# +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(67,'controller-services','pxeboot-ip','critical'); + +INSERT INTO "SERVICES_V1" VALUES(67,'pxeboot-ip','initial','initial','none','none',2,1,60000,4,16,''); + +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('pxeboot-ip','enable','ocf-script','heartbeat','IPaddr2','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('pxeboot-ip','disable','ocf-script','heartbeat','IPaddr2','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('pxeboot-ip','audit-enabled','ocf-script','heartbeat','IPaddr2','monitor','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('pxeboot-ip','audit-disabled','ocf-script','heartbeat','IPaddr2','monitor','',0,0,0,20,5); diff --git a/service-mgmt/sm-db-1.0.0/scripts/sm-db-populate.script b/service-mgmt/sm-db-1.0.0/scripts/sm-db-populate.script new file mode 100755 index 00000000..cc47a801 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/scripts/sm-db-populate.script @@ -0,0 +1,47 @@ +#!/bin/bash +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +DATABASE=sm.db.v1 +HEARTBEAT_DATABASE=sm.hb.db.v1 +CSV_DIR=./ + +sm-db-build +mv sm.db.main ${DATABASE} +mv sm.db.hb ${HEARTBEAT_DATABASE} + +echo -e "Populate SERVICE_DOMAINS_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceDomains.csv SERVICE_DOMAINS_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_DOMAIN_INTERFACES_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceDomainInterfaces.csv SERVICE_DOMAIN_INTERFACES_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_DOMAIN_MEMBERS_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceDomainMembers.csv SERVICE_DOMAIN_MEMBERS_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_GROUPS_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceGroups.csv SERVICE_GROUPS_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_GROUP_MEMBERS_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceGroupMembers.csv SERVICE_GROUP_MEMBERS_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICES_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/Services.csv SERVICES_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_INSTANCES_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceInstances.csv SERVICE_INSTANCES_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_DEPENDENCY_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceDependency.csv SERVICE_DEPENDENCY_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_ACTIONS_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceActions.csv SERVICE_ACTIONS_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_ACTION_RESULTS_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceActionResults.csv SERVICE_ACTION_RESULTS_V1 \n" | /usr/bin/sqlite3 ${DATABASE} + +echo -e "Populate SERVICE_HEARTBEAT_V1" +/bin/echo -e ".separator | \n.import ${CSV_DIR}/ServiceHeartbeat.csv SERVICE_HEARTBEAT_V1 \n" | /usr/bin/sqlite3 ${HEARTBEAT_DATABASE} + diff --git a/service-mgmt/sm-db-1.0.0/src/Makefile b/service-mgmt/sm-db-1.0.0/src/Makefile new file mode 100644 index 00000000..71472cfc --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/Makefile @@ -0,0 +1,62 @@ +# +# Copyright (c) 2014 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# +INCLUDES =-I$(STAGING_DIR)/usr/include/glib-2.0 +INCLUDES+=-I$(STAGING_DIR)/usr/lib64/glib-2.0/include + +SRCS=sm_db.c +SRCS+=sm_db_iterator.c +SRCS+=sm_db_foreach.c +SRCS+=sm_db_nodes.c +SRCS+=sm_db_node_history.c +SRCS+=sm_db_service_domains.c +SRCS+=sm_db_service_domain_interfaces.c +SRCS+=sm_db_service_domain_members.c +SRCS+=sm_db_service_domain_neighbors.c +SRCS+=sm_db_service_domain_assignments.c +SRCS+=sm_db_service_groups.c +SRCS+=sm_db_service_group_members.c +SRCS+=sm_db_services.c +SRCS+=sm_db_service_heartbeat.c +SRCS+=sm_db_service_dependency.c +SRCS+=sm_db_service_instances.c +SRCS+=sm_db_service_actions.c +SRCS+=sm_db_service_action_results.c +SRCS+=sm_db_build.c +SRCS+=sm_db_configuration.c + +OBJS = $(SRCS:.c=.o) +CCFLAGS= -fPIC -g -O2 -Wall -Werror +EXTRACCFLAGS= -D__STDC_FORMAT_MACROS +LDLIBS= -lsqlite3 -lglib-2.0 -luuid -lrt -lsm_common +LDFLAGS = -shared -rdynamic + +build: libsm_db.so sm_db_build + +.c.o: + $(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) -c $< -o $@ + +libsm_db.so: libsm_db.so.$(VER_MJR) + ln -sf $^ $@ + +libsm_db.so.$(VER_MJR): libsm_db.so.$(VER) + ln -sf $^ $@ + +libsm_db.so.$(VER): ${OBJS} + $(CXX) ${LDFLAGS} $(LDLIBS) -Wl,-soname,libsm_db.so.$(VER_MJR) -o $@ $^ + +sm_db_build: ${OBJS} + $(CXX) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) $(OBJS) $(LDLIBS) -o sm_db_build + +install_non_bb: + install -d ${DEST_DIR}/usr/lib64 + install libsm_db.so.${VER} $(DEST_DIR)/usr/lib64 + cp -P libsm_db.so libsm_db.so.$(VER_MJR) $(DEST_DIR)/usr/lib64 + install -d ${DEST_DIR}/usr/include + install -m 0644 *.h ${DEST_DIR}/usr/include + install -d 755 ${DEST_DIR}/usr/bin + +clean: + @rm -f *.o *.a *.so *.so.* diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db.c b/service-mgmt/sm-db-1.0.0/src/sm_db.c new file mode 100644 index 00000000..af1df513 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db.c @@ -0,0 +1,1131 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db_nodes.h" +#include "sm_db_node_history.h" +#include "sm_db_service_domains.h" +#include "sm_db_service_domain_interfaces.h" +#include "sm_db_service_domain_members.h" +#include "sm_db_service_domain_neighbors.h" +#include "sm_db_service_domain_assignments.h" +#include "sm_db_service_groups.h" +#include "sm_db_service_group_members.h" +#include "sm_db_services.h" +#include "sm_db_service_heartbeat.h" +#include "sm_db_service_dependency.h" +#include "sm_db_service_instances.h" +#include "sm_db_service_actions.h" +#include "sm_db_service_action_results.h" + +SmErrorT sm_db_patch(const char* sm_db_name); +// **************************************************************************** +// Database - Transaction Start +// ============================ +SmErrorT sm_db_transaction_start( SmDbHandleT* sm_db_handle ) +{ + char* error = NULL; + int rc; + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, "BEGIN TRANSACTION;", 0, 0, + &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to start a transaction, rc=%i, error=%s.", rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Transaction End +// ========================== +SmErrorT sm_db_transaction_end( SmDbHandleT* sm_db_handle ) +{ + char* error = NULL; + int rc; + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, "END TRANSACTION;", 0, 0, + &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to end a transaction, rc=%i, error=%s.", rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Statement Result Reset +// ================================= +SmErrorT sm_db_statement_result_reset( SmDbStatementT* sm_db_statement ) +{ + int rc; + + rc = sqlite3_reset( (sqlite3_stmt*) sm_db_statement ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to reset statement results, rc=%i.", rc ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Statement Result Step +// ================================= +SmErrorT sm_db_statement_result_step( SmDbStatementT* sm_db_statement, + bool* done ) +{ + int rc; + + *done = false; + + rc = sqlite3_step( (sqlite3_stmt*) sm_db_statement ); + if( SQLITE_ROW != rc ) + { + *done = true; + + if( SQLITE_DONE != rc ) + { + DPRINTFE( "Failed to step through statement results, rc=%i.", rc ); + return( SM_FAILED ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Statement Initialize +// =============================== +SmErrorT sm_db_statement_initialize( SmDbHandleT* sm_db_handle, + const char* sql_statement, SmDbStatementT** sm_db_statement ) +{ + int rc; + + rc = sqlite3_prepare_v2( (sqlite3*) sm_db_handle, sql_statement, -1, + (sqlite3_stmt **) sm_db_statement, NULL ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to initialize statement (%s), rc=%i.", sql_statement, + rc ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Statement Finalize +// ============================= +SmErrorT sm_db_statement_finalize( SmDbStatementT* sm_db_statement ) +{ + int rc; + + rc = sqlite3_finalize( (sqlite3_stmt*) sm_db_statement ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to finalize statement, rc=%i.", rc ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Connect +// ================== +SmErrorT sm_db_connect( const char* sm_db_name, SmDbHandleT** sm_db_handle ) +{ + int rc; + + rc = sqlite3_open_v2( sm_db_name, (sqlite3**) sm_db_handle, + SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | + SQLITE_OPEN_NOMUTEX, NULL ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to connect to database (%s), rc=%i.", sm_db_name, rc ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Disconnect +// ===================== +SmErrorT sm_db_disconnect( SmDbHandleT* sm_db_handle ) +{ + int rc; + + rc = sqlite3_close( (sqlite3*) sm_db_handle ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to disconnect from database, rc=%i.", rc ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Build Main +// ===================== +static SmErrorT sm_db_build_main( SmDbHandleT* sm_db_handle ) +{ + SmErrorT error; + + // Create Database Tables. + error = sm_db_nodes_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create node table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_node_history_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create node history table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_interfaces_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service domain interfaces table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domains_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service domains table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_members_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service domain members table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_neighbors_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service domain neighbors table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_assignments_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service domain assignments table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_groups_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service groups table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_group_members_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service group members table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_services_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create services table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_heartbeat_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service heartbeat table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_dependency_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service dependency table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_instances_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service instances table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_actions_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service actions table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_action_results_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service action results table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + // Cleanup Database Tables. + error = sm_db_nodes_cleanup_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup nodes table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_interfaces_cleanup_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup service domain interfaces table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domains_cleanup_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup service domains table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_neighbors_cleanup_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup service domain neighbors table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_assignments_cleanup_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup service domain assignments table, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_groups_cleanup_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup service groups table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_services_cleanup_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup services table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Build Heartbeat +// ========================== +static SmErrorT sm_db_build_heartbeat( SmDbHandleT* sm_db_handle ) +{ + SmErrorT error; + + // Create Database Tables. + error = sm_db_service_heartbeat_create_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to create service heartbeat table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + // Cleanup Database Tables. + error = sm_db_service_heartbeat_cleanup_table( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to cleanup service heartbeat table, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Build +// ================ +SmErrorT sm_db_build( const char* sm_db_name, SmDbTypeT sm_db_type ) +{ + int rc; + char* sqlite3_error = NULL; + SmDbHandleT* sm_db_handle; + SmErrorT error; + + error = sm_db_connect( sm_db_name, &sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + return( error ); + } + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, "PRAGMA journal_mode=WAL;", + NULL, NULL, &sqlite3_error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to set pragma journal mode to WAL, rc=%i, error=%s.", + rc, sqlite3_error ); + sqlite3_free( sqlite3_error ); + goto ERROR; + } + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, "PRAGMA auto_vacuum = FULL;", + NULL, NULL, &sqlite3_error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to set pragma auto-vacumm to FULL, rc=%i, error=%s.", + rc, sqlite3_error ); + sqlite3_free( sqlite3_error ); + goto ERROR; + } + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, "PRAGMA synchronous = FULL;", + NULL, NULL, &sqlite3_error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to set pragma synchronous to FULL, rc=%i, error=%s.", + rc, sqlite3_error ); + sqlite3_free( sqlite3_error ); + goto ERROR; + } + + if( SM_DB_TYPE_MAIN == sm_db_type ) + { + error = sm_db_build_main( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to build main database, error=%s.", + sm_error_str(error) ); + goto ERROR; + } + } else if( SM_DB_TYPE_HEARTBEAT == sm_db_type ) { + error = sm_db_build_heartbeat( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to build heartbeat database, error=%s.", + sm_error_str(error) ); + goto ERROR; + } + } else { + DPRINTFE( "Unknown database name (%s) given.", sm_db_name ); + goto ERROR; + } + + error = sm_db_disconnect( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + } + + return( SM_OKAY ); + +ERROR: + error = sm_db_disconnect( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - clean failed db copy +// ==================== +SmErrorT _clean_failed_db( const char* sm_db_name ) +{ + int errno; + errno = unlink(sm_db_name ); + if ( 0 == errno ) + { + DPRINTFD( "%s is removed.", sm_db_name ); + return SM_OKAY; + } + + DPRINTFE( "Failed to remove %s. Error %d", sm_db_name, errno ); + return SM_FAILED; +} +// **************************************************************************** + +// **************************************************************************** +// Database - Configure +// ==================== +SmErrorT sm_db_configure( const char* sm_db_name, SmDbTypeT sm_db_type ) +{ + bool copy_master_db; + bool check_passed; + SmErrorT error; + + copy_master_db = false; + + if( 0 > access( sm_db_name, F_OK ) ) + { + if( ENOENT == errno ) + { + copy_master_db = true; + DPRINTFI( "Database file (%s) not available.", sm_db_name ); + + } else { + DPRINTFE( "Database file (%s) access failed, error=%s.", + sm_db_name, strerror( errno ) ); + return( SM_FAILED ); + } + } + + if( !copy_master_db ) + { + error = sm_db_integrity_check( sm_db_name, &check_passed ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to do integrity check on database (%s), " + "error=%s.", sm_db_name, sm_error_str( error ) ); + return( error ); + } + + copy_master_db = !check_passed; + } + + if( copy_master_db ) + { + FILE* in = NULL; + FILE* out= NULL; + char buf[8192] = {0}; + ssize_t rlen = 0; + ssize_t wlen = 0; + + if( 0 == strcmp( SM_DATABASE_NAME, sm_db_name ) ) + { + in = fopen( SM_MASTER_DATABASE_NAME, "r" ); + if( NULL == in ) + { + DPRINTFE( "Failed to open master database (%s).", + SM_MASTER_DATABASE_NAME ); + return( SM_FAILED ); + } + } + else if( 0 == strcmp( SM_HEARTBEAT_DATABASE_NAME, sm_db_name ) ) + { + in = fopen( SM_MASTER_HEARTBEAT_DATABASE_NAME, "r" ); + if( NULL == in ) + { + DPRINTFE( "Failed to open master database (%s).", + SM_MASTER_HEARTBEAT_DATABASE_NAME ); + return( SM_FAILED ); + } + } else { + DPRINTFE( "Unknown database (%s) requested to configure.", + sm_db_name ); + return( SM_FAILED ); + } + + out = fopen( sm_db_name, "w" ); + if( NULL == out ) + { + DPRINTFE( "Failed to open master database (%s).", sm_db_name ); + fclose( in ); + return( SM_FAILED ); + } + + while( true ) + { + rlen = read( fileno(in), buf, sizeof(buf) ); + if( 0 == rlen ) + { + break; + + } else if ( 0 > rlen ) { + DPRINTFE( "Failed to read for database (%s), error=%s.", + sm_db_name, strerror(errno) ); + fclose( in ); + fclose( out ); + _clean_failed_db( sm_db_name ); + return( SM_FAILED ); + } + + wlen = write( fileno(out), buf, rlen ); + if( 0 > wlen ) + { + DPRINTFE( "Failed to write to database (%s), error=%s.", + sm_db_name, strerror(errno) ); + fclose( in ); + fclose( out ); + _clean_failed_db( sm_db_name ); + return( SM_FAILED ); + } + + if( rlen != wlen ) + { + DPRINTFE( "Failed to write all data to database (%s), " + "rlen=%i, wlen=%i.", sm_db_name, + (int) rlen, (int) wlen ); + fclose( in ); + fclose( out ); + _clean_failed_db( sm_db_name ); + return( SM_FAILED ); + } + } + + DPRINTFI( "Master database copy completed." ); + + error = sm_db_integrity_check( sm_db_name, &check_passed ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to do integrity check on database (%s), " + "error=%s.", sm_db_name, sm_error_str( error ) ); + fclose( in ); + fclose( out ); + _clean_failed_db( sm_db_name ); + return( error ); + } + + if( !check_passed ) + { + DPRINTFE( "Database (%s) integrity check failed, after master " + "database copy.", sm_db_name ); + fclose( in ); + fclose( out ); + _clean_failed_db( sm_db_name ); + return( SM_FAILED ); + } + + error = sm_db_patch(sm_db_name); + if ( SM_OKAY != error ) + { + _clean_failed_db( sm_db_name ); + return( error ); + } + } + + error = sm_db_build( sm_db_name, sm_db_type ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to do build database (%s), error=%s.", + sm_db_name, sm_error_str( error ) ); + _clean_failed_db( sm_db_name ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Integrity Check Callback +// =================================== +static int sm_db_integrity_check_callback( void* user_data, int num_cols, + char **col_data, char **col_name ) +{ + bool* check_passed = (bool*) user_data; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + if( 0 == strcmp( col_data[col_i], "ok" ) ) + { + *check_passed = true; + + } else { + DPRINTFE( "Database integrity error detected, error=%s.", + col_data[col_i] ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Integrity Check +// ========================== +SmErrorT sm_db_integrity_check( const char* sm_db_name, bool* check_passed ) +{ + int rc; + char* sqlite3_error = NULL; + SmDbHandleT* sm_db_handle; + SmErrorT error; + + *check_passed = false; + + error = sm_db_connect( sm_db_name, &sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + return( error ); + } + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, "PRAGMA integrity_check;", + sm_db_integrity_check_callback, check_passed, + &sqlite3_error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to execute database (%s) integrity check, rc=%i, " + "error=%s.", sm_db_name, rc, sqlite3_error ); + sqlite3_free( sqlite3_error ); + goto ERROR; + } + + error = sm_db_disconnect( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + } + + return( SM_OKAY ); + +ERROR: + error = sm_db_disconnect( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Checkpoint +// ===================== +SmErrorT sm_db_checkpoint( const char* sm_db_name ) +{ + int wal_num_frames, checkpointed_frames; + int rc; + SmDbHandleT* sm_db_handle; + SmErrorT error; + + error = sm_db_connect( sm_db_name, &sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to open database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + return( error ); + } + + rc = sqlite3_wal_checkpoint_v2( (sqlite3*) sm_db_handle, NULL, + SQLITE_CHECKPOINT_PASSIVE, + &wal_num_frames, &checkpointed_frames ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to checkpoint database (%s), rc=%i.", sm_db_name, + rc ); + goto ERROR; + } + + DPRINTFD( "Database (%s) checkpoint complete, wal_num_frames=%i, " + "checkpointed_frames=%i.", sm_db_name, wal_num_frames, + checkpointed_frames ); + + error = sm_db_disconnect( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + } + + return( SM_OKAY ); + +ERROR: + error = sm_db_disconnect( sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to close database (%s), error=%s.", sm_db_name, + sm_error_str( error ) ); + } + + return( SM_FAILED ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - patch +// =================== +SmErrorT sm_db_patch(const char* sm_db_name) +{ + SmErrorT result = SM_OKAY; + if( 0 == strcmp(sm_db_name, SM_DATABASE_NAME) ) + { + FILE *fp; + char cmd_line[255]; + char line[1024]; + int ret; + + struct stat stat_o = {0}; + struct stat stat_n = {0}; + bool changed = true; + + if( 0 != stat(SM_DATABASE_NAME, &stat_o) ) + { + DPRINTFE("Failed to get stat: %s", SM_DATABASE_NAME); + } + snprintf(cmd_line, sizeof(cmd_line), "cat %s | sqlite3 %s 2>&1", + SM_PATCH_SCRIPT, + SM_DATABASE_NAME + ); + + fp = popen(cmd_line, "r"); + if (fp == NULL) { + DPRINTFE("Failed to execute patch script."); + return SM_FAILED; + } + + while (fgets(line, sizeof(line) - 1, fp) != NULL) { + DPRINTFI("%s", line); + } + ret = pclose(fp); + + if( 0 != stat_o.st_mtime) + { + if(0 != stat(SM_DATABASE_NAME, &stat_n)) + { + DPRINTFE("Failed to get stat: %s", SM_DATABASE_NAME); + }else + { + changed = (stat_n.st_mtime != stat_o.st_mtime || + stat_n.st_mtim.tv_nsec != stat_o.st_mtim.tv_nsec); + } + } + + if (0 == ret) + { + if(changed) + { + DPRINTFI("Patch script completed successfully."); + } + }else + { + result = SM_FAILED; + DPRINTFE("Patch script failed."); + } + } + return result; +} +// **************************************************************************** + +// **************************************************************************** +// Database - Initialize +// ===================== +SmErrorT sm_db_initialize( void ) +{ + SmErrorT error; + + error = sm_db_nodes_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node database module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_node_history_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize node history database module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_interfaces_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain interfaces database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domains_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domains database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_members_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain members database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_neighbors_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain neighbors database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_domain_assignments_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service domain assignments database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_groups_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service groups database module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_group_members_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service group members database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_services_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize services database module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_heartbeat_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service heartbeat database module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_dependency_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service dependency database module, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_instances_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service instances database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_actions_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service actions database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + error = sm_db_service_action_results_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize service action results database " + "module, error=%s.", sm_error_str( error ) ); + return( error ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database - Finalize +// =================== +SmErrorT sm_db_finalize( void ) +{ + SmErrorT error; + + error = sm_db_service_action_results_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service action results database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_actions_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service actions database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_instances_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service instances database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_heartbeat_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service heartbeat database module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_dependency_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service dependency database module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_db_services_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize services database module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_group_members_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service group members database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_groups_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service groups database module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_domain_assignments_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service domain assignments database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_domain_neighbors_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service domain neighbors database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_domain_members_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service domain members database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_domains_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service domains database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_service_domain_interfaces_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize service domain interfaces database " + "module, error=%s.", sm_error_str( error ) ); + } + + error = sm_db_node_history_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize node database module, " + "error=%s.", sm_error_str( error ) ); + } + + error = sm_db_nodes_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize node database module, " + "error=%s.", sm_error_str( error ) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** \ No newline at end of file diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db.h b/service-mgmt/sm-db-1.0.0/src/sm_db.h new file mode 100644 index 00000000..5617c7ef --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db.h @@ -0,0 +1,112 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_H__ +#define __SM_DB_H__ + +#include + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void SmDbHandleT; +typedef void SmDbStatementT; + +// **************************************************************************** +// Database - Statement Result Reset +// ================================= +extern SmErrorT sm_db_statement_result_reset( SmDbStatementT* sm_db_statement ); +// **************************************************************************** + +// **************************************************************************** +// Database - Statement Result Step +// ================================= +extern SmErrorT sm_db_statement_result_step( SmDbStatementT* sm_db_statement, + bool* done ); +// **************************************************************************** + +// **************************************************************************** +// Database - Transaction Start +// ============================ +extern SmErrorT sm_db_transaction_start( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database - Transaction End +// ========================== +extern SmErrorT sm_db_transaction_end( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database - Statement Initialize +// =============================== +extern SmErrorT sm_db_statement_initialize( SmDbHandleT* sm_db_handle, + const char* sql_statement, SmDbStatementT** sm_db_statement ); +// **************************************************************************** + +// **************************************************************************** +// Database - Statement Finalize +// ============================= +extern SmErrorT sm_db_statement_finalize( SmDbStatementT* sm_db_statement ); +// **************************************************************************** + +// **************************************************************************** +// Database - Connect +// ================== +extern SmErrorT sm_db_connect( const char* sm_db_name, + SmDbHandleT** sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database - Disconnect +// ===================== +extern SmErrorT sm_db_disconnect( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database - Configure +// ==================== +extern SmErrorT sm_db_configure( const char* sm_db_name, SmDbTypeT sm_db_type ); +// **************************************************************************** + +// **************************************************************************** +// Database - Build +// ================ +extern SmErrorT sm_db_build( const char* sm_db_name, SmDbTypeT sm_db_type ); +// **************************************************************************** + +// **************************************************************************** +// Database - Integrity Check +// ========================== +extern SmErrorT sm_db_integrity_check( const char* sm_db_name, + bool* check_passed ); +// **************************************************************************** + +// **************************************************************************** +// Database - Checkpoint +// ===================== +extern SmErrorT sm_db_checkpoint( const char* sm_db_name ); +// **************************************************************************** + +// **************************************************************************** +// Database - Initialize +// ===================== +extern SmErrorT sm_db_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database - Finalize +// =================== +extern SmErrorT sm_db_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_build.c b/service-mgmt/sm-db-1.0.0/src/sm_db_build.c new file mode 100644 index 00000000..9bfb83fb --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_build.c @@ -0,0 +1,75 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include +#include +#include + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Main - Database Builder +// ======================= +int main( int argc, char *argv[], char *envp[] ) +{ + char main_db_name[] = "sm.db.main"; + char heartbeat_db_name[] = "sm.db.hb"; + SmErrorT error; + + error = sm_debug_initialize(); + if( SM_OKAY != error ) + { + printf( "Debug initialization failed, error=%s.", + sm_error_str( error ) ); + return( EXIT_FAILURE ); + } + + error = sm_db_initialize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize database module, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + DPRINTFI( "Building Databases." ); + + error = sm_db_build( main_db_name, SM_DB_TYPE_MAIN ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed build database, error=%s.", + sm_error_str(error) ); + return( error ); + } + + error = sm_db_build( heartbeat_db_name, SM_DB_TYPE_HEARTBEAT ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed build heartbeat database, error=%s.", + sm_error_str(error) ); + return( error ); + } + + DPRINTFI( "Building Databases Complete." ); + + error = sm_db_finalize(); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finialize database module, error=%s.", + sm_error_str( error ) ); + } + + error = sm_debug_finalize(); + if( SM_OKAY != error ) + { + printf( "Debug finalization failed, error=%s.", + sm_error_str( error ) ); + } + + return( EXIT_SUCCESS ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_configuration.c b/service-mgmt/sm-db-1.0.0/src/sm_db_configuration.c new file mode 100644 index 00000000..c257d13e --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_configuration.c @@ -0,0 +1,68 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_configuration.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Configuration - Convert +// ========================================= +SmErrorT sm_db_configuration_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbConfigurationT* record = (SmDbConfigurationT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_CONFIGURATION_TABLE_COLUMN_KEY, + col_name ) ) + { + strncpy( record->key, col_data, SM_CONFIGURATION_KEY_MAX_CHAR ); + } + else if( 0 == strcmp( SM_CONFIGURATION_TABLE_COLUMN_VALUE, + col_name ) ) + { + strncpy( record->value, col_data, SM_CONFIGURATION_VALUE_MAX_CHAR ); + } + else if( 0 == strcmp( SM_CONFIGURATION_TABLE_COLUMN_ID, + col_name ) ) + { + //don't care + } + else { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} + +// **************************************************************************** + +// **************************************************************************** +// Database Configuration - Initialize +// ============================================ +SmErrorT sm_db_configuration_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Configuration - Finalize +// ========================================== +SmErrorT sm_db_configuration_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_configuration.h b/service-mgmt/sm-db-1.0.0/src/sm_db_configuration.h new file mode 100644 index 00000000..2e6321a1 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_configuration.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2018 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_CONFIGURATION_H__ +#define __SM_DB_CONFIGURATION_H__ + +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_CONFIGURATION_TABLE_NAME "CONFIGURATION" +#define SM_CONFIGURATION_TABLE_COLUMN_ID "ID" +#define SM_CONFIGURATION_TABLE_COLUMN_KEY "KEY" +#define SM_CONFIGURATION_TABLE_COLUMN_VALUE "VALUE" + +typedef struct +{ + char key[SM_CONFIGURATION_KEY_MAX_CHAR]; + char value[SM_CONFIGURATION_VALUE_MAX_CHAR]; +} SmDbConfigurationT; + +// **************************************************************************** +// Database Configuration - Convert +// ========================================= +extern SmErrorT sm_db_configuration_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Initialize +// ============================================ +extern SmErrorT sm_db_service_domain_members_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Finalize +// ========================================== +extern SmErrorT sm_db_service_domain_members_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_CONFIGURATION_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_foreach.c b/service-mgmt/sm-db-1.0.0/src/sm_db_foreach.c new file mode 100644 index 00000000..8f14ca66 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_foreach.c @@ -0,0 +1,79 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_foreach.h" + +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" +#include "sm_db_iterator.h" + +// **************************************************************************** +// Database For-Each +// ================= +SmErrorT sm_db_foreach( const char* db_name, const char* db_table, + const char* db_query, void* record_storage, + SmDbForEachRecordConverterT record_converter, + SmDbForEachRecordCallbackT record_callback, void* user_data[] ) +{ + SmDbIteratorT it; + SmErrorT error, error2; + + error = sm_db_iterator_initialize( db_name, db_table, db_query, &it ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize iterator, error=%s.", + sm_error_str( error ) ); + return( error ); + } + + error = sm_db_iterator_first( &it ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go to first result of iterator, error=%s.", + sm_error_str( error ) ); + goto ERROR; + } + + while( !(it.done) ) + { + error = sm_db_iterator_get( &it, record_storage, record_converter ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go to get result from iterator, error=%s.", + sm_error_str( error ) ); + goto ERROR; + } + + error = record_callback( user_data, record_storage ); + if( SM_OKAY != error ) + { + DPRINTFE( "Callback failed , error=%s.", sm_error_str( error ) ); + goto ERROR; + } + + error = sm_db_iterator_next( &it ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to go to next result of iterator, error=%s.", + sm_error_str( error ) ); + goto ERROR; + } + } + + error = SM_OKAY; + +ERROR: + error2 = sm_db_iterator_finalize( &it ); + if( SM_OKAY != error2 ) + { + DPRINTFE( "Failed to finalize iterator, error=%s.", + sm_error_str( error2 ) ); + return( error ); + } + + return( error ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_foreach.h b/service-mgmt/sm-db-1.0.0/src/sm_db_foreach.h new file mode 100644 index 00000000..64188ade --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_foreach.h @@ -0,0 +1,34 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_FOREACH_H__ +#define __SM_DB_FOREACH_H__ + +#include "sm_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef SmErrorT (SmDbForEachRecordConverterT) + ( const char* col_name, const char* col_data, void* record ); + +typedef SmErrorT (*SmDbForEachRecordCallbackT) + (void* user_data[], void* record); + +// **************************************************************************** +// Database For-Each +// ================= +extern SmErrorT sm_db_foreach( const char* db_name, const char* db_table, + const char* db_query, void* record_storage, + SmDbForEachRecordConverterT record_converter, + SmDbForEachRecordCallbackT record_callback, void* user_data[] ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_FOREACH_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_iterator.c b/service-mgmt/sm-db-1.0.0/src/sm_db_iterator.c new file mode 100644 index 00000000..0e563553 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_iterator.c @@ -0,0 +1,192 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_iterator.h" + +#include +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_debug.h" +#include "sm_db.h" + +#define SM_DB_ITERATOR_VALID 0xFDFDFDFD + +// **************************************************************************** +// Database Iterator - First +// ========================= +SmErrorT sm_db_iterator_first( SmDbIteratorT* it ) +{ + if( SM_DB_ITERATOR_VALID == it->valid ) + { + SmErrorT error; + + error = sm_db_statement_result_reset( it->sm_db_statement ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to reset statement results, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + error = sm_db_statement_result_step( it->sm_db_statement, + &(it->done) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set through statement results, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); + + } else { + DPRINTFE( "Database iterator is not valid." ); + return( SM_FAILED ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Database Iterator - Get +// ======================= +SmErrorT sm_db_iterator_get( SmDbIteratorT* it, void* record, + SmDbIteratorRecordConverterT converter ) +{ + const char* col_name = NULL; + const char* col_data = NULL; + int num_cols = sqlite3_column_count( (sqlite3_stmt*) it->sm_db_statement ); + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + col_name = sqlite3_column_name( (sqlite3_stmt*) it->sm_db_statement, + col_i ); + col_data = (const char*) sqlite3_column_text( + (sqlite3_stmt*) it->sm_db_statement, col_i ); + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + error = converter( col_name, col_data, record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to convert database data to record, " + "error=%s.", sm_error_str( error ) ); + return( error ); + } + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Iterator - Next +// ======================== +SmErrorT sm_db_iterator_next( SmDbIteratorT* it ) +{ + if( SM_DB_ITERATOR_VALID == it->valid ) + { + SmErrorT error; + + error = sm_db_statement_result_step( it->sm_db_statement, + &(it->done) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to set through statement results, error=%s.", + sm_error_str( error ) ); + return( SM_FAILED ); + } + + return( SM_OKAY ); + + } else { + DPRINTFE( "Database iterator is not valid." ); + return( SM_FAILED ); + } +} +// **************************************************************************** + +// **************************************************************************** +// Database Iterator - Initialize +// ============================== +SmErrorT sm_db_iterator_initialize( const char* db_name, + const char* db_table, const char* db_query, SmDbIteratorT* it ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + SmErrorT error; + + memset( it, 0, sizeof(SmDbIteratorT) ); + + error = sm_db_connect( db_name, &(it->sm_db_handle) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to connect to database (%s), error=%s.", db_name, + sm_error_str( error ) ); + return( SM_FAILED ); + } + + if( NULL == db_query ) + { + snprintf( sql, sizeof(sql), "SELECT * FROM %s", db_table ); + } else { + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s", db_table, + db_query ); + } + + error = sm_db_statement_initialize( it->sm_db_handle, sql, + &(it->sm_db_statement) ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to initialize statement (%s), error=%s.", sql, + sm_error_str( error ) ); + sm_db_disconnect( it->sm_db_handle ); + return( SM_FAILED ); + } + + it->valid = SM_DB_ITERATOR_VALID; + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Iterator - Finalize +// ============================ +SmErrorT sm_db_iterator_finalize( SmDbIteratorT* it ) +{ + if( SM_DB_ITERATOR_VALID == it->valid ) + { + SmErrorT error; + + if( NULL != it->sm_db_statement ) + { + error = sm_db_statement_finalize( it->sm_db_statement ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to finalize statement, error=%s.", + sm_error_str( error ) ); + } + } + + if( NULL != it->sm_db_handle ) + { + error = sm_db_disconnect( it->sm_db_handle ); + if( SM_OKAY != error ) + { + DPRINTFE( "Failed to disconnect from database, error=%s.", + sm_error_str( error ) ); + } + } + + memset( it, 0, sizeof(SmDbIteratorT) ); + } + + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_iterator.h b/service-mgmt/sm-db-1.0.0/src/sm_db_iterator.h new file mode 100644 index 00000000..c47fb5b0 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_iterator.h @@ -0,0 +1,67 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_ITERATOR_H__ +#define __SM_DB_ITERATOR_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct +{ + uint32_t valid; + bool done; + SmDbHandleT* sm_db_handle; + SmDbStatementT* sm_db_statement; +} SmDbIteratorT; + +typedef SmErrorT (SmDbIteratorRecordConverterT) ( const char* col_name, + const char* col_data, + void* record ); + +// **************************************************************************** +// Database Iterator - First +// ========================= +extern SmErrorT sm_db_iterator_first( SmDbIteratorT* it ); +// **************************************************************************** + +// **************************************************************************** +// Database Iterator - Get +// ======================= +extern SmErrorT sm_db_iterator_get( SmDbIteratorT* it, void* record, + SmDbIteratorRecordConverterT converter ); +// **************************************************************************** + +// **************************************************************************** +// Database Iterator - Next +// ======================== +extern SmErrorT sm_db_iterator_next( SmDbIteratorT* it ); +// **************************************************************************** + +// **************************************************************************** +// Database Iterator - Initialize +// ============================== +extern SmErrorT sm_db_iterator_initialize( const char* db_name, + const char* db_table, const char* db_query, SmDbIteratorT* it ); +// **************************************************************************** + +// **************************************************************************** +// Database Iterator - Finalize +// ============================ +extern SmErrorT sm_db_iterator_finalize( SmDbIteratorT* it ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_ITERATOR_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_node_history.c b/service-mgmt/sm-db-1.0.0/src/sm_db_node_history.c new file mode 100644 index 00000000..053a9d3c --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_node_history.c @@ -0,0 +1,328 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_node_history.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Node History - Convert +// =============================== +SmErrorT sm_db_node_history_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbNodeHistoryT* record = (SmDbNodeHistoryT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_NODE_HISTORY_TABLE_COLUMN_ID, col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_NODE_HISTORY_TABLE_COLUMN_NAME, col_name ) ) + { + snprintf( record->name, sizeof(record->name), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_NODE_HISTORY_TABLE_COLUMN_ADMIN_STATE, col_name ) ) + { + record->admin_state = sm_node_admin_state_value( col_data ); + } + else if( 0 == strcmp( SM_NODE_HISTORY_TABLE_COLUMN_OPER_STATE, col_name ) ) + { + record->oper_state = sm_node_oper_state_value( col_data ); + } + else if( 0 == strcmp( SM_NODE_HISTORY_TABLE_COLUMN_AVAIL_STATUS, col_name ) ) + { + record->avail_status = sm_node_avail_status_value( col_data ); + } + else if( 0 == strcmp( SM_NODE_HISTORY_TABLE_COLUMN_READY_STATE, col_name ) ) + { + record->ready_state = sm_node_ready_state_value( col_data ); + } + else if( 0 == strcmp( SM_NODE_HISTORY_TABLE_COLUMN_STATE_UUID, col_name ) ) + { + snprintf( record->state_uuid, sizeof(record->state_uuid), "%s", + col_data ? col_data : "" ); + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Read Callback +// ===================================== +static int sm_db_node_history_read_callback( void* user_data, int num_cols, + char **col_data, char **col_name ) +{ + SmDbNodeHistoryT* record = (SmDbNodeHistoryT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_node_history_convert( col_name[col_i], col_data[col_i], + record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Read +// ============================ +SmErrorT sm_db_node_history_read( SmDbHandleT* sm_db_handle, char name[], + SmDbNodeHistoryT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbNodeHistoryT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s';", + SM_NODE_HISTORY_TABLE_NAME, + SM_NODE_HISTORY_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_node_history_read_callback, record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Query +// ============================= +SmErrorT sm_db_node_history_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbNodeHistoryT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbNodeHistoryT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_NODE_HISTORY_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_node_history_read_callback, record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Insert +// ============================== +SmErrorT sm_db_node_history_insert( SmDbHandleT* sm_db_handle, + SmDbNodeHistoryT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s');", + SM_NODE_HISTORY_TABLE_NAME, + SM_NODE_HISTORY_TABLE_COLUMN_NAME, + SM_NODE_HISTORY_TABLE_COLUMN_ADMIN_STATE, + SM_NODE_HISTORY_TABLE_COLUMN_OPER_STATE, + SM_NODE_HISTORY_TABLE_COLUMN_AVAIL_STATUS, + SM_NODE_HISTORY_TABLE_COLUMN_READY_STATE, + SM_NODE_HISTORY_TABLE_COLUMN_STATE_UUID, + record->name, + sm_node_admin_state_str( record->admin_state ), + sm_node_oper_state_str( record->oper_state ), + sm_node_avail_status_str( record->avail_status ), + sm_node_ready_state_str( record->ready_state ), + record->state_uuid + ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Delete +// ============================== +SmErrorT sm_db_node_history_delete( SmDbHandleT* sm_db_handle, char name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s';", + SM_NODE_HISTORY_TABLE_NAME, + SM_NODE_HISTORY_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Create Table +// ==================================== +SmErrorT sm_db_node_history_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i));", + SM_NODE_HISTORY_TABLE_NAME, + SM_NODE_HISTORY_TABLE_COLUMN_ID, + SM_NODE_HISTORY_TABLE_COLUMN_NAME, + SM_NODE_NAME_MAX_CHAR, + SM_NODE_HISTORY_TABLE_COLUMN_ADMIN_STATE, + SM_NODE_ADMIN_STATE_MAX_CHAR, + SM_NODE_HISTORY_TABLE_COLUMN_OPER_STATE, + SM_NODE_OPERATIONAL_STATE_MAX_CHAR, + SM_NODE_HISTORY_TABLE_COLUMN_AVAIL_STATUS, + SM_NODE_AVAIL_STATUS_MAX_CHAR, + SM_NODE_HISTORY_TABLE_COLUMN_READY_STATE, + SM_NODE_READY_STATE_MAX_CHAR, + SM_NODE_HISTORY_TABLE_COLUMN_STATE_UUID, + SM_UUID_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Delete Table +// ==================================== +SmErrorT sm_db_node_history_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_NODE_HISTORY_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Initialize +// ================================== +SmErrorT sm_db_node_history_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Finalize +// ================================ +SmErrorT sm_db_node_history_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_node_history.h b/service-mgmt/sm-db-1.0.0/src/sm_db_node_history.h new file mode 100644 index 00000000..1991ae98 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_node_history.h @@ -0,0 +1,104 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_NODE_HISTORY_H__ +#define __SM_DB_NODE_HISTORY_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_uuid.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_NODE_HISTORY_TABLE_NAME "NODE_HISTORY" +#define SM_NODE_HISTORY_TABLE_COLUMN_ID "ID" +#define SM_NODE_HISTORY_TABLE_COLUMN_NAME "NAME" +#define SM_NODE_HISTORY_TABLE_COLUMN_ADMIN_STATE "ADMINISTRATIVE_STATE" +#define SM_NODE_HISTORY_TABLE_COLUMN_OPER_STATE "OPERATIONAL_STATE" +#define SM_NODE_HISTORY_TABLE_COLUMN_AVAIL_STATUS "AVAILABILITY_STATUS" +#define SM_NODE_HISTORY_TABLE_COLUMN_READY_STATE "READY_STATE" +#define SM_NODE_HISTORY_TABLE_COLUMN_STATE_UUID "STATE_UUID" + +typedef struct +{ + int64_t id; + char name[SM_NODE_NAME_MAX_CHAR]; + SmNodeAdminStateT admin_state; + SmNodeOperationalStateT oper_state; + SmNodeAvailStatusT avail_status; + SmNodeReadyStateT ready_state; + SmUuidT state_uuid; +} SmDbNodeHistoryT; + +// **************************************************************************** +// Database Node History - Convert +// =============================== +extern SmErrorT sm_db_node_history_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Read +// ============================ +extern SmErrorT sm_db_node_history_read( SmDbHandleT* sm_db_handle, + char name[], SmDbNodeHistoryT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Query +// ============================= +extern SmErrorT sm_db_node_history_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbNodeHistoryT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Insert +// ============================== +extern SmErrorT sm_db_node_history_insert( SmDbHandleT* sm_db_handle, + SmDbNodeHistoryT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Delete +// ============================== +extern SmErrorT sm_db_node_history_delete( SmDbHandleT* sm_db_handle, + char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Create Table +// ==================================== +extern SmErrorT sm_db_node_history_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Delete Table +// ==================================== +extern SmErrorT sm_db_node_history_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Initialize +// ================================== +extern SmErrorT sm_db_node_history_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Node History - Finalize +// ================================ +extern SmErrorT sm_db_node_history_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_NODE_HISTORY_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_nodes.c b/service-mgmt/sm-db-1.0.0/src/sm_db_nodes.c new file mode 100644 index 00000000..487eabef --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_nodes.c @@ -0,0 +1,437 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_nodes.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_uuid.h" +#include "sm_db.h" +#include "sm_node_utils.h" + +// **************************************************************************** +// Database Nodes - Convert +// ======================== +SmErrorT sm_db_nodes_convert( const char* col_name, const char* col_data, + void* data ) +{ + SmDbNodeT* record = (SmDbNodeT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_NODES_TABLE_COLUMN_ID, col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_NODES_TABLE_COLUMN_NAME, col_name ) ) + { + snprintf( record->name, sizeof(record->name), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_NODES_TABLE_COLUMN_ADMIN_STATE, col_name ) ) + { + record->admin_state = sm_node_admin_state_value( col_data ); + } + else if( 0 == strcmp( SM_NODES_TABLE_COLUMN_OPER_STATE, col_name ) ) + { + record->oper_state = sm_node_oper_state_value( col_data ); + } + else if( 0 == strcmp( SM_NODES_TABLE_COLUMN_AVAIL_STATUS, col_name ) ) + { + record->avail_status = sm_node_avail_status_value( col_data ); + } + else if( 0 == strcmp( SM_NODES_TABLE_COLUMN_READY_STATE, col_name ) ) + { + record->ready_state = sm_node_ready_state_value( col_data ); + } + else if( 0 == strcmp( SM_NODES_TABLE_COLUMN_STATE_UUID, col_name ) ) + { + snprintf( record->state_uuid, sizeof(record->state_uuid), "%s", + col_data ? col_data : "" ); + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Read Callback +// ============================== +static int sm_db_nodes_read_callback( void* user_data, int num_cols, + char **col_data, char **col_name ) +{ + SmDbNodeT* record = (SmDbNodeT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_nodes_convert( col_name[col_i], col_data[col_i], + record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Read +// ===================== +SmErrorT sm_db_nodes_read( SmDbHandleT* sm_db_handle, char name[], + SmDbNodeT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbNodeT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s';", + SM_NODES_TABLE_NAME, + SM_NODES_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_nodes_read_callback, record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Query +// ====================== +SmErrorT sm_db_nodes_query( SmDbHandleT* sm_db_handle, const char* db_query, + SmDbNodeT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbNodeT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_NODES_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_nodes_read_callback, record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Insert +// ======================= +SmErrorT sm_db_nodes_insert( SmDbHandleT* sm_db_handle, SmDbNodeT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s');", + SM_NODES_TABLE_NAME, + SM_NODES_TABLE_COLUMN_NAME, + SM_NODES_TABLE_COLUMN_ADMIN_STATE, + SM_NODES_TABLE_COLUMN_OPER_STATE, + SM_NODES_TABLE_COLUMN_AVAIL_STATUS, + SM_NODES_TABLE_COLUMN_READY_STATE, + SM_NODES_TABLE_COLUMN_STATE_UUID, + record->name, + sm_node_admin_state_str( record->admin_state ), + sm_node_oper_state_str( record->oper_state ), + sm_node_avail_status_str( record->avail_status ), + sm_node_ready_state_str( record->ready_state ), + record->state_uuid + ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Update +// ======================= +SmErrorT sm_db_nodes_update( SmDbHandleT* sm_db_handle, SmDbNodeT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_NODES_TABLE_NAME); + + if( SM_NODE_ADMIN_STATE_NIL != record->admin_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_NODES_TABLE_COLUMN_ADMIN_STATE, + sm_node_admin_state_str(record->admin_state) ); + } + + if( SM_NODE_OPERATIONAL_STATE_NIL != record->oper_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_NODES_TABLE_COLUMN_OPER_STATE, + sm_node_oper_state_str(record->oper_state) ); + } + + if( SM_NODE_AVAIL_STATUS_NIL != record->avail_status ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_NODES_TABLE_COLUMN_AVAIL_STATUS, + sm_node_avail_status_str(record->avail_status) ); + } + + if( SM_NODE_READY_STATE_NIL != record->ready_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_NODES_TABLE_COLUMN_READY_STATE, + sm_node_ready_state_str(record->ready_state) ); + } + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_NODES_TABLE_COLUMN_STATE_UUID, + record->state_uuid ); + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s';", + SM_NODES_TABLE_COLUMN_NAME, record->name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Delete +// ======================= +SmErrorT sm_db_nodes_delete( SmDbHandleT* sm_db_handle, char name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s';", + SM_NODES_TABLE_NAME, + SM_NODES_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Create Table +// ============================= +SmErrorT sm_db_nodes_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i));", + SM_NODES_TABLE_NAME, + SM_NODES_TABLE_COLUMN_ID, + SM_NODES_TABLE_COLUMN_NAME, + SM_NODE_NAME_MAX_CHAR, + SM_NODES_TABLE_COLUMN_ADMIN_STATE, + SM_NODE_ADMIN_STATE_MAX_CHAR, + SM_NODES_TABLE_COLUMN_OPER_STATE, + SM_NODE_OPERATIONAL_STATE_MAX_CHAR, + SM_NODES_TABLE_COLUMN_AVAIL_STATUS, + SM_NODE_AVAIL_STATUS_MAX_CHAR, + SM_NODES_TABLE_COLUMN_READY_STATE, + SM_NODE_READY_STATE_MAX_CHAR, + SM_NODES_TABLE_COLUMN_STATE_UUID, + SM_UUID_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Delete Table +// ============================= +SmErrorT sm_db_nodes_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_NODES_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Cleanup Table +// ============================== +SmErrorT sm_db_nodes_cleanup_table( SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + char hostname[SM_NODE_NAME_MAX_CHAR]; + int rc; + SmErrorT sm_error; + + sm_error = sm_node_utils_get_hostname( hostname ); + if( SM_OKAY != sm_error ) + { + DPRINTFE( "Failed to get hostname, error=%s.", + sm_error_str( sm_error ) ); + return( sm_error ); + } + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_NODES_TABLE_NAME); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_NODES_TABLE_COLUMN_READY_STATE, + sm_node_ready_state_str(SM_NODE_READY_STATE_DISABLED) ); + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s';", + SM_NODES_TABLE_COLUMN_NAME, hostname ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Initialize +// =========================== +SmErrorT sm_db_nodes_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Finalize +// ========================= +SmErrorT sm_db_nodes_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_nodes.h b/service-mgmt/sm-db-1.0.0/src/sm_db_nodes.h new file mode 100644 index 00000000..d9bb7746 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_nodes.h @@ -0,0 +1,116 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_NODES_H__ +#define __SM_DB_NODES_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_uuid.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_NODES_TABLE_NAME "NODES" +#define SM_NODES_TABLE_COLUMN_ID "ID" +#define SM_NODES_TABLE_COLUMN_NAME "NAME" +#define SM_NODES_TABLE_COLUMN_ADMIN_STATE "ADMINISTRATIVE_STATE" +#define SM_NODES_TABLE_COLUMN_OPER_STATE "OPERATIONAL_STATE" +#define SM_NODES_TABLE_COLUMN_AVAIL_STATUS "AVAILABILITY_STATUS" +#define SM_NODES_TABLE_COLUMN_READY_STATE "READY_STATE" +#define SM_NODES_TABLE_COLUMN_STATE_UUID "STATE_UUID" + +typedef struct +{ + int64_t id; + char name[SM_NODE_NAME_MAX_CHAR]; + SmNodeAdminStateT admin_state; + SmNodeOperationalStateT oper_state; + SmNodeAvailStatusT avail_status; + SmNodeReadyStateT ready_state; + SmUuidT state_uuid; +} SmDbNodeT; + +// **************************************************************************** +// Database Nodes - Convert +// ======================== +extern SmErrorT sm_db_nodes_convert( const char* col_name, const char* col_data, + void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Read +// ===================== +extern SmErrorT sm_db_nodes_read( SmDbHandleT* sm_db_handle, char name[], + SmDbNodeT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Query +// ====================== +extern SmErrorT sm_db_nodes_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbNodeT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Insert +// ======================= +extern SmErrorT sm_db_nodes_insert( SmDbHandleT* sm_db_handle, + SmDbNodeT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Update +// ======================= +extern SmErrorT sm_db_nodes_update( SmDbHandleT* sm_db_handle, + SmDbNodeT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Delete +// ======================= +extern SmErrorT sm_db_nodes_delete( SmDbHandleT* sm_db_handle, char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Create Table +// ============================= +extern SmErrorT sm_db_nodes_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Delete Table +// ============================= +extern SmErrorT sm_db_nodes_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Cleanup Table +// ============================== +extern SmErrorT sm_db_nodes_cleanup_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Initialize +// =========================== +extern SmErrorT sm_db_nodes_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Nodes - Finalize +// ========================= +extern SmErrorT sm_db_nodes_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_NODES_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_action_results.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_action_results.c new file mode 100644 index 00000000..afd22ffb --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_action_results.c @@ -0,0 +1,408 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_action_results.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Action Results - Convert +// ========================================= +SmErrorT sm_db_service_action_results_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceActionResultT* record; + + record = (SmDbServiceActionResultT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_TYPE, + col_name ) ) + { + snprintf( record->plugin_type, sizeof(record->plugin_type), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_NAME, + col_name ) ) + { + snprintf( record->plugin_name, sizeof(record->plugin_name), + "%s", col_data ? col_data : "" ); + + } + else if( 0 == strcmp( SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_COMMAND, + col_name ) ) + { + snprintf( record->plugin_command, sizeof(record->plugin_command), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_EXIT_CODE, + col_name ) ) + { + snprintf( record->plugin_exit_code, sizeof(record->plugin_exit_code), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_ACTION_RESULT, + col_name ) ) + { + record->action_result = sm_service_action_result_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATE, + col_name ) ) + { + record->service_state = sm_service_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATUS, + col_name ) ) + { + record->service_status = sm_service_status_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_CONDITION, + col_name ) ) + { + record->service_condition = sm_service_condition_value( col_data ); + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Read Callback +// =============================================== +static int sm_db_service_action_results_read_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + SmDbServiceActionResultT* record; + SmErrorT error; + + record = (SmDbServiceActionResultT*) user_data; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_action_results_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Read +// ====================================== +SmErrorT sm_db_service_action_results_read( SmDbHandleT* sm_db_handle, + char plugin_type[], char plugin_name[], char plugin_command[], + char plugin_exit_code[], SmDbServiceActionResultT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceActionResultT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s " + "WHERE %s = '%s' and %s = '%s' and %s = '%s' and %s = '%s';", + SM_SERVICE_ACTION_RESULTS_TABLE_NAME, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_TYPE, + plugin_type, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_NAME, + plugin_name, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_COMMAND, + plugin_command, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_EXIT_CODE, + plugin_exit_code ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_action_results_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( plugin_type, record->plugin_type ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Insert +// ======================================== +SmErrorT sm_db_service_action_results_insert( SmDbHandleT* sm_db_handle, + SmDbServiceActionResultT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( " + "%s, %s, %s, %s, %s, %s %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' );", + SM_SERVICE_ACTION_RESULTS_TABLE_NAME, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_TYPE, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_NAME, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_COMMAND, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_EXIT_CODE, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_ACTION_RESULT, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATE, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATUS, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_CONDITION, + record->plugin_type, record->plugin_name, + record->plugin_command, record->plugin_exit_code, + sm_service_action_result_str( record->action_result ), + sm_service_state_str( record->service_state ), + sm_service_status_str( record->service_status ), + sm_service_condition_str( record->service_condition ) ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Update +// ======================================== +SmErrorT sm_db_service_action_results_update( SmDbHandleT* sm_db_handle, + SmDbServiceActionResultT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_ACTION_RESULTS_TABLE_NAME ); + + if( SM_SERVICE_ACTION_RESULT_NIL != record->action_result ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_ACTION_RESULT, + sm_service_action_result_str( record->action_result ) ); + } + + if( SM_SERVICE_STATE_NIL != record->service_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATE, + sm_service_state_str( record->service_state ) ); + } + + if( SM_SERVICE_STATUS_NIL != record->service_status ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATUS, + sm_service_status_str( record->service_status ) ); + } + + if( SM_SERVICE_CONDITION_NIL != record->service_condition ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_CONDITION, + sm_service_condition_str( record->service_condition ) ); + } + + snprintf( sql+len-2, sizeof(sql)-len, + " WHERE %s = '%s' %s = '%s' and %s = '%s' and %s = '%s';", + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_TYPE, + record->plugin_type, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_NAME, + record->plugin_name, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_COMMAND, + record->plugin_command, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_EXIT_CODE, + record->plugin_exit_code ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Delete +// ======================================== +SmErrorT sm_db_service_action_results_delete( SmDbHandleT* sm_db_handle, + char plugin_type[], char plugin_name[], char plugin_command[], + char plugin_exit_code[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s " + "WHERE %s = '%s' and %s = '%s' and %s = '%s' and %s = '%s';", + SM_SERVICE_ACTION_RESULTS_TABLE_NAME, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_TYPE, + plugin_type, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_NAME, + plugin_name, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_COMMAND, + plugin_command, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_EXIT_CODE, + plugin_exit_code ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Create Table +// ============================================== +SmErrorT sm_db_service_action_results_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "PRIMARY KEY (%s, %s, %s, %s));", + SM_SERVICE_ACTION_RESULTS_TABLE_NAME, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_TYPE, + SM_SERVICE_ACTION_PLUGIN_TYPE_MAX_CHAR, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_NAME, + SM_SERVICE_ACTION_PLUGIN_NAME_MAX_CHAR, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_COMMAND, + SM_SERVICE_ACTION_PLUGIN_COMMAND_MAX_CHAR, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_EXIT_CODE, + SM_SERVICE_ACTION_PLUGIN_EXIT_CODE_MAX_CHAR, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_ACTION_RESULT, + SM_SERVICE_ACTION_RESULT_MAX_CHAR, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATE, + SM_SERVICE_STATE_MAX_CHAR, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATUS, + SM_SERVICE_STATUS_MAX_CHAR, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_CONDITION, + SM_SERVICE_CONDITION_MAX_CHAR, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_TYPE, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_NAME, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_COMMAND, + SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_EXIT_CODE ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Delete Table +// ============================================== +SmErrorT sm_db_service_action_results_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_ACTION_RESULTS_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Initialize +// ============================================ +SmErrorT sm_db_service_action_results_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Finalize +// ========================================== +SmErrorT sm_db_service_action_results_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_action_results.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_action_results.h new file mode 100644 index 00000000..8e20c049 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_action_results.h @@ -0,0 +1,106 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_ACTION_RESULTS_H__ +#define __SM_DB_SERVICE_ACTION_RESULTS_H__ + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_ACTION_RESULTS_TABLE_NAME "SERVICE_ACTION_RESULTS" +#define SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_TYPE "PLUGIN_TYPE" +#define SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_NAME "PLUGIN_NAME" +#define SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_COMMAND "PLUGIN_COMMAND" +#define SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_PLUGIN_EXIT_CODE "PLUGIN_EXIT_CODE" +#define SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_ACTION_RESULT "ACTION_RESULT" +#define SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATE "SERVICE_STATE" +#define SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_STATUS "SERVICE_STATUS" +#define SM_SERVICE_ACTION_RESULTS_TABLE_COLUMN_SERVICE_CONDITION "SERVICE_CONDITION" + +typedef struct +{ + char plugin_type[SM_SERVICE_ACTION_PLUGIN_TYPE_MAX_CHAR]; + char plugin_name[SM_SERVICE_ACTION_PLUGIN_NAME_MAX_CHAR]; + char plugin_command[SM_SERVICE_ACTION_PLUGIN_COMMAND_MAX_CHAR]; + char plugin_exit_code[SM_SERVICE_ACTION_PLUGIN_EXIT_CODE_MAX_CHAR]; + SmServiceActionResultT action_result; + SmServiceStateT service_state; + SmServiceStatusT service_status; + SmServiceConditionT service_condition; +} SmDbServiceActionResultT; + +// **************************************************************************** +// Database Service Action Results - Convert +// ========================================= +extern SmErrorT sm_db_service_action_results_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Read +// ====================================== +extern SmErrorT sm_db_service_action_results_read( SmDbHandleT* sm_db_handle, + char plugin_type[], char plugin_name[], char plugin_command[], + char plugin_exit_code[], SmDbServiceActionResultT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Insert +// ======================================== +extern SmErrorT sm_db_service_action_results_insert( SmDbHandleT* sm_db_handle, + SmDbServiceActionResultT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Update +// ======================================== +extern SmErrorT sm_db_service_results_update( SmDbHandleT* sm_db_handle, + SmDbServiceActionResultT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Delete +// ======================================== +extern SmErrorT sm_db_service_action_results_delete( SmDbHandleT* sm_db_handle, + char plugin_type[], char plugin_name[], char plugin_command[], + char plugin_exit_code[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Create Table +// ============================================== +extern SmErrorT sm_db_service_action_results_create_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Delete Table +// ============================================== +extern SmErrorT sm_db_service_action_results_delete_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Initialize +// ============================================ +extern SmErrorT sm_db_service_action_results_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Action Results - Finalize +// ========================================== +extern SmErrorT sm_db_service_action_results_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_ACTION_RESULTS_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_actions.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_actions.c new file mode 100644 index 00000000..fd97d207 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_actions.c @@ -0,0 +1,476 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_actions.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Actions - Convert +// ================================== +SmErrorT sm_db_service_actions_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceActionT* record = (SmDbServiceActionT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_SERVICE_NAME, col_name ) ) + { + snprintf( record->service_name, sizeof(record->service_name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_ACTION, + col_name ) ) + { + record->action = sm_service_action_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_TYPE, + col_name ) ) + { + int max_plugin_type_str_len = sizeof(record->plugin_type)-1; + int char_i = 0; + + if( NULL != col_data ) + { + for( ; '\0' != col_data[char_i]; ++char_i ) + { + if( max_plugin_type_str_len < char_i ) + { + break; + } + + record->plugin_type[char_i] = tolower( col_data[char_i] ); + } + } + + record->plugin_type[char_i] = '\0'; + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_CLASS, + col_name ) ) + { + snprintf( record->plugin_class, sizeof(record->plugin_class), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_NAME, + col_name ) ) + { + snprintf( record->plugin_name, sizeof(record->plugin_name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_COMMAND, + col_name ) ) + { + snprintf( record->plugin_command, sizeof(record->plugin_command), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_PARAMETERS, + col_name ) ) + { + snprintf( record->plugin_params, sizeof(record->plugin_params), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_FAILURE_RETRIES, + col_name ) ) + { + record->max_failure_retries = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TIMEOUT_RETRIES, + col_name ) ) + { + record->max_timeout_retries = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TOTAL_RETRIES, + col_name ) ) + { + record->max_total_retries = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_TIMEOUT_IN_SECS, + col_name ) ) + { + record->timeout_in_secs = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_ACTIONS_TABLE_COLUMN_INTERVAL_IN_SECS, + col_name ) ) + { + record->interval_in_secs = col_data ? atoi(col_data) : 0; + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Read Callback +// ======================================== +static int sm_db_service_actions_read_callback( void* user_data, int num_cols, + char **col_data, char **col_name ) +{ + SmDbServiceActionT* record = (SmDbServiceActionT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_actions_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Read +// =============================== +SmErrorT sm_db_service_actions_read( SmDbHandleT* sm_db_handle, + char service_name[], SmServiceActionT action, SmDbServiceActionT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceActionT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s " + "WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_ACTIONS_TABLE_NAME, + SM_SERVICE_ACTIONS_TABLE_COLUMN_SERVICE_NAME, + service_name, + SM_SERVICE_ACTIONS_TABLE_COLUMN_ACTION, + sm_service_action_str( action ) ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_actions_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( service_name, record->service_name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Insert +// ================================= +SmErrorT sm_db_service_actions_insert( SmDbHandleT* sm_db_handle, + SmDbServiceActionT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( " + "%s, %s, %s, %s, %s, %s, %s, %s, %s, %s , %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', " + "'%s', %i, %i, %i, %i, %i);", + SM_SERVICE_ACTIONS_TABLE_NAME, + SM_SERVICE_ACTIONS_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_ACTIONS_TABLE_COLUMN_ACTION, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_TYPE, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_CLASS, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_NAME, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_COMMAND, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_PARAMETERS, + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_FAILURE_RETRIES, + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TIMEOUT_RETRIES, + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TOTAL_RETRIES, + SM_SERVICE_ACTIONS_TABLE_COLUMN_TIMEOUT_IN_SECS, + SM_SERVICE_ACTIONS_TABLE_COLUMN_INTERVAL_IN_SECS, + record->service_name, + sm_service_action_str( record->action ), + record->plugin_type, record->plugin_class, + record->plugin_name, record->plugin_command, + record->plugin_params, record->max_failure_retries, + record->max_timeout_retries, record->max_total_retries, + record->timeout_in_secs, record->interval_in_secs ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Update +// ================================= +SmErrorT sm_db_service_actions_update( SmDbHandleT* sm_db_handle, + SmDbServiceActionT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_ACTIONS_TABLE_NAME ); + + if( 0 < strlen( record->plugin_type ) ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_TYPE, + record->plugin_type ); + } + + if( 0 < strlen( record->plugin_class ) ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_CLASS, + record->plugin_class ); + } + + if( 0 < strlen( record->plugin_name ) ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_NAME, + record->plugin_name ); + } + + if( 0 < strlen( record->plugin_command ) ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_COMMAND, + record->plugin_command ); + } + + if( 0 < strlen( record->plugin_params ) ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_PARAMETERS, + record->plugin_params ); + } + + if( 0 <= record->max_failure_retries ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_FAILURE_RETRIES, + record->max_failure_retries ); + } + + if( 0 <= record->max_timeout_retries ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TIMEOUT_RETRIES, + record->max_timeout_retries ); + } + + if( 0 <= record->max_total_retries ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TOTAL_RETRIES, + record->max_total_retries ); + } + + if( 0 <= record->timeout_in_secs ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_TIMEOUT_IN_SECS, + record->timeout_in_secs ); + } + + if( 0 <= record->interval_in_secs ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_ACTIONS_TABLE_COLUMN_INTERVAL_IN_SECS, + record->interval_in_secs ); + } + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_ACTIONS_TABLE_COLUMN_SERVICE_NAME, + record->service_name, + SM_SERVICE_ACTIONS_TABLE_COLUMN_ACTION, + sm_service_action_str( record->action ) ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Delete +// ================================= +SmErrorT sm_db_service_actions_delete( SmDbHandleT* sm_db_handle, + char service_name[], SmServiceActionT action ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s' and " + "%s = '%s';", SM_SERVICE_ACTIONS_TABLE_NAME, + SM_SERVICE_ACTIONS_TABLE_COLUMN_SERVICE_NAME, service_name, + SM_SERVICE_ACTIONS_TABLE_COLUMN_ACTION, + sm_service_action_str( action ) ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Create Table +// ======================================= +SmErrorT sm_db_service_actions_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "PRIMARY KEY (%s, %s));", + SM_SERVICE_ACTIONS_TABLE_NAME, + SM_SERVICE_ACTIONS_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_NAME_MAX_CHAR, + SM_SERVICE_ACTIONS_TABLE_COLUMN_ACTION, + SM_SERVICE_ACTION_NAME_MAX_CHAR, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_TYPE, + SM_SERVICE_ACTION_PLUGIN_TYPE_MAX_CHAR, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_CLASS, + SM_SERVICE_ACTION_PLUGIN_CLASS_MAX_CHAR, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_NAME, + SM_SERVICE_ACTION_PLUGIN_NAME_MAX_CHAR, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_COMMAND, + SM_SERVICE_ACTION_PLUGIN_COMMAND_MAX_CHAR, + SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_PARAMETERS, + SM_SERVICE_ACTION_PLUGIN_PARAMS_MAX_CHAR, + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_FAILURE_RETRIES, + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TIMEOUT_RETRIES, + SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TOTAL_RETRIES, + SM_SERVICE_ACTIONS_TABLE_COLUMN_TIMEOUT_IN_SECS, + SM_SERVICE_ACTIONS_TABLE_COLUMN_INTERVAL_IN_SECS, + SM_SERVICE_ACTIONS_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_ACTIONS_TABLE_COLUMN_ACTION ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Delete Table +// ======================================= +SmErrorT sm_db_service_actions_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_ACTIONS_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Initialize +// ===================================== +SmErrorT sm_db_service_actions_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Finalize +// =================================== +SmErrorT sm_db_service_actions_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_actions.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_actions.h new file mode 100644 index 00000000..6f00acfc --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_actions.h @@ -0,0 +1,110 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_ACTIONS_H__ +#define __SM_DB_SERVICE_ACTIONS_H__ + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_ACTIONS_TABLE_NAME "SERVICE_ACTIONS" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_SERVICE_NAME "SERVICE_NAME" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_ACTION "ACTION" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_TYPE "PLUGIN_TYPE" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_CLASS "PLUGIN_CLASS" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_NAME "PLUGIN_NAME" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_COMMAND "PLUGIN_COMMAND" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_PLUGIN_PARAMETERS "PLUGIN_PARAMETERS" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_FAILURE_RETRIES "MAX_FAILURE_RETRIES" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TIMEOUT_RETRIES "MAX_TIMEOUT_RETRIES" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_MAX_TOTAL_RETRIES "MAX_TOTAL_RETRIES" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_TIMEOUT_IN_SECS "TIMEOUT_IN_SECS" +#define SM_SERVICE_ACTIONS_TABLE_COLUMN_INTERVAL_IN_SECS "INTERVAL_IN_SECS" + +typedef struct +{ + char service_name[SM_SERVICE_NAME_MAX_CHAR]; + SmServiceActionT action; + char plugin_type[SM_SERVICE_ACTION_PLUGIN_TYPE_MAX_CHAR]; + char plugin_class[SM_SERVICE_ACTION_PLUGIN_CLASS_MAX_CHAR]; + char plugin_name[SM_SERVICE_ACTION_PLUGIN_NAME_MAX_CHAR]; + char plugin_command[SM_SERVICE_ACTION_PLUGIN_COMMAND_MAX_CHAR]; + char plugin_params[SM_SERVICE_ACTION_PLUGIN_PARAMS_MAX_CHAR]; + int max_failure_retries; + int max_timeout_retries; + int max_total_retries; + int timeout_in_secs; + int interval_in_secs; +} SmDbServiceActionT; + +// **************************************************************************** +// Database Service Actions - Convert +// ================================== +extern SmErrorT sm_db_service_actions_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Read +// =============================== +extern SmErrorT sm_db_service_actions_read( SmDbHandleT* sm_db_handle, + char service_name[], SmServiceActionT action, SmDbServiceActionT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Insert +// ================================= +extern SmErrorT sm_db_service_actions_insert( SmDbHandleT* sm_db_handle, + SmDbServiceActionT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Update +// ================================= +extern SmErrorT sm_db_service_actions_update( SmDbHandleT* sm_db_handle, + SmDbServiceActionT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Delete +// ================================= +extern SmErrorT sm_db_service_actions_delete( SmDbHandleT* sm_db_handle, + char service_name[], SmServiceActionT action ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Create Table +// ======================================= +extern SmErrorT sm_db_service_actions_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Delete Table +// ======================================= +extern SmErrorT sm_db_service_actions_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Initialize +// ===================================== +extern SmErrorT sm_db_service_actions_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Actions - Finalize +// =================================== +extern SmErrorT sm_db_service_actions_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_ACTIONS_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_dependency.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_dependency.c new file mode 100644 index 00000000..e153eeea --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_dependency.c @@ -0,0 +1,380 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_dependency.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Dependency - Convert +// ===================================== +SmErrorT sm_db_service_dependency_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceDependencyT* record = (SmDbServiceDependencyT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENCY_TYPE, + col_name ) ) + { + record->type = sm_service_dependency_type_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DEPENDENCY_TABLE_COLUMN_SERVICE_NAME, + col_name ) ) + { + snprintf( record->service_name, sizeof(record->service_name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DEPENDENCY_TABLE_COLUMN_STATE, + col_name ) ) + { + if( col_data ) + { + record->state = sm_service_state_value( col_data ); + } else { + record->state = SM_SERVICE_STATE_NIL; + } + } + else if( 0 == strcmp( SM_SERVICE_DEPENDENCY_TABLE_COLUMN_ACTION, + col_name ) ) + { + if( col_data ) + { + record->action = sm_service_action_value( col_data ); + } else { + record->action = SM_SERVICE_ACTION_NIL; + } + } + else if( 0 == strcmp( SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT, + col_name ) ) + { + snprintf( record->dependent, sizeof(record->dependent), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT_STATE, + col_name ) ) + { + record->dependent_state = sm_service_state_value( col_data ); + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Read Callback +// =========================================== +static int sm_db_service_dependency_read_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + SmDbServiceDependencyT* record = (SmDbServiceDependencyT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_dependency_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Read +// ================================== +SmErrorT sm_db_service_dependency_read( SmDbHandleT* sm_db_handle, + SmServiceDependencyTypeT type, char service_name[], SmServiceStateT state, + SmServiceActionT action, char dependent[], SmDbServiceDependencyT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDependencyT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s' " + "and %s = '%s' and %s = '%s' and %s = '%s' and %s = '%s';", + SM_SERVICE_DEPENDENCY_TABLE_NAME, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENCY_TYPE, + sm_service_dependency_type_str( type ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_SERVICE_NAME, + service_name, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_STATE, + sm_service_state_str( state ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_ACTION, + sm_service_action_str( action ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT, + dependent ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_dependency_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( type != record->type ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Insert +// ==================================== +SmErrorT sm_db_service_dependency_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDependencyT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( " + "%s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', %s );", + SM_SERVICE_DEPENDENCY_TABLE_NAME, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENCY_TYPE, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_STATE, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_ACTION, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT_STATE, + sm_service_dependency_type_str( record->type ), + record->service_name, + sm_service_state_str( record->state ), + sm_service_action_str( record->action ), + record->dependent, + sm_service_state_str( record->dependent_state ) ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Update +// ==================================== +SmErrorT sm_db_service_dependency_update( SmDbHandleT* sm_db_handle, + SmDbServiceDependencyT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DEPENDENCY_TABLE_NAME ); + + if( SM_SERVICE_STATE_NIL != record->dependent_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT_STATE, + sm_service_state_str( record->dependent_state ) ); + } + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s' and %s = '%s' " + "and %s = '%s' and %s = '%s' and %s = '%s';", + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENCY_TYPE, + sm_service_dependency_type_str( record->type ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_SERVICE_NAME, + record->service_name, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_STATE, + sm_service_state_str( record->state ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_ACTION, + sm_service_action_str( record->action ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT, + record->dependent ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Delete +// ==================================== +SmErrorT sm_db_service_dependency_delete( SmDbHandleT* sm_db_handle, + SmServiceDependencyTypeT type, char service_name[], SmServiceStateT state, + SmServiceActionT action, char dependent[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s " + "WHERE %s = '%s' and %s = '%s' and %s = '%s' " + "and %s = '%s' and %s = '%s';", + SM_SERVICE_DEPENDENCY_TABLE_NAME, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENCY_TYPE, + sm_service_dependency_type_str( type ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_SERVICE_NAME, + service_name, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_STATE, + sm_service_state_str( state ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_ACTION, + sm_service_action_str( action ), + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT, + dependent ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Create Table +// ========================================== +SmErrorT sm_db_service_dependency_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "PRIMARY KEY (%s, %s, %s, %s, %s));", + SM_SERVICE_DEPENDENCY_TABLE_NAME, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENCY_TYPE, + SM_SERVICE_DEPENDENCY_MAX_CHAR, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_NAME_MAX_CHAR, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_STATE, + SM_SERVICE_STATE_MAX_CHAR, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_ACTION, + SM_SERVICE_ACTION_NAME_MAX_CHAR, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT, + SM_SERVICE_NAME_MAX_CHAR, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT_STATE, + SM_SERVICE_STATE_MAX_CHAR, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENCY_TYPE, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_STATE, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_ACTION, + SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Delete Table +// ========================================== +SmErrorT sm_db_service_dependency_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_DEPENDENCY_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Initialize +// ======================================== +SmErrorT sm_db_service_dependency_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Finalize +// ====================================== +SmErrorT sm_db_service_dependency_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_dependency.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_dependency.h new file mode 100644 index 00000000..d658dc19 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_dependency.h @@ -0,0 +1,100 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_DEPENDENCY_H__ +#define __SM_DB_SERVICE_DEPENDENCY_H__ + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_DEPENDENCY_TABLE_NAME "SERVICE_DEPENDENCY" +#define SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENCY_TYPE "DEPENDENCY_TYPE" +#define SM_SERVICE_DEPENDENCY_TABLE_COLUMN_SERVICE_NAME "SERVICE_NAME" +#define SM_SERVICE_DEPENDENCY_TABLE_COLUMN_STATE "STATE" +#define SM_SERVICE_DEPENDENCY_TABLE_COLUMN_ACTION "ACTION" +#define SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT "DEPENDENT" +#define SM_SERVICE_DEPENDENCY_TABLE_COLUMN_DEPENDENT_STATE "DEPENDENT_STATE" + +typedef struct +{ + SmServiceDependencyTypeT type; + char service_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceStateT state; + SmServiceActionT action; + char dependent[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceStateT dependent_state; +} SmDbServiceDependencyT; + +// **************************************************************************** +// Database Service Dependency - Convert +// ===================================== +extern SmErrorT sm_db_service_dependency_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Read +// ================================== +extern SmErrorT sm_db_service_dependency_read( SmDbHandleT* sm_db_handle, + SmServiceDependencyTypeT type, char service_name[], SmServiceStateT state, + SmServiceActionT action, char dependent[], SmDbServiceDependencyT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Insert +// ==================================== +extern SmErrorT sm_db_service_dependency_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDependencyT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Update +// ==================================== +extern SmErrorT sm_db_service_dependency_update( SmDbHandleT* sm_db_handle, + SmDbServiceDependencyT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Delete +// ==================================== +extern SmErrorT sm_db_service_dependency_delete( SmDbHandleT* sm_db_handle, + SmServiceDependencyTypeT type, char service_name[], SmServiceStateT state, + SmServiceActionT action, char dependent[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Create Table +// ========================================== +extern SmErrorT sm_db_service_dependency_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Delete Table +// ========================================== +extern SmErrorT sm_db_service_dependency_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Initialize +// ======================================== +extern SmErrorT sm_db_service_dependency_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Dependency - Finalize +// ====================================== +extern SmErrorT sm_db_service_dependency_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_DEPENDENCY_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_assignments.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_assignments.c new file mode 100644 index 00000000..821673fa --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_assignments.c @@ -0,0 +1,644 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_domain_assignments.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_utils.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Domain Assignments - Convert +// ============================================= +SmErrorT sm_db_service_domain_assignments_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceDomainAssignmentT* record = (SmDbServiceDomainAssignmentT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_ID, + col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_UUID, + col_name ) ) + { + snprintf( record->uuid, sizeof(record->uuid), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NAME, + col_name ) ) + { + snprintf( record->name, sizeof(record->name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NODE_NAME, + col_name ) ) + { + snprintf( record->node_name, sizeof(record->node_name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_SERVICE_GROUP_NAME, + col_name ) ) + { + snprintf( record->service_group_name, sizeof(record->service_group_name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_DESIRED_STATE, + col_name ) ) + { + record->desired_state = sm_service_group_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATE, + col_name ) ) + { + record->state = sm_service_group_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATUS, + col_name ) ) + { + record->status = sm_service_group_status_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_CONDITION, + col_name ) ) + { + record->condition = sm_service_group_condition_value( col_data ); + + } else { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Read Callback +// =================================================== +static int sm_db_service_domain_assignments_read_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + SmDbServiceDomainAssignmentT* record; + SmErrorT error; + + record = (SmDbServiceDomainAssignmentT*) user_data; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_domain_assignments_convert( col_name[col_i], + col_data[col_i], + record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Read +// ========================================== +SmErrorT sm_db_service_domain_assignments_read( SmDbHandleT* sm_db_handle, + char name[], char node_name[], char service_group_name[], + SmDbServiceDomainAssignmentT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainAssignmentT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s' " + "and %s = '%s' and %s = '%s';", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NAME, name, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NODE_NAME, node_name, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_SERVICE_GROUP_NAME, + service_group_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_assignments_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Read By Identifier +// ======================================================== +SmErrorT sm_db_service_domain_assignments_read_by_id( + SmDbHandleT* sm_db_handle, int64_t id, + SmDbServiceDomainAssignmentT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainAssignmentT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%"PRIi64"';", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_ID, id ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_assignments_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( id != record->id ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Query +// =========================================== +SmErrorT sm_db_service_domain_assignments_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceDomainAssignmentT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainAssignmentT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_assignments_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Count Callback +// ==================================================== +static int sm_db_service_domain_assignments_count_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + int* count = (int*) user_data; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + if( 0 == strcmp( col_name[col_i], "record_count" ) ) + { + *count = atoi( col_data[col_i] ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Count +// =========================================== +SmErrorT sm_db_service_domain_assignments_count( SmDbHandleT* sm_db_handle, + const char* db_distinct_columns, const char* db_query, int* count ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + *count = 0; + + if( NULL == db_distinct_columns ) + { + snprintf( sql, sizeof(sql), "SELECT COUNT(*) AS record_count FROM %s " + "WHERE %s;", SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, + db_query ); + } else { + snprintf( sql, sizeof(sql), "SELECT COUNT(DISTINCT %s) AS record_count " + "FROM %s WHERE %s;", db_distinct_columns, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, db_query ); + } + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_assignments_count_callback, + count, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to count, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Sum Callback +// ================================================== +static int sm_db_service_domain_assignments_sum_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + int* sum = (int*) user_data; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + if( 0 == strcmp( col_name[col_i], "record_sum" ) ) + { + *sum = atoi( col_data[col_i] ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Sum +// ========================================= +SmErrorT sm_db_service_domain_assignments_sum( SmDbHandleT* sm_db_handle, + const char* db_sum_column, const char* db_query, int* sum ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + *sum = 0; + + snprintf( sql, sizeof(sql), "SELECT SUM(%s) AS record_sum " + "FROM %s WHERE %s;", db_sum_column, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_assignments_sum_callback, + sum, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to sum, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Insert +// ============================================ +SmErrorT sm_db_service_domain_assignments_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDomainAssignmentT* record ) +{ + SmUuidT uuid; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + sm_uuid_create( uuid ); + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( " + "%s, %s, %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s');", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_UUID, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NODE_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_SERVICE_GROUP_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_DESIRED_STATE, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATE, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATUS, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_CONDITION, + uuid, + record->name, record->node_name, record->service_group_name, + sm_service_group_state_str( record->desired_state ), + sm_service_group_state_str( record->state ), + sm_service_group_status_str( record->status ), + sm_service_group_condition_str( record->condition ) ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Update +// ============================================ +SmErrorT sm_db_service_domain_assignments_update( SmDbHandleT* sm_db_handle, + SmDbServiceDomainAssignmentT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME); + + if( SM_SERVICE_GROUP_STATE_NIL != record->desired_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_DESIRED_STATE, + sm_service_group_state_str(record->desired_state) ); + } + + if( SM_SERVICE_GROUP_STATE_NIL != record->state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATE, + sm_service_group_state_str(record->state) ); + } + + if( SM_SERVICE_GROUP_STATUS_NIL != record->status ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATUS, + sm_service_group_status_str(record->status) ); + } + + if( SM_SERVICE_GROUP_CONDITION_NIL != record->condition ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_CONDITION, + sm_service_group_condition_str(record->condition) ); + } + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s' and %s = '%s' " + "and %s = '%s';", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NAME, record->name, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NODE_NAME, + record->node_name, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_SERVICE_GROUP_NAME, + record->service_group_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Delete +// ============================================ +SmErrorT sm_db_service_domain_assignments_delete( SmDbHandleT* sm_db_handle, + char name[], char node_name[], char service_group_name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s " + "WHERE %s = '%s' and %s = '%s' and %s = '%s';", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NAME, name, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NODE_NAME, node_name, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_SERVICE_GROUP_NAME, + service_group_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Create Table +// ================================================== +SmErrorT sm_db_service_domain_assignments_create_table( + SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i) );", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_ID, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_UUID, + SM_UUID_MAX_CHAR, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NAME, + SM_SERVICE_DOMAIN_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NODE_NAME, + SM_NODE_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_SERVICE_GROUP_NAME, + SM_SERVICE_GROUP_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_DESIRED_STATE, + SM_SERVICE_GROUP_STATE_MAX_CHAR, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATE, + SM_SERVICE_GROUP_STATE_MAX_CHAR, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATUS, + SM_SERVICE_GROUP_STATUS_MAX_CHAR, + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_CONDITION, + SM_SERVICE_GROUP_CONDITION_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Delete Table +// ================================================== +SmErrorT sm_db_service_domain_assignments_delete_table( + SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Cleanup Table +// =================================================== +SmErrorT sm_db_service_domain_assignments_cleanup_table( + SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + if( sm_utils_boot_complete() ) + { + DPRINTFD( "Boot is complete, leave service domain assignments " + "alone." ); + return( SM_OKAY ); + } + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_DESIRED_STATE, + sm_service_group_state_str(SM_SERVICE_GROUP_STATE_DISABLED) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATE, + sm_service_group_state_str(SM_SERVICE_GROUP_STATE_DISABLED) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATUS, + sm_service_group_status_str(SM_SERVICE_GROUP_STATUS_NONE) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_CONDITION, + sm_service_group_condition_str(SM_SERVICE_GROUP_CONDITION_NONE) ); + + snprintf( sql+len-2, sizeof(sql)-len, ";" ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Initialize +// ================================================ +SmErrorT sm_db_service_domain_assignments_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Finalize +// ============================================== +SmErrorT sm_db_service_domain_assignments_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_assignments.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_assignments.h new file mode 100644 index 00000000..00a6a779 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_assignments.h @@ -0,0 +1,150 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_DOMAIN_ASSIGNMENTS_H__ +#define __SM_DB_SERVICE_DOMAIN_ASSIGNMENTS_H__ + +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_uuid.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_NAME "SERVICE_DOMAIN_ASSIGNMENTS" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_UUID "UUID" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NAME "NAME" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_NODE_NAME "NODE_NAME" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_SERVICE_GROUP_NAME "SERVICE_GROUP_NAME" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_DESIRED_STATE "DESIRED_STATE" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATE "STATE" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_STATUS "STATUS" +#define SM_SERVICE_DOMAIN_ASSIGNMENTS_TABLE_COLUMN_CONDITION "CONDITION" + +typedef struct +{ + int64_t id; + SmUuidT uuid; + char name[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char node_name[SM_NODE_NAME_MAX_CHAR]; + char service_group_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceGroupStateT desired_state; + SmServiceGroupStateT state; + SmServiceGroupStatusT status; + SmServiceGroupConditionT condition; +} SmDbServiceDomainAssignmentT; + +// **************************************************************************** +// Database Service Domain Assignments - Convert +// ============================================= +extern SmErrorT sm_db_service_domain_assignments_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Read +// ========================================== +extern SmErrorT sm_db_service_domain_assignments_read( + SmDbHandleT* sm_db_handle, char name[], char node_name[], + char service_group_name[], SmDbServiceDomainAssignmentT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Read By Identifier +// ======================================================== +extern SmErrorT sm_db_service_domain_assignments_read_by_id( + SmDbHandleT* sm_db_handle, int64_t id, + SmDbServiceDomainAssignmentT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Query +// =========================================== +extern SmErrorT sm_db_service_domain_assignments_query( + SmDbHandleT* sm_db_handle, const char* db_query, + SmDbServiceDomainAssignmentT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Count +// =========================================== +extern SmErrorT sm_db_service_domain_assignments_count( + SmDbHandleT* sm_db_handle, const char* db_distinct_columns, + const char* db_query, int* count ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Sum +// ========================================= +extern SmErrorT sm_db_service_domain_assignments_sum( + SmDbHandleT* sm_db_handle, const char* db_sum_column, + const char* db_query, int* sum ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Insert +// ============================================ +extern SmErrorT sm_db_service_domain_assignments_insert( + SmDbHandleT* sm_db_handle, SmDbServiceDomainAssignmentT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Update +// ============================================ +extern SmErrorT sm_db_service_domain_assignments_update( + SmDbHandleT* sm_db_handle, SmDbServiceDomainAssignmentT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Delete +// ============================================ +extern SmErrorT sm_db_service_domain_assignments_delete( + SmDbHandleT* sm_db_handle, char name[], char node_name[], + char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Create Table +// ================================================== +extern SmErrorT sm_db_service_domain_assignments_create_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Delete Table +// ================================================== +extern SmErrorT sm_db_service_domain_assignments_delete_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Cleanup Table +// =================================================== +extern SmErrorT sm_db_service_domain_assignments_cleanup_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Initialize +// ================================================ +extern SmErrorT sm_db_service_domain_assignments_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Assignments - Finalize +// ============================================== +extern SmErrorT sm_db_service_domain_assignments_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_DOMAIN_ASSIGNMENTS_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_interfaces.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_interfaces.c new file mode 100644 index 00000000..ecdff20e --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_interfaces.c @@ -0,0 +1,663 @@ +// +// Copyright (c) 2014-2017 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_domain_interfaces.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Domain Interfaces - Convert +// ============================================ +SmErrorT sm_db_service_domain_interfaces_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceDomainInterfaceT* record = (SmDbServiceDomainInterfaceT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_ID, col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PROVISIONED, + col_name ) ) + { + record->provisioned = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->provisioned = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN, + col_name ) ) + { + snprintf( record->service_domain, sizeof(record->service_domain), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN_INTERFACE, + col_name ) ) + { + snprintf( record->service_domain_interface, + sizeof(record->service_domain_interface), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PATH_TYPE, + col_name ) ) + { + record->path_type = sm_path_type_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_TYPE, col_name ) ) + { + record->auth_type = sm_auth_type_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_KEY, + col_name ) ) + { + snprintf( record->auth_key, sizeof(record->auth_key), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_NAME, + col_name ) ) + { + snprintf( record->interface_name, sizeof(record->interface_name), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_STATE, + col_name ) ) + { + record->interface_state = sm_interface_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_TYPE, + col_name ) ) + { + record->network_type = sm_network_type_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_MULTICAST, + col_name ) ) + { + // Assumes that network type has already been set in the record. + record->network_multicast.type = record->network_type; + if( !sm_network_address_value( col_data, &(record->network_multicast) ) ) + { + // MULTICAST NOT CONFIGURED + record->network_multicast.type = SM_NETWORK_TYPE_NIL; + DPRINTFI( "Multicast not configured, look like (%s).", col_data ); + } + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_ADDRESS, + col_name ) ) + { + // Assumes that network type has already been set in the record. + record->network_address.type = record->network_type; + sm_network_address_value( col_data, &(record->network_address) ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PORT, + col_name ) ) + { + record->network_port = col_data ? atoi(col_data) : -1; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_HEARTBEAT_PORT, + col_name ) ) + { + record->network_heartbeat_port = col_data ? atoi(col_data) : -1; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_ADDRESS, + col_name ) ) + { + // Assumes that network type has already been set in the record. + record->network_peer_address.type = record->network_type; + sm_network_address_value( col_data, &(record->network_peer_address) ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_PORT, + col_name ) ) + { + record->network_peer_port = col_data ? atoi(col_data) : -1; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_HEARTBEAT_PORT, + col_name ) ) + { + record->network_peer_heartbeat_port = col_data ? atoi(col_data) : -1; + }else if ( 0 == strcmp( SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_CONNECT_TYPE, col_name ) ) + { + if ( 0 == strcmp( SM_INTERFACE_CONNECT_TYPE_DC, col_data ) ) + { + record->interface_connect_type = SM_SERVICE_DOMAIN_INTERFACE_CONNECT_TYPE_DC; + DPRINTFD( "connect type %s", SM_INTERFACE_CONNECT_TYPE_DC ); + } + else if ( 0 == strcmp( SM_INTERFACE_CONNECT_TYPE_TOR, col_data ) ) + { + record->interface_connect_type = SM_SERVICE_DOMAIN_INTERFACE_CONNECT_TYPE_TOR; + DPRINTFD( "connect type %s", SM_INTERFACE_CONNECT_TYPE_TOR ); + } + else + { + DPRINTFE( "Unknown interface connect type (%s).", col_data ); + } + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Read Callback +// ================================================== +static int sm_db_service_domain_interfaces_read_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + SmDbServiceDomainInterfaceT* record = (SmDbServiceDomainInterfaceT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_domain_interfaces_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Read +// ========================================= +SmErrorT sm_db_service_domain_interfaces_read( SmDbHandleT* sm_db_handle, + char service_domain[], char service_domain_interface[], + SmDbServiceDomainInterfaceT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainInterfaceT) ); + record->network_type = SM_NETWORK_TYPE_UNKNOWN; + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s' and " + "%s = '%s';", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN, + service_domain, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN_INTERFACE, + service_domain_interface ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_interfaces_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if(( 0 != strcmp( service_domain, record->service_domain ) )&& + ( 0 != strcmp( service_domain_interface, + record->service_domain_interface ) )) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Query +// ========================================== +SmErrorT sm_db_service_domain_interfaces_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceDomainInterfaceT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainInterfaceT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_interfaces_read_callback, record, + &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->service_domain_interface ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Insert +// =========================================== +SmErrorT sm_db_service_domain_interfaces_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDomainInterfaceT* record ) +{ + char network_multicast[SM_NETWORK_ADDRESS_MAX_CHAR]; + char network_address[SM_NETWORK_ADDRESS_MAX_CHAR]; + char network_peer_address[SM_NETWORK_ADDRESS_MAX_CHAR]; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + sm_network_address_str( &(record->network_multicast), network_multicast ); + sm_network_address_str( &(record->network_address), network_address ); + sm_network_address_str( &(record->network_peer_address), network_peer_address ); + + snprintf( sql, sizeof(sql), "INSERT INTO %s " + "( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', " + "'%s', '%s', '%i', '%i', '%s', '%i', '%i');", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN_INTERFACE, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PATH_TYPE, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_TYPE, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_KEY, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_NAME, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_STATE, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_TYPE, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_MULTICAST, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_ADDRESS, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PORT, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_HEARTBEAT_PORT, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_ADDRESS, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_PORT, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_HEARTBEAT_PORT, + record->provisioned ? "yes" : "no", + record->service_domain, + record->service_domain_interface, + sm_path_type_str( record->path_type ), + sm_auth_type_str( record->auth_type ), + record->auth_key, + record->interface_name, + sm_interface_state_str( record->interface_state ), + sm_network_type_str( record->network_type ), + network_multicast, network_address, record->network_port, + record->network_heartbeat_port, network_peer_address, + record->network_peer_port, record->network_peer_heartbeat_port + ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Update +// ============================================ +SmErrorT sm_db_service_domain_interfaces_update( SmDbHandleT* sm_db_handle, + SmDbServiceDomainInterfaceT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME); + + if( SM_PATH_TYPE_NIL != record->path_type ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PATH_TYPE, + sm_path_type_str(record->path_type) ); + } + + if( SM_AUTH_TYPE_NIL != record->auth_type ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_TYPE, + sm_auth_type_str(record->auth_type) ); + } + + if( '\0' != record->auth_key ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_KEY, + record->auth_key ); + } + + if( '\0' != record->interface_name[0] ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_NAME, + record->interface_name ); + } + + if( SM_INTERFACE_STATE_NIL != record->interface_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_STATE, + sm_interface_state_str(record->interface_state) ); + } + + if( SM_NETWORK_TYPE_NIL != record->network_type ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_TYPE, + sm_network_type_str(record->network_type) ); + } + + if( SM_NETWORK_TYPE_UNKNOWN != record->network_multicast.type ) + { + char network_multicast[SM_NETWORK_ADDRESS_MAX_CHAR]; + + sm_network_address_str( &(record->network_multicast), + network_multicast ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_MULTICAST, + network_multicast ); + } + + if( SM_NETWORK_TYPE_UNKNOWN != record->network_address.type ) + { + char network_address[SM_NETWORK_ADDRESS_MAX_CHAR]; + + sm_network_address_str( &(record->network_address), network_address ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_ADDRESS, + network_address ); + } + + if( -1 != record->network_port ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PORT, + record->network_port ); + } + + if( -1 != record->network_heartbeat_port ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_HEARTBEAT_PORT, + record->network_heartbeat_port ); + } + + if( SM_NETWORK_TYPE_UNKNOWN != record->network_peer_address.type ) + { + char network_peer_address[SM_NETWORK_ADDRESS_MAX_CHAR]; + + sm_network_address_str( &(record->network_peer_address), + network_peer_address ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_ADDRESS, + network_peer_address ); + } + + if( -1 != record->network_peer_port ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_PORT, + record->network_peer_port ); + } + + if( -1 != record->network_peer_heartbeat_port ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_HEARTBEAT_PORT, + record->network_peer_heartbeat_port ); + } + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN, + record->service_domain, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN_INTERFACE, + record->service_domain_interface ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Delete +// =========================================== +SmErrorT sm_db_service_domain_interfaces_delete( SmDbHandleT* sm_db_handle, + char service_domain[], char service_domain_interface[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN, + service_domain, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN_INTERFACE, + service_domain_interface ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Create Table +// ================================================= +SmErrorT sm_db_service_domain_interfaces_create_table( + SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s INT, " + "%s INT, " + "%s CHAR(%i), " + "%s INT, " + "%s INT );", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_ID, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_DOMAIN_INTERFACE_PROVISIONED_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN, + SM_SERVICE_DOMAIN_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN_INTERFACE, + SM_SERVICE_DOMAIN_INTERFACE_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PATH_TYPE, + SM_PATH_TYPE_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_TYPE, + SM_AUTHENTICATION_TYPE_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_KEY, + SM_AUTHENTICATION_KEY_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_NAME, + SM_INTERFACE_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_STATE, + SM_INTERFACE_STATE_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_TYPE, + SM_NETWORK_TYPE_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_MULTICAST, + SM_NETWORK_ADDRESS_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_ADDRESS, + SM_NETWORK_ADDRESS_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PORT, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_HEARTBEAT_PORT, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_ADDRESS, + SM_NETWORK_ADDRESS_MAX_CHAR, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_PORT, + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_HEARTBEAT_PORT ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Delete Table +// ================================================= +SmErrorT sm_db_service_domain_interfaces_delete_table( + SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Cleanup Table +// ================================================== +SmErrorT sm_db_service_domain_interfaces_cleanup_table( + SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_STATE, + sm_interface_state_str( SM_INTERFACE_STATE_UNKNOWN ) ); + + snprintf( sql+len-2, sizeof(sql)-len, ";" ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Initialize +// =============================================== +SmErrorT sm_db_service_domain_interfaces_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Finalize +// ============================================= +SmErrorT sm_db_service_domain_interfaces_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_interfaces.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_interfaces.h new file mode 100644 index 00000000..a5c9deec --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_interfaces.h @@ -0,0 +1,149 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_DOMAIN_INTERFACES_H__ +#define __SM_DB_SERVICE_DOMAIN_INTERFACES_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_timer.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_NAME "SERVICE_DOMAIN_INTERFACES" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PROVISIONED "PROVISIONED" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN "SERVICE_DOMAIN" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_SERVICE_DOMAIN_INTERFACE "SERVICE_DOMAIN_INTERFACE" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_PATH_TYPE "PATH_TYPE" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_TYPE "AUTH_TYPE" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_AUTH_KEY "AUTH_KEY" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_NAME "INTERFACE_NAME" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_STATE "INTERFACE_STATE" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_TYPE "NETWORK_TYPE" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_MULTICAST "NETWORK_MULTICAST" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_ADDRESS "NETWORK_ADDRESS" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PORT "NETWORK_PORT" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_HEARTBEAT_PORT "NETWORK_HEARTBEAT_PORT" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_ADDRESS "NETWORK_PEER_ADDRESS" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_PORT "NETWORK_PEER_PORT" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_NETWORK_PEER_HEARTBEAT_PORT "NETWORK_PEER_HEARTBEAT_PORT" +#define SM_SERVICE_DOMAIN_INTERFACES_TABLE_COLUMN_INTERFACE_CONNECT_TYPE "INTERFACE_CONNECT_TYPE" + + +#define SM_INTERFACE_CONNECT_TYPE_DC "dc" +#define SM_INTERFACE_CONNECT_TYPE_TOR "tor" + +typedef struct +{ + int64_t id; + bool provisioned; + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char service_domain_interface[SM_SERVICE_DOMAIN_INTERFACE_NAME_MAX_CHAR]; + SmPathTypeT path_type; + SmAuthTypeT auth_type; + char auth_key[SM_AUTHENTICATION_KEY_MAX_CHAR]; + char interface_name[SM_INTERFACE_NAME_MAX_CHAR]; + SmInterfaceStateT interface_state; + SmNetworkTypeT network_type; + SmNetworkAddressT network_multicast; + SmNetworkAddressT network_address; + int network_port; + int network_heartbeat_port; + SmNetworkAddressT network_peer_address; + int network_peer_port; + int network_peer_heartbeat_port; + SmServiceDomainInterfaceConnectTypeT interface_connect_type; +} SmDbServiceDomainInterfaceT; + +// **************************************************************************** +// Database Service Domain Interfaces - Convert +// ============================================ +extern SmErrorT sm_db_service_domain_interfaces_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Read +// ========================================= +extern SmErrorT sm_db_service_domain_interfaces_read( + SmDbHandleT* sm_db_handle, char service_domain[], + char service_domain_interface[], SmDbServiceDomainInterfaceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Query +// ========================================== +extern SmErrorT sm_db_service_domain_interfaces_query( + SmDbHandleT* sm_db_handle, const char* db_query, + SmDbServiceDomainInterfaceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Insert +// =========================================== +extern SmErrorT sm_db_service_domain_interfaces_insert( + SmDbHandleT* sm_db_handle, SmDbServiceDomainInterfaceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Update +// =========================================== +extern SmErrorT sm_db_service_domain_interfaces_update( + SmDbHandleT* sm_db_handle, SmDbServiceDomainInterfaceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Delete +// =========================================== +extern SmErrorT sm_db_service_domain_interfaces_delete( + SmDbHandleT* sm_db_handle, char service_domain[], + char service_domain_interface[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Create Table +// ================================================= +extern SmErrorT sm_db_service_domain_interfaces_create_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Delete Table +// ================================================= +extern SmErrorT sm_db_service_domain_interfaces_delete_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Cleanup Table +// ================================================== +extern SmErrorT sm_db_service_domain_interfaces_cleanup_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Initialize +// =============================================== +extern SmErrorT sm_db_service_domain_interfaces_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Interfaces - Finalize +// ============================================= +extern SmErrorT sm_db_service_domain_interfaces_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_DOMAIN_INTERFACES_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_members.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_members.c new file mode 100644 index 00000000..247b3b32 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_members.c @@ -0,0 +1,494 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_domain_members.h" + +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Domain Members - Convert +// ========================================= +SmErrorT sm_db_service_domain_members_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceDomainMemberT* record = (SmDbServiceDomainMemberT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_ID, + col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_PROVISIONED, + col_name ) ) + { + record->provisioned = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->provisioned = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_NAME, col_name ) ) + { + snprintf( record->name, sizeof(record->name), + "%s", col_data ? col_data : "" ); + + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_NAME, + col_name ) ) + { + snprintf( record->service_group_name, sizeof(record->service_group_name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_REDUNDANCY_MODEL, + col_name ) ) + { + record->redundancy_model + = sm_service_domain_member_redundancy_model_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_N_ACTIVE, + col_name ) ) + { + record->n_active = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_M_STANDBY, + col_name ) ) + { + record->m_standby = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_AGGREGATE, + col_name ) ) + { + snprintf( record->service_group_aggregate, + sizeof(record->service_group_aggregate), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_ACTIVE_ONLY_IF_ACTIVE, + col_name ) ) + { + snprintf( record->active_only_if_active, + sizeof(record->active_only_if_active), + "%s", col_data ? col_data : "" ); + + } else { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Read Callback +// =============================================== +static int sm_db_service_domain_members_read_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + SmDbServiceDomainMemberT* record = (SmDbServiceDomainMemberT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_domain_members_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Read +// ====================================== +SmErrorT sm_db_service_domain_members_read( SmDbHandleT* sm_db_handle, + char name[], char service_group_name[], SmDbServiceDomainMemberT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainMemberT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s' " + "and %s = '%s';", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_NAME, name, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_NAME, + service_group_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_members_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Query +// ======================================= +SmErrorT sm_db_service_domain_members_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceDomainMemberT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainMemberT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_members_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Count Callback +// ================================================ +static int sm_db_service_domain_members_count_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + int* count = (int*) user_data; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + if( 0 == strcmp( col_name[col_i], "record_count" ) ) + { + *count = atoi( col_data[col_i] ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Count +// ======================================= +SmErrorT sm_db_service_domain_members_count( SmDbHandleT* sm_db_handle, + const char* db_distinct_columns, const char* db_query, int* count ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + *count = 0; + + if( NULL == db_distinct_columns ) + { + snprintf( sql, sizeof(sql), "SELECT COUNT(*) AS record_count FROM %s " + "WHERE %s;", SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME, + db_query ); + } else { + snprintf( sql, sizeof(sql), "SELECT COUNT(DISTINCT %s) AS record_count " + "FROM %s WHERE %s;", db_distinct_columns, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME, db_query ); + } + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_members_count_callback, + count, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to count, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Insert +// ======================================== +SmErrorT sm_db_service_domain_members_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDomainMemberT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( " + "%s, %s, %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%i', '%i', '%s', '%s');", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_NAME, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_NAME, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_REDUNDANCY_MODEL, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_N_ACTIVE, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_M_STANDBY, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_AGGREGATE, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_ACTIVE_ONLY_IF_ACTIVE, + record->provisioned ? "yes" : "no", + record->name, record->service_group_name, + sm_service_domain_member_redundancy_model_str(record->redundancy_model), + record->n_active, record->m_standby, + record->service_group_aggregate, record->active_only_if_active ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Update +// ======================================== +SmErrorT sm_db_service_domain_members_update( SmDbHandleT* sm_db_handle, + SmDbServiceDomainMemberT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME ); + + if( SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_NIL != record->redundancy_model ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_REDUNDANCY_MODEL, + sm_service_domain_member_redundancy_model_str( + record->redundancy_model) ); + } + + if( 0 < record->n_active ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_N_ACTIVE, + record->n_active ); + } + + if( 0 < record->m_standby ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_M_STANDBY, + record->m_standby ); + } + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_AGGREGATE, + record->service_group_aggregate ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_ACTIVE_ONLY_IF_ACTIVE, + record->active_only_if_active ); + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_NAME, record->name, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_NAME, + record->service_group_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Delete +// ======================================== +SmErrorT sm_db_service_domain_members_delete( SmDbHandleT* sm_db_handle, + char name[], char service_group_name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s " + "WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_NAME, name, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_NAME, + service_group_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Create Table +// ============================================== +SmErrorT sm_db_service_domain_members_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s INT, " + "%s INT, " + "%s CHAR(%i), " + "%s CHAR(%i) );", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_ID, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_DOMAIN_MEMBER_PROVISIONED_MAX_CHAR, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_NAME, + SM_SERVICE_DOMAIN_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_NAME, + SM_SERVICE_GROUP_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_REDUNDANCY_MODEL, + SM_SERVICE_DOMAIN_MEMBER_REDUNDANCY_MODEL_MAX_CHAR, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_N_ACTIVE, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_M_STANDBY, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_AGGREGATE, + SM_SERVICE_GROUP_AGGREGATE_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_ACTIVE_ONLY_IF_ACTIVE, + SM_SERVICE_GROUP_NAME_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Delete Table +// ============================================== +SmErrorT sm_db_service_domain_members_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Initialize +// ============================================ +SmErrorT sm_db_service_domain_members_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Finalize +// ========================================== +SmErrorT sm_db_service_domain_members_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_members.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_members.h new file mode 100644 index 00000000..478d9787 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_members.h @@ -0,0 +1,122 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_DOMAIN_MEMBERS_H__ +#define __SM_DB_SERVICE_DOMAIN_MEMBERS_H__ + +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_NAME "SERVICE_DOMAIN_MEMBERS" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_PROVISIONED "PROVISIONED" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_NAME "NAME" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_NAME "SERVICE_GROUP_NAME" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_REDUNDANCY_MODEL "REDUNDANCY_MODEL" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_N_ACTIVE "N_ACTIVE" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_M_STANDBY "M_STANDBY" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_SERVICE_GROUP_AGGREGATE "SERVICE_GROUP_AGGREGATE" +#define SM_SERVICE_DOMAIN_MEMBERS_TABLE_COLUMN_ACTIVE_ONLY_IF_ACTIVE "ACTIVE_ONLY_IF_ACTIVE" + +typedef struct +{ + int64_t id; + bool provisioned; + char name[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char service_group_name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + SmServiceDomainMemberRedundancyModelT redundancy_model; + int n_active; + int m_standby; + char service_group_aggregate[SM_SERVICE_GROUP_AGGREGATE_NAME_MAX_CHAR]; + char active_only_if_active[SM_SERVICE_GROUP_NAME_MAX_CHAR]; +} SmDbServiceDomainMemberT; + +// **************************************************************************** +// Database Service Domain Members - Convert +// ========================================= +extern SmErrorT sm_db_service_domain_members_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Read +// ====================================== +extern SmErrorT sm_db_service_domain_members_read( SmDbHandleT* sm_db_handle, + char name[], char service_group_name[], SmDbServiceDomainMemberT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Query +// ======================================= +extern SmErrorT sm_db_service_domain_members_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceDomainMemberT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Count +// ======================================= +extern SmErrorT sm_db_service_domain_members_count( SmDbHandleT* sm_db_handle, + const char* db_distinct_columns, const char* db_query, int* count ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Insert +// ======================================== +extern SmErrorT sm_db_service_domain_members_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDomainMemberT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Update +// ======================================== +extern SmErrorT sm_db_service_domain_members_update( SmDbHandleT* sm_db_handle, + SmDbServiceDomainMemberT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Delete +// ======================================== +extern SmErrorT sm_db_service_domain_members_delete( SmDbHandleT* sm_db_handle, + char name[], char service_group_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Create Table +// ============================================== +extern SmErrorT sm_db_service_domain_members_create_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Delete Table +// ============================================== +extern SmErrorT sm_db_service_domain_members_delete_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Initialize +// ============================================ +extern SmErrorT sm_db_service_domain_members_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Members - Finalize +// ========================================== +extern SmErrorT sm_db_service_domain_members_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_DOMAIN_MEMBERS_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_neighbors.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_neighbors.c new file mode 100644 index 00000000..23e4ace4 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_neighbors.c @@ -0,0 +1,563 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_domain_neighbors.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Domain Neighbors - Convert +// =========================================== +SmErrorT sm_db_service_domain_neighbors_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceDomainNeighborT* record = (SmDbServiceDomainNeighborT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ID, + col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_NAME, + col_name ) ) + { + snprintf( record->name, sizeof(record->name), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_SERVICE_DOMAIN, + col_name ) ) + { + snprintf( record->service_domain, sizeof(record->service_domain), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ORCHESTRATION, + col_name ) ) + { + snprintf( record->orchestration, sizeof(record->orchestration), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DESIGNATION, + col_name ) ) + { + snprintf( record->designation, sizeof(record->designation), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_GENERATION, + col_name ) ) + { + record->generation = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_PRIORITY, + col_name ) ) + { + record->priority = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_HELLO_INTERVAL, + col_name ) ) + { + record->hello_interval = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DEAD_INTERVAL, + col_name ) ) + { + record->dead_interval = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_WAIT_INTERVAL, + col_name ) ) + { + record->wait_interval = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_EXCHANGE_INTERVAL, + col_name ) ) + { + record->exchange_interval = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_STATE, + col_name ) ) + { + record->state = sm_service_domain_neighbor_state_value( col_data ); + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Read Callback +// ================================================= +static int sm_db_service_domain_neighbors_read_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + SmDbServiceDomainNeighborT* record = (SmDbServiceDomainNeighborT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_domain_neighbors_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Read +// ======================================== +SmErrorT sm_db_service_domain_neighbors_read( SmDbHandleT* sm_db_handle, + char name[], char service_domain[], SmDbServiceDomainNeighborT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainNeighborT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s' and " + "%s = '%s';", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_NAME, name, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_SERVICE_DOMAIN, + service_domain ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_neighbors_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Read By Identifier +// ====================================================== +SmErrorT sm_db_service_domain_neighbors_read_by_id( SmDbHandleT* sm_db_handle, + int64_t id, SmDbServiceDomainNeighborT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainNeighborT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%"PRIi64"';", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ID, id ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_neighbors_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( id != record->id ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Query +// ========================================= +SmErrorT sm_db_service_domain_neighbors_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceDomainNeighborT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainNeighborT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domain_neighbors_read_callback, record, + &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Insert +// ========================================== +SmErrorT sm_db_service_domain_neighbors_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDomainNeighborT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s " + "( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%i', '%i', '%i', '%i', " + "'%i', '%i', '%s');", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_NAME, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_SERVICE_DOMAIN, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ORCHESTRATION, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DESIGNATION, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_GENERATION, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_PRIORITY, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_HELLO_INTERVAL, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DEAD_INTERVAL, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_WAIT_INTERVAL, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_EXCHANGE_INTERVAL, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_STATE, + record->name, + record->service_domain, + record->orchestration, + record->designation, + record->generation, + record->priority, + record->hello_interval, record->dead_interval, + record->wait_interval, record->exchange_interval, + sm_service_domain_neighbor_state_str( record->state ) + ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Update +// ========================================== +SmErrorT sm_db_service_domain_neighbors_update( SmDbHandleT* sm_db_handle, + SmDbServiceDomainNeighborT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME); + + if( '\0' != record->orchestration ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ORCHESTRATION, + record->orchestration ); + } + + if( '\0' != record->designation ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DESIGNATION, + record->designation ); + } + + if( -1 < record->generation ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_GENERATION, + record->generation ); + } + + if( 0 < record->priority ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_PRIORITY, + record->priority ); + } + + if( 0 < record->hello_interval ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_HELLO_INTERVAL, + record->hello_interval ); + } + + if( 0 < record->dead_interval ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DEAD_INTERVAL, + record->dead_interval ); + } + + if( 0 < record->wait_interval ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_WAIT_INTERVAL, + record->wait_interval ); + } + + if( 0 < record->exchange_interval ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_EXCHANGE_INTERVAL, + record->exchange_interval ); + } + + if( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_NIL != record->state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_STATE, + sm_service_domain_neighbor_state_str(record->state) ); + } + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_NAME, record->name, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_SERVICE_DOMAIN, + record->service_domain ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Delete +// ========================================== +SmErrorT sm_db_service_domain_neighbors_delete( SmDbHandleT* sm_db_handle, + char name[], char service_domain[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s' " + "and %s = '%s';", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_NAME, name, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_SERVICE_DOMAIN, + service_domain ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Create Table +// ================================================ +SmErrorT sm_db_service_domain_neighbors_create_table( + SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s CHAR(%i));", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ID, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_NAME, + SM_NODE_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_SERVICE_DOMAIN, + SM_SERVICE_DOMAIN_NAME_MAX_CHAR, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ORCHESTRATION, + SM_ORCHESTRATION_MAX_CHAR, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DESIGNATION, + SM_DESIGNATION_MAX_CHAR, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_GENERATION, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_PRIORITY, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_HELLO_INTERVAL, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DEAD_INTERVAL, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_WAIT_INTERVAL, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_EXCHANGE_INTERVAL, + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_STATE, + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Delete Table +// ================================================ +SmErrorT sm_db_service_domain_neighbors_delete_table( + SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Cleanup Table +// ================================================= +SmErrorT sm_db_service_domain_neighbors_cleanup_table( + SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_STATE, + sm_service_domain_neighbor_state_str( + SM_SERVICE_DOMAIN_NEIGHBOR_STATE_DOWN ) ); + + snprintf( sql+len-2, sizeof(sql)-len, ";" ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Initialize +// ============================================== +SmErrorT sm_db_service_domain_neighbors_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Finalize +// ============================================ +SmErrorT sm_db_service_domain_neighbors_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_neighbors.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_neighbors.h new file mode 100644 index 00000000..a91b35ac --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domain_neighbors.h @@ -0,0 +1,138 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_DOMAIN_NEIGHBORS_H__ +#define __SM_DB_SERVICE_DOMAIN_NEIGHBORS_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_timer.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_NAME "SERVICE_DOMAIN_NEIGHBORS" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_NAME "NAME" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_SERVICE_DOMAIN "SERVICE_DOMAIN" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_ORCHESTRATION "ORCHESTRATION" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DESIGNATION "DESIGNATION" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_GENERATION "GENERATION" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_PRIORITY "PRIORITY" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_HELLO_INTERVAL "HELLO_INTERVAL" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_DEAD_INTERVAL "DEAD_INTERVAL" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_WAIT_INTERVAL "WAIT_INTERVAL" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_EXCHANGE_INTERVAL "EXCHANGE_INTERVAL" +#define SM_SERVICE_DOMAIN_NEIGHBORS_TABLE_COLUMN_STATE "STATE" + +typedef struct +{ + int64_t id; + char name[SM_NODE_NAME_MAX_CHAR]; + char service_domain[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + char orchestration[SM_ORCHESTRATION_MAX_CHAR]; + char designation[SM_DESIGNATION_MAX_CHAR]; + int generation; + int priority; + int hello_interval; + int dead_interval; + int wait_interval; + int exchange_interval; + SmServiceDomainNeighborStateT state; +} SmDbServiceDomainNeighborT; + +// **************************************************************************** +// Database Service Domain Neighbors - Convert +// =========================================== +extern SmErrorT sm_db_service_domain_neighbors_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Read +// ======================================== +extern SmErrorT sm_db_service_domain_neighbors_read( SmDbHandleT* sm_db_handle, + char name[], char service_domain[], SmDbServiceDomainNeighborT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Read By Identifier +// ====================================================== +extern SmErrorT sm_db_service_domain_neighbors_read_by_id( + SmDbHandleT* sm_db_handle, int64_t id, SmDbServiceDomainNeighborT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Query +// ========================================= +extern SmErrorT sm_db_service_domain_neighbors_query( + SmDbHandleT* sm_db_handle, const char* db_query, + SmDbServiceDomainNeighborT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Insert +// ========================================== +extern SmErrorT sm_db_service_domain_neighbors_insert( + SmDbHandleT* sm_db_handle, SmDbServiceDomainNeighborT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Update +// ========================================== +extern SmErrorT sm_db_service_domain_neighbors_update( + SmDbHandleT* sm_db_handle, SmDbServiceDomainNeighborT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Delete +// ========================================== +extern SmErrorT sm_db_service_domain_neighbors_delete( + SmDbHandleT* sm_db_handle, char name[], char service_domain[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Create Table +// ================================================ +extern SmErrorT sm_db_service_domain_neighbors_create_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Delete Table +// ================================================ +extern SmErrorT sm_db_service_domain_neighbors_delete_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Cleanup Table +// ================================================= +extern SmErrorT sm_db_service_domain_neighbors_cleanup_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Initialize +// ============================================== +extern SmErrorT sm_db_service_domain_neighbors_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domain Neighbors - Finalize +// ============================================ +extern SmErrorT sm_db_service_domain_neighbors_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_DOMAIN_NEIGHBORS_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domains.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domains.c new file mode 100644 index 00000000..e916a54d --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domains.c @@ -0,0 +1,623 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_domains.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_timer.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Domains - Convert +// ================================== +SmErrorT sm_db_service_domains_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceDomainT* record = (SmDbServiceDomainT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_ID,col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_PROVISIONED, + col_name ) ) + { + record->provisioned = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->provisioned = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_NAME, col_name ) ) + { + snprintf( record->name, sizeof(record->name), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_ORCHESTRATION, + col_name ) ) + { + record->orchestration = sm_orchestration_type_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_DESIGNATION, + col_name ) ) + { + record->designation = sm_designation_type_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_PREEMPT, + col_name ) ) + { + record->preempt = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->preempt = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_GENERATION, + col_name ) ) + { + record->generation = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_PRIORITY, + col_name ) ) + { + record->priority = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_HELLO_INTERVAL, + col_name ) ) + { + record->hello_interval = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_DEAD_INTERVAL, + col_name ) ) + { + record->dead_interval = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_WAIT_INTERVAL, + col_name ) ) + { + record->wait_interval = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_EXCHANGE_INTERVAL, + col_name ) ) + { + record->exchange_interval = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_STATE, + col_name ) ) + { + record->state = sm_service_domain_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_SPLIT_BRAIN_RECOVERY, + col_name ) ) + { + record->split_brain_recovery + = sm_service_domain_split_brain_recovery_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_DOMAINS_TABLE_COLUMN_LEADER, + col_name ) ) + { + snprintf( record->leader, sizeof(record->leader), "%s", + col_data ? col_data : "" ); + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Read Callback +// ======================================== +static int sm_db_service_domains_read_callback( void* user_data, int num_cols, + char **col_data, char **col_name ) +{ + SmDbServiceDomainT* record = (SmDbServiceDomainT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_domains_convert( col_name[col_i], col_data[col_i], + record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Read +// =============================== +SmErrorT sm_db_service_domains_read( SmDbHandleT* sm_db_handle, char name[], + SmDbServiceDomainT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s';", + SM_SERVICE_DOMAINS_TABLE_NAME, + SM_SERVICE_DOMAINS_TABLE_COLUMN_NAME, name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domains_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Read By Identifier +// ============================================= +SmErrorT sm_db_service_domains_read_by_id( SmDbHandleT* sm_db_handle, + int64_t id, SmDbServiceDomainT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%"PRIi64"';", + SM_SERVICE_DOMAINS_TABLE_NAME, + SM_SERVICE_DOMAINS_TABLE_COLUMN_ID, id ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domains_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( id != record->id ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Query +// ================================ +SmErrorT sm_db_service_domains_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceDomainT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceDomainT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_SERVICE_DOMAINS_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_domains_read_callback, record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Insert +// ================================= +SmErrorT sm_db_service_domains_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDomainT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s " + "( %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%i', '%i', '%i', " + "'%i', '%i', '%i', '%s', '%s', '%s');", + SM_SERVICE_DOMAINS_TABLE_NAME, + SM_SERVICE_DOMAINS_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_DOMAINS_TABLE_COLUMN_NAME, + SM_SERVICE_DOMAINS_TABLE_COLUMN_ORCHESTRATION, + SM_SERVICE_DOMAINS_TABLE_COLUMN_DESIGNATION, + SM_SERVICE_DOMAINS_TABLE_COLUMN_PREEMPT, + SM_SERVICE_DOMAINS_TABLE_COLUMN_GENERATION, + SM_SERVICE_DOMAINS_TABLE_COLUMN_PRIORITY, + SM_SERVICE_DOMAINS_TABLE_COLUMN_HELLO_INTERVAL, + SM_SERVICE_DOMAINS_TABLE_COLUMN_DEAD_INTERVAL, + SM_SERVICE_DOMAINS_TABLE_COLUMN_WAIT_INTERVAL, + SM_SERVICE_DOMAINS_TABLE_COLUMN_EXCHANGE_INTERVAL, + SM_SERVICE_DOMAINS_TABLE_COLUMN_STATE, + SM_SERVICE_DOMAINS_TABLE_COLUMN_SPLIT_BRAIN_RECOVERY, + SM_SERVICE_DOMAINS_TABLE_COLUMN_LEADER, + record->provisioned ? "yes" : "no", + record->name, + sm_orchestration_type_str(record->orchestration), + sm_designation_type_str(record->designation), + record->preempt ? "yes" : "no", + record->generation, + record->priority, + record->hello_interval, + record->dead_interval, + record->wait_interval, + record->exchange_interval, + sm_service_domain_state_str( record->state ), + sm_service_domain_split_brain_recovery_str( + record->split_brain_recovery ), + record->leader + ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Update +// ================================= +SmErrorT sm_db_service_domains_update( SmDbHandleT* sm_db_handle, + SmDbServiceDomainT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAINS_TABLE_NAME); + + if( SM_ORCHESTRATION_TYPE_NIL != record->orchestration ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_ORCHESTRATION, + sm_orchestration_type_str(record->orchestration) ); + } + + if( SM_DESIGNATION_TYPE_NIL != record->designation ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_DESIGNATION, + sm_designation_type_str(record->designation) ); + } + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_PREEMPT, + record->preempt ? "yes" : "no" ); + + if( -1 < record->generation ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_GENERATION, + record->generation ); + } + + if( -1 < record->priority ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_PRIORITY, + record->priority ); + } + + if( 0 < record->hello_interval ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_HELLO_INTERVAL, + record->hello_interval ); + } + + if( 0 < record->dead_interval ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_DEAD_INTERVAL, + record->dead_interval ); + } + + if( 0 < record->wait_interval ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_WAIT_INTERVAL, + record->wait_interval ); + } + + if( 0 < record->exchange_interval ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_EXCHANGE_INTERVAL, + record->exchange_interval ); + } + + if( SM_SERVICE_DOMAIN_STATE_NIL != record->state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_STATE, + sm_service_domain_state_str(record->state) ); + } + + if( SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_NIL != record->split_brain_recovery ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_SPLIT_BRAIN_RECOVERY, + sm_service_domain_split_brain_recovery_str( + record->split_brain_recovery) ); + } + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_LEADER, + record->leader ); + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s';", + SM_SERVICE_DOMAINS_TABLE_COLUMN_NAME, + record->name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Delete +// ================================= +SmErrorT sm_db_service_domains_delete( SmDbHandleT* sm_db_handle, char name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s';", + SM_SERVICE_DOMAINS_TABLE_NAME, + SM_SERVICE_DOMAINS_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Create Table +// ======================================= +SmErrorT sm_db_service_domains_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i));", + SM_SERVICE_DOMAINS_TABLE_NAME, + SM_SERVICE_DOMAINS_TABLE_COLUMN_ID, + SM_SERVICE_DOMAINS_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_DOMAIN_PROVISIONED_MAX_CHAR, + SM_SERVICE_DOMAINS_TABLE_COLUMN_NAME, + SM_SERVICE_DOMAIN_NAME_MAX_CHAR, + SM_SERVICE_DOMAINS_TABLE_COLUMN_ORCHESTRATION, + SM_ORCHESTRATION_MAX_CHAR, + SM_SERVICE_DOMAINS_TABLE_COLUMN_DESIGNATION, + SM_DESIGNATION_MAX_CHAR, + SM_SERVICE_DOMAINS_TABLE_COLUMN_PREEMPT, + SM_SERVICE_DOMAIN_PREEMPT_MAX_CHAR, + SM_SERVICE_DOMAINS_TABLE_COLUMN_GENERATION, + SM_SERVICE_DOMAINS_TABLE_COLUMN_PRIORITY, + SM_SERVICE_DOMAINS_TABLE_COLUMN_HELLO_INTERVAL, + SM_SERVICE_DOMAINS_TABLE_COLUMN_DEAD_INTERVAL, + SM_SERVICE_DOMAINS_TABLE_COLUMN_WAIT_INTERVAL, + SM_SERVICE_DOMAINS_TABLE_COLUMN_EXCHANGE_INTERVAL, + SM_SERVICE_DOMAINS_TABLE_COLUMN_STATE, + SM_SERVICE_DOMAIN_STATE_MAX_CHAR, + SM_SERVICE_DOMAINS_TABLE_COLUMN_SPLIT_BRAIN_RECOVERY, + SM_SERVICE_DOMAIN_SPLIT_BRAIN_RECOVERY_MAX_CHAR, + SM_SERVICE_DOMAINS_TABLE_COLUMN_LEADER, + SM_NODE_NAME_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Delete Table +// ======================================= +SmErrorT sm_db_service_domains_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_DOMAINS_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Cleanup Table +// ======================================== +SmErrorT sm_db_service_domains_cleanup_table( SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_DOMAINS_TABLE_NAME ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_DESIGNATION, + sm_designation_type_str(SM_DESIGNATION_TYPE_UNKNOWN) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_STATE, + sm_service_domain_state_str(SM_SERVICE_DOMAIN_STATE_INITIAL) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_DOMAINS_TABLE_COLUMN_LEADER, "" ); + + snprintf( sql+len-2, sizeof(sql)-len, ";" ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Initialize +// ===================================== +SmErrorT sm_db_service_domains_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Finalize +// =================================== +SmErrorT sm_db_service_domains_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_domains.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domains.h new file mode 100644 index 00000000..79854b11 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_domains.h @@ -0,0 +1,140 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_DOMAINS_H__ +#define __SM_DB_SERVICE_DOMAINS_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_timer.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_DOMAINS_TABLE_NAME "SERVICE_DOMAINS" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_PROVISIONED "PROVISIONED" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_NAME "NAME" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_ORCHESTRATION "ORCHESTRATION" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_DESIGNATION "DESIGNATION" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_PREEMPT "PREEMPT" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_GENERATION "GENERATION" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_PRIORITY "PRIORITY" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_HELLO_INTERVAL "HELLO_INTERVAL" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_DEAD_INTERVAL "DEAD_INTERVAL" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_WAIT_INTERVAL "WAIT_INTERVAL" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_EXCHANGE_INTERVAL "EXCHANGE_INTERVAL" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_STATE "STATE" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_SPLIT_BRAIN_RECOVERY "SPLIT_BRAIN_RECOVERY" +#define SM_SERVICE_DOMAINS_TABLE_COLUMN_LEADER "LEADER" + +typedef struct +{ + int64_t id; + bool provisioned; + char name[SM_SERVICE_DOMAIN_NAME_MAX_CHAR]; + SmOrchestrationTypeT orchestration; + SmDesignationTypeT designation; + bool preempt; + int generation; + int priority; + int hello_interval; + int dead_interval; + int wait_interval; + int exchange_interval; + SmServiceDomainStateT state; + SmServiceDomainSplitBrainRecoveryT split_brain_recovery; + char leader[SM_NODE_NAME_MAX_CHAR]; +} SmDbServiceDomainT; + +// **************************************************************************** +// Database Service Domains - Convert +// ================================== +extern SmErrorT sm_db_service_domains_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Read +// =============================== +extern SmErrorT sm_db_service_domains_read( SmDbHandleT* sm_db_handle, + char name[], SmDbServiceDomainT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Read By Identifier +// ============================================= +extern SmErrorT sm_db_service_domains_read_by_id( SmDbHandleT* sm_db_handle, + int64_t id, SmDbServiceDomainT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Query +// ================================ +extern SmErrorT sm_db_service_domains_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceDomainT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Insert +// ================================= +extern SmErrorT sm_db_service_domains_insert( SmDbHandleT* sm_db_handle, + SmDbServiceDomainT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Update +// ================================= +extern SmErrorT sm_db_service_domains_update( SmDbHandleT* sm_db_handle, + SmDbServiceDomainT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Delete +// ================================= +extern SmErrorT sm_db_service_domains_delete( SmDbHandleT* sm_db_handle, + char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Create Table +// ======================================= +extern SmErrorT sm_db_service_domains_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Delete Table +// ======================================= +extern SmErrorT sm_db_service_domains_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Cleanup Table +// ======================================== +extern SmErrorT sm_db_service_domains_cleanup_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Initialize +// ===================================== +extern SmErrorT sm_db_service_domains_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Domains - Finalize +// =================================== +extern SmErrorT sm_db_service_domains_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_DOMAINS_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_group_members.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_group_members.c new file mode 100644 index 00000000..5b11429e --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_group_members.c @@ -0,0 +1,405 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_group_members.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Group Members - Convert +// ======================================== +SmErrorT sm_db_service_group_members_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceGroupMemberT* record = (SmDbServiceGroupMemberT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_ID, + col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_PROVISIONED, + col_name ) ) + { + record->provisioned = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->provisioned = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_NAME, + col_name ) ) + { + snprintf( record->name, sizeof(record->name), + "%s", col_data ? col_data : "" ); + + } else if( 0 == strcmp( SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_NAME, + col_name ) ) + { + snprintf( record->service_name, sizeof(record->service_name), + "%s", col_data ? col_data : "" ); + + } else if( 0 == strcmp( SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_FAILURE_IMPACT, + col_name ) ) + { + record->service_failure_impact = sm_service_severity_value( col_data ); + + } else { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Read Callback +// ============================================== +static int sm_db_service_group_members_read_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + SmDbServiceGroupMemberT* record = (SmDbServiceGroupMemberT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_group_members_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Read +// ===================================== +SmErrorT sm_db_service_group_members_read( SmDbHandleT* sm_db_handle, + char name[], char service_name[], SmDbServiceGroupMemberT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceGroupMemberT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s' " + "and %s = '%s';", + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_NAME, name, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_NAME, + service_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_group_members_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Query +// ====================================== +SmErrorT sm_db_service_group_members_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceGroupMemberT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceGroupMemberT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_group_members_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Insert +// ======================================= +SmErrorT sm_db_service_group_members_insert( SmDbHandleT* sm_db_handle, + SmDbServiceGroupMemberT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( " + "%s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s');", + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_NAME, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_FAILURE_IMPACT, + record->provisioned ? "yes" : "no", + record->name, record->service_name, + sm_service_severity_str( record->service_failure_impact ) ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Update +// ======================================= +SmErrorT sm_db_service_group_members_update( SmDbHandleT* sm_db_handle, + SmDbServiceGroupMemberT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME ); + + if( SM_SERVICE_SEVERITY_NIL != record->service_failure_impact ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_FAILURE_IMPACT, + sm_service_severity_str( record->service_failure_impact ) ); + } + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_NAME, record->name, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_NAME, + record->service_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Delete +// ======================================= +SmErrorT sm_db_service_group_members_delete( SmDbHandleT* sm_db_handle, + char name[], char service_name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s " + "WHERE %s = '%s' and %s = '%s';", + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_NAME, name, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_NAME, + service_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Create Table +// ============================================= +SmErrorT sm_db_service_group_members_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i));", + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_ID, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_GROUP_MEMBER_PROVISIONED_MAX_CHAR, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_NAME, + SM_SERVICE_GROUP_NAME_MAX_CHAR, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_NAME_MAX_CHAR, + SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_FAILURE_IMPACT, + SM_SERVICE_SEVERITY_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Delete Table +// ============================================= +SmErrorT sm_db_service_group_members_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Cleanup Table +// ============================================== +SmErrorT sm_db_service_group_members_cleanup_table( + SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_GROUP_MEMBERS_TABLE_NAME ); + + // Nothing at the momement. + + snprintf( sql+len-2, sizeof(sql)-len, ";" ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Initialize +// =========================================== +SmErrorT sm_db_service_group_members_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Finalize +// ========================================= +SmErrorT sm_db_service_group_members_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_group_members.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_group_members.h new file mode 100644 index 00000000..acfd9b15 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_group_members.h @@ -0,0 +1,115 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_GROUP_MEMBERS_H__ +#define __SM_DB_SERVICE_GROUP_MEMBERS_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_GROUP_MEMBERS_TABLE_NAME "SERVICE_GROUP_MEMBERS" +#define SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_PROVISIONED "PROVISIONED" +#define SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_NAME "NAME" +#define SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_NAME "SERVICE_NAME" +#define SM_SERVICE_GROUP_MEMBERS_TABLE_COLUMN_SERVICE_FAILURE_IMPACT "SERVICE_FAILURE_IMPACT" + +typedef struct +{ + int64_t id; + bool provisioned; + char name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + char service_name[SM_SERVICE_NAME_MAX_CHAR]; + SmServiceSeverityT service_failure_impact; +} SmDbServiceGroupMemberT; + +// **************************************************************************** +// Database Service Group Members - Convert +// ======================================== +extern SmErrorT sm_db_service_group_members_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Read +// ===================================== +extern SmErrorT sm_db_service_group_members_read( SmDbHandleT* sm_db_handle, + char name[], char service_name[], SmDbServiceGroupMemberT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Query +// ====================================== +extern SmErrorT sm_db_service_group_members_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceGroupMemberT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Insert +// ======================================= +extern SmErrorT sm_db_service_group_members_insert( SmDbHandleT* sm_db_handle, + SmDbServiceGroupMemberT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Update +// ======================================= +extern SmErrorT sm_db_service_group_members_update( SmDbHandleT* sm_db_handle, + SmDbServiceGroupMemberT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Delete +// ======================================= +extern SmErrorT sm_db_service_group_members_delete( SmDbHandleT* sm_db_handle, + char name[], char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Create Table +// ============================================= +extern SmErrorT sm_db_service_group_members_create_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Delete Table +// ============================================= +extern SmErrorT sm_db_service_group_members_delete_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Cleanup Table +// ============================================== +extern SmErrorT sm_db_service_group_members_cleanup_table( + SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Initialize +// =========================================== +extern SmErrorT sm_db_service_group_members_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Group Members - Finalize +// ========================================= +extern SmErrorT sm_db_service_group_members_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_GROUP_MEMBERS_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_groups.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_groups.c new file mode 100644 index 00000000..7ad3ee63 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_groups.c @@ -0,0 +1,494 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_groups.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Groups - Convert +// ================================= +SmErrorT sm_db_service_groups_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceGroupT* record = (SmDbServiceGroupT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_ID,col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_PROVISIONED, + col_name ) ) + { + record->provisioned = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->provisioned = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_NAME, col_name ) ) + { + snprintf( record->name, sizeof(record->name), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_AUTO_RECOVER, + col_name ) ) + { + record->auto_recover = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->auto_recover = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_CORE, + col_name ) ) + { + record->core = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->core = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_DESIRED_STATE, + col_name ) ) + { + record->desired_state = sm_service_group_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_STATE, col_name ) ) + { + record->state = sm_service_group_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_STATUS, col_name ) ) + { + record->status = sm_service_group_status_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_CONDITION, col_name ) ) + { + record->condition = sm_service_group_condition_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_FAILURE_DEBOUNCE, + col_name ) ) + { + record->failure_debounce_in_ms = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_GROUPS_TABLE_COLUMN_FATAL_ERROR_REBOOT, + col_name ) ) + { + record->fatal_error_reboot = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->fatal_error_reboot = true; + } + } + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Read Callback +// ======================================= +static int sm_db_service_groups_read_callback( void* user_data, int num_cols, + char **col_data, char **col_name ) +{ + SmDbServiceGroupT* record = (SmDbServiceGroupT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_groups_convert( col_name[col_i], col_data[col_i], + record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Read +// ============================== +SmErrorT sm_db_service_groups_read( SmDbHandleT* sm_db_handle, char name[], + SmDbServiceGroupT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceGroupT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s';", + SM_SERVICE_GROUPS_TABLE_NAME, + SM_SERVICE_GROUPS_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_groups_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Insert +// ================================ +SmErrorT sm_db_service_groups_insert( SmDbHandleT* sm_db_handle, + SmDbServiceGroupT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( %s, %s, %s, %s, %s, %s, %s, " + "%s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', " + "'%i', '%s');", + SM_SERVICE_GROUPS_TABLE_NAME, + SM_SERVICE_GROUPS_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_GROUPS_TABLE_COLUMN_NAME, + SM_SERVICE_GROUPS_TABLE_COLUMN_AUTO_RECOVER, + SM_SERVICE_GROUPS_TABLE_COLUMN_CORE, + SM_SERVICE_GROUPS_TABLE_COLUMN_DESIRED_STATE, + SM_SERVICE_GROUPS_TABLE_COLUMN_STATE, + SM_SERVICE_GROUPS_TABLE_COLUMN_STATUS, + SM_SERVICE_GROUPS_TABLE_COLUMN_CONDITION, + SM_SERVICE_GROUPS_TABLE_COLUMN_FAILURE_DEBOUNCE, + SM_SERVICE_GROUPS_TABLE_COLUMN_FATAL_ERROR_REBOOT, + record->provisioned ? "yes" : "no", + record->name, + record->auto_recover ? "yes" : "no", + record->core ? "yes" : "no", + sm_service_group_state_str( record->desired_state ), + sm_service_group_state_str( record->state ), + sm_service_group_status_str( record->status ), + sm_service_group_condition_str( record->condition ), + record->failure_debounce_in_ms, + record->fatal_error_reboot ? "yes" : "no" + ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Update +// ================================ +SmErrorT sm_db_service_groups_update( SmDbHandleT* sm_db_handle, + SmDbServiceGroupT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_GROUPS_TABLE_NAME); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_AUTO_RECOVER, + record->auto_recover ? "yes" : "no" ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_CORE, + record->core ? "yes" : "no" ); + + if( SM_SERVICE_GROUP_STATE_NIL != record->desired_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_DESIRED_STATE, + sm_service_group_state_str(record->desired_state) ); + } + + if( SM_SERVICE_GROUP_STATE_NIL != record->state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_STATE, + sm_service_group_state_str(record->state) ); + } + + if( SM_SERVICE_GROUP_STATUS_NIL != record->status ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_STATUS, + sm_service_group_status_str(record->status) ); + } + + if( SM_SERVICE_GROUP_CONDITION_NIL != record->condition ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_CONDITION, + sm_service_group_condition_str(record->condition) ); + } + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_FAILURE_DEBOUNCE, + record->failure_debounce_in_ms ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_FATAL_ERROR_REBOOT, + record->fatal_error_reboot ? "yes" : "no" ); + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s';", + SM_SERVICE_GROUPS_TABLE_COLUMN_NAME, record->name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Delete +// ================================ +SmErrorT sm_db_service_groups_delete( SmDbHandleT* sm_db_handle, char name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s';", + SM_SERVICE_GROUPS_TABLE_NAME, + SM_SERVICE_GROUPS_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Create Table +// ====================================== +SmErrorT sm_db_service_groups_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s INT, " + "%s CHAR(%i) );", + SM_SERVICE_GROUPS_TABLE_NAME, + SM_SERVICE_GROUPS_TABLE_COLUMN_ID, + SM_SERVICE_GROUPS_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_GROUP_PROVISIONED_MAX_CHAR, + SM_SERVICE_GROUPS_TABLE_COLUMN_NAME, + SM_SERVICE_GROUP_NAME_MAX_CHAR, + SM_SERVICE_GROUPS_TABLE_COLUMN_AUTO_RECOVER, + SM_SERVICE_GROUP_AUTO_RECOVER_MAX_CHAR, + SM_SERVICE_GROUPS_TABLE_COLUMN_CORE, + SM_SERVICE_GROUP_CORE_MAX_CHAR, + SM_SERVICE_GROUPS_TABLE_COLUMN_DESIRED_STATE, + SM_SERVICE_GROUP_STATE_MAX_CHAR, + SM_SERVICE_GROUPS_TABLE_COLUMN_STATE, + SM_SERVICE_GROUP_STATE_MAX_CHAR, + SM_SERVICE_GROUPS_TABLE_COLUMN_STATUS, + SM_SERVICE_GROUP_STATUS_MAX_CHAR, + SM_SERVICE_GROUPS_TABLE_COLUMN_CONDITION, + SM_SERVICE_GROUP_CONDITION_MAX_CHAR, + SM_SERVICE_GROUPS_TABLE_COLUMN_FAILURE_DEBOUNCE, + SM_SERVICE_GROUPS_TABLE_COLUMN_FATAL_ERROR_REBOOT, + SM_SERVICE_GROUP_FATAL_ERROR_REBOOT_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Delete Table +// ====================================== +SmErrorT sm_db_service_groups_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_GROUPS_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Cleanup Table +// ======================================= +SmErrorT sm_db_service_groups_cleanup_table( SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_GROUPS_TABLE_NAME); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_STATE, + sm_service_group_state_str(SM_SERVICE_GROUP_STATE_INITIAL) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_STATUS, + sm_service_group_status_str(SM_SERVICE_GROUP_STATUS_NONE) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_GROUPS_TABLE_COLUMN_CONDITION, + sm_service_group_condition_str(SM_SERVICE_GROUP_CONDITION_NONE) ); + + snprintf( sql+len-2, sizeof(sql)-len, ";" ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Initialize +// ==================================== +SmErrorT sm_db_service_groups_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Finalize +// ================================== +SmErrorT sm_db_service_groups_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_groups.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_groups.h new file mode 100644 index 00000000..160834de --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_groups.h @@ -0,0 +1,117 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_GROUPS_H__ +#define __SM_DB_SERVICE_GROUPS_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_GROUPS_TABLE_NAME "SERVICE_GROUPS" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_PROVISIONED "PROVISIONED" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_NAME "NAME" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_AUTO_RECOVER "AUTO_RECOVER" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_CORE "CORE" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_DESIRED_STATE "DESIRED_STATE" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_STATE "STATE" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_STATUS "STATUS" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_CONDITION "CONDITION" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_FAILURE_DEBOUNCE "FAILURE_DEBOUNCE" +#define SM_SERVICE_GROUPS_TABLE_COLUMN_FATAL_ERROR_REBOOT "FATAL_ERROR_REBOOT" + +typedef struct +{ + int64_t id; + bool provisioned; + char name[SM_SERVICE_GROUP_NAME_MAX_CHAR]; + bool auto_recover; + bool core; + SmServiceGroupStateT desired_state; + SmServiceGroupStateT state; + SmServiceGroupStatusT status; + SmServiceGroupConditionT condition; + int failure_debounce_in_ms; + bool fatal_error_reboot; +} SmDbServiceGroupT; + +// **************************************************************************** +// Database Service Groups - Convert +// ================================= +extern SmErrorT sm_db_service_groups_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Read +// ============================== +extern SmErrorT sm_db_service_groups_read( SmDbHandleT* sm_db_handle, + char name[], SmDbServiceGroupT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Insert +// ================================ +extern SmErrorT sm_db_service_groups_insert( SmDbHandleT* sm_db_handle, + SmDbServiceGroupT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Update +// ================================ +extern SmErrorT sm_db_service_groups_update( SmDbHandleT* sm_db_handle, + SmDbServiceGroupT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Delete +// ================================ +extern SmErrorT sm_db_service_groups_delete( SmDbHandleT* sm_db_handle, + char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Create Table +// ====================================== +extern SmErrorT sm_db_service_groups_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Delete Table +// ====================================== +extern SmErrorT sm_db_service_groups_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Cleanup Table +// ======================================= +extern SmErrorT sm_db_service_groups_cleanup_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Initialize +// ==================================== +extern SmErrorT sm_db_service_groups_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Groups - Finalize +// ================================== +extern SmErrorT sm_db_service_groups_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_GROUPS_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_heartbeat.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_heartbeat.c new file mode 100644 index 00000000..f9d3503c --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_heartbeat.c @@ -0,0 +1,642 @@ + +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_heartbeat.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Heartbeat - Convert +// ==================================== +SmErrorT sm_db_service_heartbeat_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceHeartbeatT* record = (SmDbServiceHeartbeatT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_ID, col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_PROVISIONED, + col_name ) ) + { + record->provisioned = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->provisioned = true; + } + } + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_NAME, col_name ) ) + { + snprintf( record->name, sizeof(record->name), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_TYPE, col_name ) ) + { + record->type = sm_service_heartbeat_type_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_ADDRESS, + col_name ) ) + { + snprintf( record->src_address, sizeof(record->src_address), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_PORT, + col_name ) ) + { + record->src_port = col_data ? atoi(col_data) : 0; + } + + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_ADDRESS, + col_name ) ) + { + snprintf( record->dst_address, sizeof(record->dst_address), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_PORT, + col_name ) ) + { + record->dst_port = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MESSAGE, col_name ) ) + { + snprintf( record->message, sizeof(record->message), "%s", + col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_INTERVAL_IN_MS, + col_name ) ) + { + record->interval_in_ms = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_WARN, + col_name ) ) + { + record->missed_warn = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_DEGRADE, + col_name ) ) + { + record->missed_degrade = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_FAIL, + col_name ) ) + { + record->missed_fail = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_STATE, + col_name ) ) + { + record->state = sm_service_heartbeat_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED, + col_name ) ) + { + record->missed = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_TIMER_ID, + col_name ) ) + { + record->heartbeat_timer_id = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_SOCKET, + col_name ) ) + { + record->heartbeat_socket = col_data ? atoi(col_data) : 0; + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Read Callback +// ========================================== +static int sm_db_service_heartbeat_read_callback( void* user_data, int num_cols, + char **col_data, char **col_name ) +{ + SmDbServiceHeartbeatT* record = (SmDbServiceHeartbeatT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_heartbeat_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Read +// ================================= +SmErrorT sm_db_service_heartbeat_read( SmDbHandleT* sm_db_handle, char name[], + SmDbServiceHeartbeatT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceHeartbeatT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s';", + SM_SERVICE_HEARTBEAT_TABLE_NAME, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_heartbeat_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Read By Identifier +// =============================================== +SmErrorT sm_db_service_heartbeat_read_by_id( SmDbHandleT* sm_db_handle, + int64_t id, SmDbServiceHeartbeatT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceHeartbeatT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%"PRIi64"';", + SM_SERVICE_HEARTBEAT_TABLE_NAME, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_ID, id ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_heartbeat_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( id != record->id ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Query +// ================================== +SmErrorT sm_db_service_heartbeat_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceHeartbeatT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceHeartbeatT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_SERVICE_HEARTBEAT_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_heartbeat_read_callback, record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Insert +// =================================== +SmErrorT sm_db_service_heartbeat_insert( SmDbHandleT* sm_db_handle, + SmDbServiceHeartbeatT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( %s, " + "%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%i', '%s', '%i', '%s', " + "'%i', '%i', '%i', '%i', '%s', '%i', %i', '%i' );", + SM_SERVICE_HEARTBEAT_TABLE_NAME, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_NAME, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_TYPE, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_ADDRESS, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_PORT, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_ADDRESS, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_PORT, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MESSAGE, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_INTERVAL_IN_MS, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_WARN, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_DEGRADE, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_FAIL, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_STATE, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_TIMER_ID, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_SOCKET, + record->provisioned ? "yes" : "no", + record->name, + sm_service_heartbeat_type_str( record->type ), + record->src_address, + record->src_port, + record->dst_address, + record->dst_port, + record->message, + record->interval_in_ms, + record->missed_warn, + record->missed_degrade, + record->missed_fail, + sm_service_heartbeat_state_str( record->state ), + record->missed, + record->heartbeat_timer_id, + record->heartbeat_socket + ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Update +// =================================== +SmErrorT sm_db_service_heartbeat_update( SmDbHandleT* sm_db_handle, + SmDbServiceHeartbeatT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_HEARTBEAT_TABLE_NAME); + + if( SM_SERVICE_HEARTBEAT_TYPE_NIL != record->type ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_TYPE, + sm_service_heartbeat_type_str( record->type ) ); + } + + if( '\0' != record->src_address[0] ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_ADDRESS, + record->src_address ); + } + + if( 0 <= record->src_port ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_PORT, + record->src_port ); + } + + if( '\0' != record->dst_address[0] ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_ADDRESS, + record->dst_address ); + } + + if( 0 <= record->dst_port ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_PORT, + record->dst_port ); + } + + if( '\0' != record->message[0] ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MESSAGE, + record->message ); + } + + if( 0 <= record->interval_in_ms ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_INTERVAL_IN_MS, + record->interval_in_ms ); + } + + if( 0 <= record->missed_warn ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_WARN, + record->missed_warn ); + } + + if( 0 <= record->missed_degrade ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_DEGRADE, + record->missed_degrade ); + } + + if( 0 <= record->missed_fail ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_FAIL, + record->missed_fail ); + } + + if( SM_SERVICE_HEARTBEAT_STATE_NIL != record->state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_STATE, + sm_service_heartbeat_state_str(record->state) ); + } + + if( 0 <= record->missed ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED, + record->missed ); + } + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_TIMER_ID, + record->heartbeat_timer_id ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_SOCKET, + record->heartbeat_socket ); + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s';", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_NAME, record->name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Delete +// =================================== +SmErrorT sm_db_service_heartbeat_delete( SmDbHandleT* sm_db_handle, char name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s';", + SM_SERVICE_HEARTBEAT_TABLE_NAME, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_NAME, + name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Create Table +// ========================================= +SmErrorT sm_db_service_heartbeat_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s INT, " + "%s CHAR(%i), " + "%s INT, " + "%s CHAR(%i), " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s CHAR(%i), " + "%s INT, " + "%s INT, " + "%s INT );", + SM_SERVICE_HEARTBEAT_TABLE_NAME, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_ID, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_HEARTBEAT_PROVISIONED_MAX_CHAR, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_NAME, + SM_SERVICE_HEARTBEAT_NAME_MAX_CHAR, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_TYPE, + SM_SERVICE_HEARTBEAT_TYPE_MAX_CHAR, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_ADDRESS, + SM_SERVICE_HEARTBEAT_ADDRESS_MAX_CHAR, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_PORT, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_ADDRESS, + SM_SERVICE_HEARTBEAT_ADDRESS_MAX_CHAR, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_PORT, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MESSAGE, + SM_SERVICE_HEARTBEAT_MESSAGE_MAX_CHAR, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_INTERVAL_IN_MS, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_WARN, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_DEGRADE, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_FAIL, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_STATE, + SM_SERVICE_HEARTBEAT_STATE_MAX_CHAR, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_TIMER_ID, + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_SOCKET ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Delete Table +// ========================================= +SmErrorT sm_db_service_heartbeat_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_HEARTBEAT_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Cleanup Table +// ========================================== +SmErrorT sm_db_service_heartbeat_cleanup_table( SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_HEARTBEAT_TABLE_NAME ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED, 0 ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_TIMER_ID, + SM_TIMER_ID_INVALID ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_SOCKET, -1 ); + + snprintf( sql+len-2, sizeof(sql)-len, ";" ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Initialize +// ======================================= +SmErrorT sm_db_service_heartbeat_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Finalize +// ===================================== +SmErrorT sm_db_service_heartbeat_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_heartbeat.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_heartbeat.h new file mode 100644 index 00000000..37b5416b --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_heartbeat.h @@ -0,0 +1,145 @@ + +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_HEARTBEAT_H__ +#define __SM_DB_SERVICE_HEARTBEAT_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_timer.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_HEARTBEAT_TABLE_NAME "SERVICE_HEARTBEAT" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_PROVISIONED "PROVISIONED" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_NAME "NAME" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_TYPE "TYPE" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_ADDRESS "SRC_ADDRESS" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_SRC_PORT "SRC_PORT" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_ADDRESS "DST_ADDRESS" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_DST_PORT "DST_PORT" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MESSAGE "MESSAGE" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_INTERVAL_IN_MS "INTERVAL_IN_MS" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_WARN "MISSED_WARN" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_DEGRADE "MISSED_DEGRADE" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED_FAIL "MISSED_FAIL" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_STATE "STATE" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_MISSED "MISSED" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_TIMER_ID "HEARTBEAT_TIMER_ID" +#define SM_SERVICE_HEARTBEAT_TABLE_COLUMN_HEARTBEAT_SOCKET "HEARTBEAT_SOCKET" + +typedef struct +{ + int64_t id; + bool provisioned; + char name[SM_SERVICE_HEARTBEAT_NAME_MAX_CHAR]; + SmServiceHeartbeatTypeT type; + char src_address[SM_SERVICE_HEARTBEAT_ADDRESS_MAX_CHAR]; + int src_port; + char dst_address[SM_SERVICE_HEARTBEAT_ADDRESS_MAX_CHAR]; + int dst_port; + char message[SM_SERVICE_HEARTBEAT_MESSAGE_MAX_CHAR]; + int interval_in_ms; + int missed_warn; + int missed_degrade; + int missed_fail; + SmServiceHeartbeatStateT state; + int missed; + SmTimerIdT heartbeat_timer_id; + int heartbeat_socket; +} SmDbServiceHeartbeatT; + +// **************************************************************************** +// Database Service Heartbeat - Convert +// ==================================== +extern SmErrorT sm_db_service_heartbeat_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Read +// ================================= +extern SmErrorT sm_db_service_heartbeat_read( SmDbHandleT* sm_db_handle, + char name[], SmDbServiceHeartbeatT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Read By Identifier +// =============================================== +extern SmErrorT sm_db_service_heartbeat_read_by_id( SmDbHandleT* sm_db_handle, + int64_t id, SmDbServiceHeartbeatT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Query +// ================================== +extern SmErrorT sm_db_service_heartbeat_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceHeartbeatT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Insert +// =================================== +extern SmErrorT sm_db_service_heartbeat_insert( SmDbHandleT* sm_db_handle, + SmDbServiceHeartbeatT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Update +// =================================== +extern SmErrorT sm_db_service_heartbeat_update( SmDbHandleT* sm_db_handle, + SmDbServiceHeartbeatT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Delete +// =================================== +extern SmErrorT sm_db_service_heartbeat_delete( SmDbHandleT* sm_db_handle, + char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Create Table +// ========================================= +extern SmErrorT sm_db_service_heartbeat_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Delete Table +// ========================================= +extern SmErrorT sm_db_service_heartbeat_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Cleanup Table +// ========================================== +extern SmErrorT sm_db_service_heartbeat_cleanup_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Initialize +// ======================================= +extern SmErrorT sm_db_service_heartbeat_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Heartbeat - Finalize +// ===================================== +extern SmErrorT sm_db_service_heartbeat_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_HEARTBEAT_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_instances.c b/service-mgmt/sm-db-1.0.0/src/sm_db_service_instances.c new file mode 100644 index 00000000..8a330eb8 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_instances.c @@ -0,0 +1,318 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_service_instances.h" + +#include +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Service Instances - Convert +// ==================================== +SmErrorT sm_db_service_instances_convert( const char* col_name, + const char* col_data, void* data ) +{ + SmDbServiceInstanceT* record = (SmDbServiceInstanceT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICE_INSTANCES_TABLE_COLUMN_ID, col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICE_INSTANCES_TABLE_COLUMN_SERVICE_NAME, + col_name ) ) + { + snprintf( record->service_name, sizeof(record->service_name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_NAME, + col_name ) ) + { + snprintf( record->instance_name, sizeof(record->instance_name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_PARAMETERS, + col_name ) ) + { + snprintf( record->instance_params, sizeof(record->instance_params), + "%s", col_data ? col_data : "" ); + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Read Callback +// ========================================== +static int sm_db_service_instances_read_callback( void* user_data, + int num_cols, char **col_data, char **col_name ) +{ + SmDbServiceInstanceT* record = (SmDbServiceInstanceT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_service_instances_convert( col_name[col_i], + col_data[col_i], record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Read +// ================================= +SmErrorT sm_db_service_instances_read( SmDbHandleT* sm_db_handle, + char service_name[], SmDbServiceInstanceT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceInstanceT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s';", + SM_SERVICE_INSTANCES_TABLE_NAME, + SM_SERVICE_INSTANCES_TABLE_COLUMN_SERVICE_NAME, + service_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_service_instances_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( service_name, record->service_name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Insert +// =================================== +SmErrorT sm_db_service_instances_insert( SmDbHandleT* sm_db_handle, + SmDbServiceInstanceT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( %s, %s, %s ) " + "VALUES ('%s', '%s', '%s' );", + SM_SERVICE_INSTANCES_TABLE_NAME, + SM_SERVICE_INSTANCES_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_NAME, + SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_PARAMETERS, + record->service_name, record->instance_name, + record->instance_params ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Update +// =================================== +SmErrorT sm_db_service_instances_update( SmDbHandleT* sm_db_handle, + SmDbServiceInstanceT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICE_INSTANCES_TABLE_NAME ); + + if( 0 < strlen( record->instance_name ) ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_NAME, + record->instance_name ); + } + + if( 0 < strlen( record->instance_params ) ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_PARAMETERS, + record->instance_params ); + } + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s';", + SM_SERVICE_INSTANCES_TABLE_COLUMN_SERVICE_NAME, + record->service_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Delete +// =================================== +SmErrorT sm_db_service_instances_delete( SmDbHandleT* sm_db_handle, + char service_name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s';", + SM_SERVICE_INSTANCES_TABLE_NAME, + SM_SERVICE_INSTANCES_TABLE_COLUMN_SERVICE_NAME, + service_name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Create Table +// ========================================= +SmErrorT sm_db_service_instances_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i) );", + SM_SERVICE_INSTANCES_TABLE_NAME, + SM_SERVICE_INSTANCES_TABLE_COLUMN_ID, + SM_SERVICE_INSTANCES_TABLE_COLUMN_SERVICE_NAME, + SM_SERVICE_NAME_MAX_CHAR, + SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_NAME, + SM_SERVICE_INSTANCE_NAME_MAX_CHAR, + SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_PARAMETERS, + SM_SERVICE_INSTANCE_PARAMS_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Delete Table +// ========================================= +SmErrorT sm_db_service_instances_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICE_INSTANCES_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Initialize +// ======================================= +SmErrorT sm_db_service_instances_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Finalize +// ===================================== +SmErrorT sm_db_service_instances_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_service_instances.h b/service-mgmt/sm-db-1.0.0/src/sm_db_service_instances.h new file mode 100644 index 00000000..ab735d0c --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_service_instances.h @@ -0,0 +1,96 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICE_INSTANCES_H__ +#define __SM_DB_SERVICE_INSTANCES_H__ + +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICE_INSTANCES_TABLE_NAME "SERVICE_INSTANCES" +#define SM_SERVICE_INSTANCES_TABLE_COLUMN_ID "ID" +#define SM_SERVICE_INSTANCES_TABLE_COLUMN_SERVICE_NAME "SERVICE_NAME" +#define SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_NAME "INSTANCE_NAME" +#define SM_SERVICE_INSTANCES_TABLE_COLUMN_INSTANCE_PARAMETERS "INSTANCE_PARAMETERS" + +typedef struct +{ + int64_t id; + char service_name[SM_SERVICE_NAME_MAX_CHAR]; + char instance_name[SM_SERVICE_INSTANCE_NAME_MAX_CHAR]; + char instance_params[SM_SERVICE_INSTANCE_PARAMS_MAX_CHAR]; +} SmDbServiceInstanceT; + +// **************************************************************************** +// Database Service Instances - Convert +// ==================================== +extern SmErrorT sm_db_service_instances_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Read +// ================================= +extern SmErrorT sm_db_service_instances_read( SmDbHandleT* sm_db_handle, + char service_name[], SmDbServiceInstanceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Insert +// =================================== +extern SmErrorT sm_db_service_instances_insert( SmDbHandleT* sm_db_handle, + SmDbServiceInstanceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Update +// =================================== +extern SmErrorT sm_db_service_instances_update( SmDbHandleT* sm_db_handle, + SmDbServiceInstanceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Delete +// =================================== +extern SmErrorT sm_db_service_instances_delete( SmDbHandleT* sm_db_handle, + char service_name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Create Table +// ========================================= +extern SmErrorT sm_db_service_instances_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Delete Table +// ========================================= +extern SmErrorT sm_db_service_instances_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Initialize +// ======================================= +extern SmErrorT sm_db_service_instances_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Service Instances - Finalize +// ===================================== +extern SmErrorT sm_db_service_instances_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICE_INSTANCES_H__ diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_services.c b/service-mgmt/sm-db-1.0.0/src/sm_db_services.c new file mode 100644 index 00000000..66dca285 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_services.c @@ -0,0 +1,556 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#include "sm_db_services.h" + +#include +#include +#include +#include +#include + +#include "sm_limits.h" +#include "sm_types.h" +#include "sm_debug.h" +#include "sm_db.h" + +// **************************************************************************** +// Database Services - Convert +// =========================== +SmErrorT sm_db_services_convert( const char* col_name, const char* col_data, + void* data ) +{ + SmDbServiceT* record = (SmDbServiceT*) data; + + DPRINTFD( "%s = %s", col_name, col_data ? col_data : "NULL" ); + + if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_ID,col_name ) ) + { + record->id = atoll(col_data); + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_PROVISIONED, + col_name ) ) + { + record->provisioned = false; + + if( col_data ) + { + if(( 0 == strcmp( "yes", col_data ))|| + ( 0 == strcmp( "Yes", col_data ))|| + ( 0 == strcmp( "YES", col_data ))) + { + record->provisioned = true; + } + } + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_NAME, col_name ) ) + { + snprintf( record->name, sizeof(record->name), + "%s", col_data ? col_data : "" ); + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_DESIRED_STATE, col_name ) ) + { + record->desired_state = sm_service_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_STATE, col_name ) ) + { + record->state = sm_service_state_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_STATUS, col_name ) ) + { + record->status = sm_service_status_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_CONDITION, col_name ) ) + { + record->condition = sm_service_condition_value( col_data ); + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_MAX_FAILURES, + col_name ) ) + { + record->max_failures = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN, + col_name ) ) + { + record->fail_countdown = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN_INTERVAL, + col_name ) ) + { + record->fail_countdown_interval_in_ms = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_MAX_ACTION_FAILURES, + col_name ) ) + { + record->max_action_failures = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_MAX_TRANSITION_FAILURES, + col_name ) ) + { + record->max_transition_failures = col_data ? atoi(col_data) : 0; + } + else if( 0 == strcmp( SM_SERVICES_TABLE_COLUMN_PID_FILE, col_name ) ) + { + snprintf( record->pid_file, sizeof(record->pid_file), + "%s", col_data ? col_data : "" ); + } + else + { + DPRINTFE( "Unknown column (%s).", col_name ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Read Callback +// ================================= +static int sm_db_services_read_callback( void* user_data, int num_cols, + char **col_data, char **col_name ) +{ + SmDbServiceT* record = (SmDbServiceT*) user_data; + SmErrorT error; + + int col_i; + for( col_i=0; num_cols > col_i; ++col_i ) + { + error = sm_db_services_convert( col_name[col_i], col_data[col_i], + record ); + if( SM_OKAY != error ) + { + DPRINTFE( "Convert failed for column (%s), error=%s.", + col_name[col_i], sm_error_str( error ) ); + return( SQLITE_ERROR ); + } + } + + return( SQLITE_OK ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Read +// ======================== +SmErrorT sm_db_services_read( SmDbHandleT* sm_db_handle, char name[], + SmDbServiceT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%s';", + SM_SERVICES_TABLE_NAME, SM_SERVICES_TABLE_COLUMN_NAME, name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_services_read_callback, record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 != strcmp( name, record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Read By Identifier +// ====================================== +SmErrorT sm_db_services_read_by_id( SmDbHandleT* sm_db_handle, int64_t id, + SmDbServiceT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s = '%"PRIi64"';", + SM_SERVICES_TABLE_NAME, SM_SERVICES_TABLE_COLUMN_ID, id ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_services_read_callback, + record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( id != record->id ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Query +// ========================= +SmErrorT sm_db_services_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + memset( record, 0, sizeof(SmDbServiceT) ); + + snprintf( sql, sizeof(sql), "SELECT * FROM %s WHERE %s;", + SM_SERVICES_TABLE_NAME, db_query ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, + sm_db_services_read_callback, record, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to read, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Read finished." ); + + if( 0 >= strlen( record->name ) ) + { + return( SM_NOT_FOUND ); + } + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Insert +// ========================== +SmErrorT sm_db_services_insert( SmDbHandleT* sm_db_handle, + SmDbServiceT* record ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "INSERT INTO %s ( " + "%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s ) " + "VALUES ('%s', '%s', '%s', '%s', '%s', '%s', %i, %i, %i, " + " %i, %i, %s );", + SM_SERVICES_TABLE_NAME, + SM_SERVICES_TABLE_COLUMN_PROVISIONED, + SM_SERVICES_TABLE_COLUMN_NAME, + SM_SERVICES_TABLE_COLUMN_DESIRED_STATE, + SM_SERVICES_TABLE_COLUMN_STATE, + SM_SERVICES_TABLE_COLUMN_STATUS, + SM_SERVICES_TABLE_COLUMN_CONDITION, + SM_SERVICES_TABLE_COLUMN_MAX_FAILURES, + SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN, + SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN_INTERVAL, + SM_SERVICES_TABLE_COLUMN_MAX_ACTION_FAILURES, + SM_SERVICES_TABLE_COLUMN_MAX_TRANSITION_FAILURES, + SM_SERVICES_TABLE_COLUMN_PID_FILE, + record->provisioned ? "yes" : "no", + record->name, + sm_service_state_str( record->desired_state ), + sm_service_state_str( record->state ), + sm_service_status_str( record->status ), + sm_service_condition_str( record->condition ), + record->max_failures, + record->fail_countdown, + record->fail_countdown_interval_in_ms, + record->max_action_failures, + record->max_transition_failures, + record->pid_file ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to insert, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Insert completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Update +// ========================== +SmErrorT sm_db_services_update( SmDbHandleT* sm_db_handle, + SmDbServiceT* record ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICES_TABLE_NAME ); + + if( SM_SERVICE_STATE_NIL != record->desired_state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICES_TABLE_COLUMN_DESIRED_STATE, + sm_service_state_str( record->desired_state ) ); + } + + if( SM_SERVICE_STATE_NIL != record->state ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICES_TABLE_COLUMN_STATE, + sm_service_state_str( record->state ) ); + } + + if( SM_SERVICE_STATUS_NIL != record->status ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICES_TABLE_COLUMN_STATUS, + sm_service_status_str( record->status ) ); + } + + if( SM_SERVICE_CONDITION_NIL != record->condition ) + { + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICES_TABLE_COLUMN_CONDITION, + sm_service_condition_str( record->condition ) ); + } + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICES_TABLE_COLUMN_MAX_FAILURES, + record->max_failures ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN, + record->fail_countdown ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN_INTERVAL, + record->fail_countdown_interval_in_ms ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICES_TABLE_COLUMN_MAX_ACTION_FAILURES, + record->max_action_failures ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%i', ", + SM_SERVICES_TABLE_COLUMN_MAX_TRANSITION_FAILURES, + record->max_transition_failures ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICES_TABLE_COLUMN_PID_FILE, + record->pid_file ); + + snprintf( sql+len-2, sizeof(sql)-len, " WHERE %s = '%s';", + SM_SERVICES_TABLE_COLUMN_NAME, record->name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Update completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Delete +// ========================== +SmErrorT sm_db_services_delete( SmDbHandleT* sm_db_handle, char name[] ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DELETE FROM %s " + "WHERE %s = '%s';", SM_SERVICES_TABLE_NAME, + SM_SERVICES_TABLE_COLUMN_NAME, name ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Delete finished." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Create Table +// ================================ +SmErrorT sm_db_services_create_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "CREATE TABLE IF NOT EXISTS " + "%s ( " + "%s INTEGER PRIMARY KEY AUTOINCREMENT, " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s CHAR(%i), " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s INT, " + "%s CHAR(%i) );", + SM_SERVICES_TABLE_NAME, + SM_SERVICES_TABLE_COLUMN_ID, + SM_SERVICES_TABLE_COLUMN_PROVISIONED, + SM_SERVICE_PROVISIONED_MAX_CHAR, + SM_SERVICES_TABLE_COLUMN_NAME, + SM_SERVICE_NAME_MAX_CHAR, + SM_SERVICES_TABLE_COLUMN_DESIRED_STATE, + SM_SERVICE_STATE_MAX_CHAR, + SM_SERVICES_TABLE_COLUMN_STATE, + SM_SERVICE_STATE_MAX_CHAR, + SM_SERVICES_TABLE_COLUMN_STATUS, + SM_SERVICE_STATUS_MAX_CHAR, + SM_SERVICES_TABLE_COLUMN_CONDITION, + SM_SERVICE_CONDITION_MAX_CHAR, + SM_SERVICES_TABLE_COLUMN_MAX_FAILURES, + SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN, + SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN_INTERVAL, + SM_SERVICES_TABLE_COLUMN_MAX_ACTION_FAILURES, + SM_SERVICES_TABLE_COLUMN_MAX_TRANSITION_FAILURES, + SM_SERVICES_TABLE_COLUMN_PID_FILE, + SM_SERVICE_PID_FILE_MAX_CHAR ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to create table, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table created." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Delete Table +// ================================ +SmErrorT sm_db_services_delete_table( SmDbHandleT* sm_db_handle ) +{ + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + snprintf( sql, sizeof(sql), "DROP TABLE IF EXISTS %s;", + SM_SERVICES_TABLE_NAME ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to delete table, rc=%i, error=%s.", rc, error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Table deleted." ); + + return( SM_OKAY ); +} + +// **************************************************************************** + +// **************************************************************************** +// Database Services - Cleanup Table +// ================================= +SmErrorT sm_db_services_cleanup_table( SmDbHandleT* sm_db_handle ) +{ + int len; + char sql[SM_SQL_STATEMENT_MAX_CHAR]; + char* error = NULL; + int rc; + + len = snprintf( sql, sizeof(sql), "UPDATE %s SET ", + SM_SERVICES_TABLE_NAME ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICES_TABLE_COLUMN_STATE, + sm_service_state_str( SM_SERVICE_STATE_INITIAL ) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICES_TABLE_COLUMN_STATUS, + sm_service_status_str( SM_SERVICE_STATUS_NONE ) ); + + len += snprintf( sql+len, sizeof(sql)-len, "%s = '%s', ", + SM_SERVICES_TABLE_COLUMN_CONDITION, + sm_service_condition_str( SM_SERVICE_CONDITION_NONE ) ); + + snprintf( sql+len-2, sizeof(sql)-len, ";" ); + + rc = sqlite3_exec( (sqlite3*) sm_db_handle, sql, NULL, NULL, &error ); + if( SQLITE_OK != rc ) + { + DPRINTFE( "Failed to update, sql=%s, rc=%i, error=%s.", sql, rc, + error ); + sqlite3_free( error ); + return( SM_FAILED ); + } + + DPRINTFD( "Cleanup completed." ); + + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Initialize +// ============================== +SmErrorT sm_db_services_initialize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** + +// **************************************************************************** +// Database Services - Finalize +// ============================ +SmErrorT sm_db_services_finalize( void ) +{ + return( SM_OKAY ); +} +// **************************************************************************** diff --git a/service-mgmt/sm-db-1.0.0/src/sm_db_services.h b/service-mgmt/sm-db-1.0.0/src/sm_db_services.h new file mode 100644 index 00000000..5efa650c --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/src/sm_db_services.h @@ -0,0 +1,136 @@ +// +// Copyright (c) 2014 Wind River Systems, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// +#ifndef __SM_DB_SERVICES_H__ +#define __SM_DB_SERVICES_H__ + +#include +#include + +#include "sm_types.h" +#include "sm_limits.h" +#include "sm_timer.h" +#include "sm_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define SM_SERVICES_TABLE_NAME "SERVICES" +#define SM_SERVICES_TABLE_COLUMN_ID "ID" +#define SM_SERVICES_TABLE_COLUMN_PROVISIONED "PROVISIONED" +#define SM_SERVICES_TABLE_COLUMN_NAME "NAME" +#define SM_SERVICES_TABLE_COLUMN_DESIRED_STATE "DESIRED_STATE" +#define SM_SERVICES_TABLE_COLUMN_STATE "STATE" +#define SM_SERVICES_TABLE_COLUMN_STATUS "STATUS" +#define SM_SERVICES_TABLE_COLUMN_CONDITION "CONDITION" +#define SM_SERVICES_TABLE_COLUMN_MAX_FAILURES "MAX_FAILURES" +#define SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN "FAIL_COUNTDOWN" +#define SM_SERVICES_TABLE_COLUMN_FAIL_COUNTDOWN_INTERVAL "FAIL_COUNTDOWN_INTERVAL" +#define SM_SERVICES_TABLE_COLUMN_MAX_ACTION_FAILURES "MAX_ACTION_FAILURES" +#define SM_SERVICES_TABLE_COLUMN_MAX_TRANSITION_FAILURES "MAX_TRANSITION_FAILURES" +#define SM_SERVICES_TABLE_COLUMN_PID_FILE "PID_FILE" + +typedef struct +{ + int64_t id; + bool provisioned; + char name[SM_SERVICE_NAME_MAX_CHAR]; + SmServiceStateT desired_state; + SmServiceStateT state; + SmServiceStatusT status; + SmServiceConditionT condition; + int max_failures; + int fail_countdown; + int fail_countdown_interval_in_ms; + int max_action_failures; + int max_transition_failures; + char pid_file[SM_SERVICE_PID_FILE_MAX_CHAR]; +} SmDbServiceT; + +// **************************************************************************** +// Database Services - Convert +// =========================== +extern SmErrorT sm_db_services_convert( const char* col_name, + const char* col_data, void* data ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Read +// ======================== +extern SmErrorT sm_db_services_read( SmDbHandleT* sm_db_handle, + char name[], SmDbServiceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Read By Identifier +// ====================================== +extern SmErrorT sm_db_services_read_by_id( SmDbHandleT* sm_db_handle, + int64_t id, SmDbServiceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Query +// ========================= +extern SmErrorT sm_db_services_query( SmDbHandleT* sm_db_handle, + const char* db_query, SmDbServiceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Insert +// ========================== +extern SmErrorT sm_db_services_insert( SmDbHandleT* sm_db_handle, + SmDbServiceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Update +// ========================== +extern SmErrorT sm_db_services_update( SmDbHandleT* sm_db_handle, + SmDbServiceT* record ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Delete +// ========================== +extern SmErrorT sm_db_services_delete( SmDbHandleT* sm_db_handle, + char name[] ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Create Table +// ================================ +extern SmErrorT sm_db_services_create_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Delete Table +// ================================ +extern SmErrorT sm_db_services_delete_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Cleanup Table +// ================================= +extern SmErrorT sm_db_services_cleanup_table( SmDbHandleT* sm_db_handle ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Initialize +// ============================== +extern SmErrorT sm_db_services_initialize( void ); +// **************************************************************************** + +// **************************************************************************** +// Database Services - Finalize +// ============================ +extern SmErrorT sm_db_services_finalize( void ); +// **************************************************************************** + +#ifdef __cplusplus +} +#endif + +#endif // __SM_DB_SERVICES_H__ diff --git a/service-mgmt/sm-db-1.0.0/upgrades/README b/service-mgmt/sm-db-1.0.0/upgrades/README new file mode 100644 index 00000000..2b86bd22 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/upgrades/README @@ -0,0 +1,31 @@ +The SM database can be generated off of an excel spreadsheet +(cgcs-root/addons/wr-cgcs/layers/mwa-thales/service-mgmt/sm-db-1.0.0/database/sm_database.xlsb) + +Instructions: +1. Update the SM excel spreadsheet (sm_database.xlsb) with your changes, +2. Update the SM database (sm.db.v1) with your changes: + sqlite3 sm.db.v1 + .tables + apply our changes using SQL statements + record the SQL statements for Crucible review (i.e. in commit.txt and in Crucible) + .quit +3. Update Packstack "sm-configure" calls were appropriate. +4. Update Packstack "sm-provision" and "sm-deprovision" calls were appropriate. +5. If your service runs during Packstack manifest apply, you may need to make + sure it is stopped before SM takes over. + +See packstack/puppet/templates/platform_sm_stopresources.pp +See packstack/puppet/templates/platform_sm_stopservice.pp + +OBSOLETE: + + CONTROLLER=192.168.204.4 + + mkdir -p /var/lib/sm/patches/ + + scp new-service root@${CONTROLLER}:/etc/init.d + scp sm_db_upgrade.patch root@${CONTROLLER}:/var/lib/sm/patches/ + + chmod 777 /etc/init.d/new-service + sm-patch database running sm_db_upgrade.patch + diff --git a/service-mgmt/sm-db-1.0.0/upgrades/new-service b/service-mgmt/sm-db-1.0.0/upgrades/new-service new file mode 100644 index 00000000..ec472df2 --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/upgrades/new-service @@ -0,0 +1,33 @@ +#! /bin/bash +# +# Copyright (c) 2015 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +DAEMON_PID_FILE="/var/run/new-service.pid" + +case "$1" in + start) + touch ${DAEMON_PID_FILE} + exit 0 + ;; + stop) + rm -f ${DAEMON_PID_FILE} + exit 0 + ;; + status) + if [ -e ${DAEMON_PID_FILE} ] + then + exit 0 + else + exit 3 + fi + ;; + *) + echo "Usage: $0 {start|stop|status}" + exit 1 + ;; +esac + +exit 0 diff --git a/service-mgmt/sm-db-1.0.0/upgrades/sm_db_upgrade.patch b/service-mgmt/sm-db-1.0.0/upgrades/sm_db_upgrade.patch new file mode 100644 index 00000000..bf1853ce --- /dev/null +++ b/service-mgmt/sm-db-1.0.0/upgrades/sm_db_upgrade.patch @@ -0,0 +1,62 @@ +# +# Copyright (c) 2015 Wind River Systems, Inc. +# SPDX-License-Identifier: Apache-2.0 +# +# +# +# + +UPDATE "SERVICE_DOMAINS_V1" SET GENERATION = 2; + +# Add a new service to an existing service-group +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(100,'yes','controller-services','new-service','critical'); +INSERT INTO "SERVICES_V1" VALUES(100,'yes','new-service','initial','initial','none','none',2,1,60000,4,16,''); + +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('new-service','enable','lsb-script','','new-service','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('new-service','disable','lsb-script','','new-service','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('new-service','audit-enabled','lsb-script','','new-service','status','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('new-service','audit-disabled','lsb-script','','new-service','status','',0,0,0,20,5); + +INSERT INTO "SERVICE_INSTANCES_V1" VALUES(100,'new-service','new-service',''); + + +# Add a new service-group and service +INSERT INTO "SERVICE_DOMAIN_MEMBERS_V1" VALUES(101,'yes','controller','new-services2','N + M',1,1,'controller-aggregate','directory-services'); +INSERT INTO "SERVICE_GROUPS_V1" VALUES(101,'yes','new-services2','no','no','initial','initial','none','none',300000,'yes'); +INSERT INTO "SERVICE_GROUP_MEMBERS_V1" VALUES(101,'yes','new-services2','new-service2','critical'); +INSERT INTO "SERVICES_V1" VALUES(101,'yes','new-service2','initial','initial','none','none',2,1,60000,4,16,''); + +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('new-service2','enable','lsb-script','','new-service','start','',2,2,2,20,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('new-service2','disable','lsb-script','','new-service','stop','',1,1,1,20,''); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('new-service2','audit-enabled','lsb-script','','new-service','status','',2,2,2,20,5); +INSERT INTO "SERVICE_ACTIONS_V1" VALUES('new-service2','audit-disabled','lsb-script','','new-service','status','',0,0,0,20,5); + +INSERT INTO "SERVICE_INSTANCES_V1" VALUES(101,'new-service2','new-service2',''); + +# +# sqlite3 /var/run/sm/sm.db.v1 +# UPDATE "SERVICE_DOMAINS_V1" SET GENERATION = 1; +# .quit +# + +# +# sqlite3 /var/run/sm/sm.db.v1 +# DELETE FROM "SERVICE_GROUP_MEMBERS_V1" WHERE NAME = 'controller-services' AND SERVICE_NAME = 'new-service'; +# DELETE FROM "SERVICES_V1" WHERE NAME = 'new-service'; +# DELETE FROM "SERVICE_ACTIONS_V1" WHERE SERVICE_NAME = 'new-service'; +# DELETE FROM "SERVICE_INSTANCES_V1" WHERE SERVICE_NAME = 'new-service'; +# .quit +# + +# +# sqlite3 /var/run/sm/sm.db.v1 +# DELETE FROM "SERVICE_DOMAIN_ASSIGNMENTS_V1" WHERE NAME = 'controller' AND SERVICE_GROUP_NAME = 'new-services2'; +# DELETE FROM "SERVICE_DOMAIN_MEMBERS_V1" WHERE NAME = 'controller' AND SERVICE_GROUP_NAME = 'new-services2'; +# DELETE FROM "SERVICE_GROUPS_V1" WHERE NAME = 'new-services2'; +# DELETE FROM "SERVICE_GROUP_MEMBERS_V1" WHERE NAME = 'new-services2' AND SERVICE_NAME = 'new-service2'; +# DELETE FROM "SERVICES_V1" WHERE NAME = 'new-service2'; +# DELETE FROM "SERVICE_ACTIONS_V1" WHERE SERVICE_NAME = 'new-service2'; +# DELETE FROM "SERVICE_INSTANCES_V1" WHERE SERVICE_NAME = 'new-service2'; +# .quit +# +