%-*-Mode:erlang;coding:utf-8;tab-width:4;c-basic-offset:4;indent-tabs-mode:()-*- % ex: set ft=erlang fenc=utf-8 sts=4 ts=4 sw=4 et nomod: %%% %%%------------------------------------------------------------------------ %%% @doc %%% ==CloudI Service API Module== %%% A module that exposes dynamic configuration of CloudI. %%% @end %%% %%% MIT License %%% %%% Copyright (c) 2011-2021 Michael Truog %%% %%% Permission is hereby granted, free of charge, to any person obtaining a %%% copy of this software and associated documentation files (the "Software"), %%% to deal in the Software without restriction, including without limitation %%% the rights to use, copy, modify, merge, publish, distribute, sublicense, %%% and/or sell copies of the Software, and to permit persons to whom the %%% Software is furnished to do so, subject to the following conditions: %%% %%% The above copyright notice and this permission notice shall be included in %%% all copies or substantial portions of the Software. %%% %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR %%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, %%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE %%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER %%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING %%% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER %%% DEALINGS IN THE SOFTWARE. %%% %%% @author Michael Truog %%% @copyright 2011-2021 Michael Truog %%% @version 2.0.3 {@date} {@time} %%%------------------------------------------------------------------------ -module(cloudi_service_api). -author('mjtruog at protonmail dot com'). %% external interface -export([acl_add/2, acl_remove/2, acl/1, service_subscriptions/2, services_add/2, services_remove/2, services_restart/2, services_suspend/2, services_resume/2, services_search/2, services_status/2, services_update/2, services/1, nodes_set/2, nodes_get/1, nodes_add/2, nodes_remove/2, nodes_alive/1, nodes_dead/1, nodes_status/2, nodes/1, logging_set/2, logging_file_set/2, logging_level_set/2, logging_stdout_set/2, logging_syslog_set/2, logging_formatters_set/2, logging_redirect_set/2, logging_status/1, logging_status_reset/1, logging/1, code_path_add/2, code_path_remove/2, code_path/1, code_status/1]). -include("cloudi_service_api.hrl"). -include("cloudi_core_i_constants.hrl"). -type dest_refresh() :: lazy_closest | immediate_closest | lazy_furthest | immediate_furthest | lazy_random | immediate_random | lazy_local | immediate_local | lazy_remote | immediate_remote | lazy_newest | immediate_newest | lazy_oldest | immediate_oldest | none. -export_type([dest_refresh/0]). -type priority() :: ?PRIORITY_HIGH..?PRIORITY_LOW. -export_type([priority/0]). -type dest_refresh_delay_milliseconds() :: ?DEST_REFRESH_DELAY_MIN..?DEST_REFRESH_DELAY_MAX. -export_type([dest_refresh_delay_milliseconds/0]). -type timeout_initialize_value_milliseconds() :: ?TIMEOUT_INITIALIZE_MIN..?TIMEOUT_INITIALIZE_MAX. -type timeout_initialize_milliseconds() :: limit_min | limit_max | timeout_initialize_value_milliseconds(). -export_type([timeout_initialize_value_milliseconds/0, timeout_initialize_milliseconds/0]). -type timeout_send_async_value_milliseconds() :: ?TIMEOUT_SEND_ASYNC_MIN..?TIMEOUT_SEND_ASYNC_MAX. -type timeout_send_async_milliseconds() :: limit_min | limit_max | timeout_send_async_value_milliseconds(). -export_type([timeout_send_async_value_milliseconds/0, timeout_send_async_milliseconds/0]). -type timeout_send_sync_value_milliseconds() :: ?TIMEOUT_SEND_SYNC_MIN..?TIMEOUT_SEND_SYNC_MAX. -type timeout_send_sync_milliseconds() :: limit_min | limit_max | timeout_send_sync_value_milliseconds(). -export_type([timeout_send_sync_value_milliseconds/0, timeout_send_sync_milliseconds/0]). -type timeout_terminate_value_milliseconds() :: ?TIMEOUT_TERMINATE_MIN..?TIMEOUT_TERMINATE_MAX. -type timeout_terminate_milliseconds() :: limit_min | limit_max | timeout_terminate_value_milliseconds(). -export_type([timeout_terminate_value_milliseconds/0, timeout_terminate_milliseconds/0]). -type request_timeout_immediate_max_value_milliseconds() :: 0..?TIMEOUT_MAX_ERLANG. -type request_timeout_immediate_max_milliseconds() :: limit_min | limit_max | request_timeout_immediate_max_value_milliseconds(). -export_type([request_timeout_immediate_max_value_milliseconds/0, request_timeout_immediate_max_milliseconds/0]). -type response_timeout_immediate_max_value_milliseconds() :: 0..?TIMEOUT_MAX_ERLANG. -type response_timeout_immediate_max_milliseconds() :: limit_min | limit_max | response_timeout_immediate_max_value_milliseconds(). -export_type([response_timeout_immediate_max_value_milliseconds/0, response_timeout_immediate_max_milliseconds/0]). -type restart_delay_value_milliseconds() :: 0..?TIMEOUT_MAX_ERLANG. -type restart_delay_milliseconds() :: limit_min | limit_max | restart_delay_value_milliseconds(). -export_type([restart_delay_value_milliseconds/0, restart_delay_milliseconds/0]). -type latency_mean_time_value_milliseconds() :: 0..?TIMEOUT_MAX_ERLANG. -type latency_mean_time_milliseconds() :: limit_min | limit_max | latency_mean_time_value_milliseconds(). -type latency_min_time_value_milliseconds() :: 0..?TIMEOUT_MAX_ERLANG. -type latency_min_time_milliseconds() :: limit_min | limit_max | latency_min_time_value_milliseconds(). -type latency_max_time_value_milliseconds() :: 1..?TIMEOUT_MAX_ERLANG. -type latency_max_time_milliseconds() :: limit_min | limit_max | latency_max_time_value_milliseconds(). -type latency_time_value_milliseconds() :: 1..?TIMEOUT_MAX_ERLANG. -type latency_time_milliseconds() :: limit_min | limit_max | latency_time_value_milliseconds(). -export_type([latency_mean_time_value_milliseconds/0, latency_mean_time_milliseconds/0, latency_min_time_value_milliseconds/0, latency_min_time_milliseconds/0, latency_max_time_value_milliseconds/0, latency_max_time_milliseconds/0, latency_time_value_milliseconds/0, latency_time_milliseconds/0]). -type acl() :: list(atom() | cloudi:service_name_pattern()). -export_type([acl/0]). -type dest_list() :: acl() | undefined. -export_type([dest_list/0]). -type seconds() :: non_neg_integer(). -export_type([seconds/0]). -type period_seconds() :: 1..(?TIMEOUT_MAX_ERLANG div 1000). -export_type([period_seconds/0]). -type aspect_init_after_internal_f() :: fun((Args :: list(), Prefix :: cloudi_service:service_name_pattern(), Timeout :: timeout_initialize_value_milliseconds(), State :: any(), Dispatcher :: cloudi_service:dispatcher()) -> {ok, StateNew :: any()} | {stop, Reason :: any(), StateNew :: any()}). -type aspect_init_after_external_f() :: fun((CommandLine :: list(string()), Prefix :: cloudi:service_name_pattern(), Timeout :: timeout_initialize_value_milliseconds(), State :: any()) -> {ok, StateNew :: any()} | {stop, Reason :: any(), StateNew :: any()}). -type aspect_init_after_internal() :: aspect_init_after_internal_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type aspect_init_after_external() :: aspect_init_after_external_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -export_type([aspect_init_after_internal_f/0, aspect_init_after_external_f/0, aspect_init_after_internal/0, aspect_init_after_external/0]). -type aspect_request_before_internal_f() :: fun((RequestType :: cloudi_service:request_type(), Name :: cloudi_service:service_name(), Pattern :: cloudi_service:service_name_pattern(), RequestInfo :: cloudi_service:request_info(), Request :: cloudi_service:request(), Timeout :: cloudi_service:timeout_value_milliseconds(), Priority :: cloudi_service:priority(), TransId :: cloudi_service:trans_id(), Source :: cloudi_service:source(), State :: any(), Dispatcher :: cloudi_service:dispatcher()) -> {ok, StateNew :: any()} | {stop, Reason :: any(), StateNew :: any()}). -type aspect_request_before_external_f() :: fun((RequestType :: cloudi_service:request_type(), Name :: cloudi_service:service_name(), Pattern :: cloudi_service:service_name_pattern(), RequestInfo :: cloudi_service:request_info(), Request :: cloudi_service:request(), Timeout :: cloudi_service:timeout_value_milliseconds(), Priority :: cloudi_service:priority(), TransId :: cloudi_service:trans_id(), Source :: cloudi_service:source(), State :: any()) -> {ok, StateNew :: any()} | {stop, Reason :: any(), StateNew :: any()}). -type aspect_request_after_internal_f() :: fun((RequestType :: cloudi_service:request_type(), Name :: cloudi_service:service_name(), Pattern :: cloudi_service:service_name_pattern(), RequestInfo :: cloudi_service:request_info(), Request :: cloudi_service:request(), Timeout :: cloudi_service:timeout_value_milliseconds(), Priority :: cloudi_service:priority(), TransId :: cloudi_service:trans_id(), Source :: cloudi_service:source(), Result :: cloudi_service:request_result(), State :: any(), Dispatcher :: cloudi_service:dispatcher()) -> {ok, StateNew :: any()} | {stop, Reason :: any(), StateNew :: any()}). -type aspect_request_after_external_f() :: fun((RequestType :: cloudi_service:request_type(), Name :: cloudi_service:service_name(), Pattern :: cloudi_service:service_name_pattern(), RequestInfo :: cloudi_service:request_info(), Request :: cloudi_service:request(), Timeout :: cloudi_service:timeout_value_milliseconds(), Priority :: cloudi_service:priority(), TransId :: cloudi_service:trans_id(), Source :: cloudi_service:source(), Result :: cloudi_service:request_result(), State :: any()) -> {ok, StateNew :: any()} | {stop, Reason :: any(), StateNew :: any()}). -type aspect_request_before_internal() :: aspect_request_before_internal_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type aspect_request_before_external() :: aspect_request_before_external_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type aspect_request_after_internal() :: aspect_request_after_internal_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type aspect_request_after_external() :: aspect_request_after_external_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -export_type([aspect_request_before_internal_f/0, aspect_request_before_external_f/0, aspect_request_after_internal_f/0, aspect_request_after_external_f/0, aspect_request_before_internal/0, aspect_request_before_external/0, aspect_request_after_internal/0, aspect_request_after_external/0]). -type aspect_info_internal_f() :: fun((Request :: any(), State :: any(), Dispatcher :: cloudi_service:dispatcher()) -> {ok, StateNew :: any()} | {stop, Reason :: any(), StateNew :: any()}). -type aspect_info_internal() :: aspect_info_internal_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type aspect_info_before_internal_f() :: aspect_info_internal_f(). -type aspect_info_after_internal_f() :: aspect_info_internal_f(). -type aspect_info_before_internal() :: aspect_info_internal(). -type aspect_info_after_internal() :: aspect_info_internal(). -export_type([aspect_info_before_internal_f/0, aspect_info_after_internal_f/0, aspect_info_before_internal/0, aspect_info_after_internal/0]). -type aspect_terminate_f() :: fun((Reason :: any(), Timeout :: timeout_terminate_value_milliseconds(), State :: any()) -> {ok, State :: any()}). -type aspect_terminate_before_internal_f() :: aspect_terminate_f(). -type aspect_terminate_before_external_f() :: aspect_terminate_f(). -type aspect_terminate_before_internal() :: aspect_terminate_before_internal_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type aspect_terminate_before_external() :: aspect_terminate_before_external_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -export_type([aspect_terminate_before_internal_f/0, aspect_terminate_before_external_f/0, aspect_terminate_before_internal/0, aspect_terminate_before_external/0]). -type aspect_suspend_f() :: fun((State :: any()) -> {ok, State :: any()}). -type aspect_suspend() :: aspect_suspend_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type aspect_resume_f() :: fun((State :: any()) -> {ok, State :: any()}). -type aspect_resume() :: aspect_resume_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -export_type([aspect_suspend_f/0, aspect_suspend/0, aspect_resume_f/0, aspect_resume/0]). -type max_heap_size_options() :: non_neg_integer() | #{size => non_neg_integer(), kill => boolean(), error_logger => boolean()}. -export_type([max_heap_size_options/0]). -type file_path() :: nonempty_string(). -type limit_external_key() :: as | core | cpu | data | fsize | memlock | msgqueue | nice | nofile | nproc | rss | rtprio | rttime | sigpending | stack | vmem. -type limit_external_value() :: undefined | non_neg_integer() | infinity | % sets current list({current, non_neg_integer() | infinity} | {maximum, non_neg_integer() | infinity}). -type limit_external() :: system | list({limit_external_key(), limit_external_value()}). -type owner_external() :: list({user, pos_integer() | string()} | {group, pos_integer() | string()}). -type nice_external() :: -20..20. -type cgroup_external() :: undefined | list({name, nonempty_string()} | {parameters, list({nonempty_string(), string()})} | {update_or_create, boolean()}). -type chroot_external() :: file_path() | undefined. -type syscall_lock_external_type() :: pledge | function. -type syscall_lock_external() :: undefined | list({type, syscall_lock_external_type()} | {names, nonempty_list(nonempty_string())}). -type directory_external() :: file_path() | undefined. -export_type([file_path/0, limit_external_key/0, limit_external_value/0, limit_external/0, owner_external/0, nice_external/0, cgroup_external/0, chroot_external/0, syscall_lock_external_type/0, syscall_lock_external/0, directory_external/0]). -type service_options_rate_request_max_options() :: list({period, period_seconds()} | {value, number()}). -type service_options_count_process_dynamic_options() :: list({period, period_seconds()} | {rate_request_max, number()} | {rate_request_min, number()} | {count_max, number()} | {count_min, number()}). -type service_options_restart_delay_options() :: list({time_exponential_min, restart_delay_milliseconds()} | {time_exponential_max, restart_delay_milliseconds()} | {time_linear_min, restart_delay_milliseconds()} | {time_linear_slope, restart_delay_milliseconds()} | {time_linear_max, restart_delay_milliseconds()} | {time_absolute, restart_delay_milliseconds()}). -type service_options_monkey_latency_options() :: list({time_uniform_min, latency_min_time_milliseconds()} | {time_uniform_max, latency_max_time_milliseconds()} | {time_gaussian_mean, latency_mean_time_milliseconds()} | {time_gaussian_stddev, float() | pos_integer()} | {time_absolute, latency_time_milliseconds()}). -type service_options_monkey_chaos_options() :: list({probability_request, float()} | {probability_day, float()}). -type service_options_internal_hibernate_options() :: list({period, period_seconds()} | {rate_request_min, number()}). -type service_options_internal() :: list({priority_default, priority()} | {queue_limit, undefined | non_neg_integer()} | {queue_size, undefined | pos_integer()} | {rate_request_max, service_options_rate_request_max_options() | number() | undefined} | {dest_refresh_start, dest_refresh_delay_milliseconds()} | {dest_refresh_delay, dest_refresh_delay_milliseconds()} | {request_name_lookup, sync | async} | {request_timeout_adjustment, boolean()} | {request_timeout_immediate_max, request_timeout_immediate_max_milliseconds()} | {response_timeout_adjustment, boolean()} | {response_timeout_immediate_max, response_timeout_immediate_max_milliseconds()} | {count_process_dynamic, service_options_count_process_dynamic_options() | false} | {timeout_terminate, undefined | timeout_terminate_milliseconds()} | {restart_all, boolean()} | {restart_delay, service_options_restart_delay_options() | false} | {scope, atom()} | {monkey_latency, service_options_monkey_latency_options() | system | false} | {monkey_chaos, service_options_monkey_chaos_options() | system | false} | {automatic_loading, boolean()} | {dispatcher_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {aspects_init_after, list(aspect_init_after_internal())} | {aspects_request_before, list(aspect_request_before_internal())} | {aspects_request_after, list(aspect_request_after_internal())} | {aspects_info_before, list(aspect_info_before_internal())} | {aspects_info_after, list(aspect_info_after_internal())} | {aspects_terminate_before, list(aspect_terminate_before_internal())} | {aspects_suspend, list(aspect_suspend())} | {aspects_resume, list(aspect_resume())} | {application_name, undefined | atom()} | {init_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {request_pid_uses, infinity | pos_integer()} | {request_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {info_pid_uses, infinity | pos_integer()} | {info_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {duo_mode, boolean()} | {hibernate, service_options_internal_hibernate_options() | boolean()} | {reload, boolean()}). -type service_options_external() :: list({priority_default, ?PRIORITY_HIGH..?PRIORITY_LOW} | {queue_limit, undefined | non_neg_integer()} | {queue_size, undefined | pos_integer()} | {rate_request_max, service_options_rate_request_max_options() | number() | undefined} | {dest_refresh_start, dest_refresh_delay_milliseconds()} | {dest_refresh_delay, dest_refresh_delay_milliseconds()} | {request_name_lookup, sync | async} | {request_timeout_adjustment, boolean()} | {request_timeout_immediate_max, request_timeout_immediate_max_milliseconds()} | {response_timeout_adjustment, boolean()} | {response_timeout_immediate_max, response_timeout_immediate_max_milliseconds()} | {count_process_dynamic, service_options_count_process_dynamic_options() | false} | {timeout_terminate, undefined | timeout_terminate_milliseconds()} | {restart_all, boolean()} | {restart_delay, service_options_restart_delay_options() | false} | {scope, atom()} | {monkey_latency, service_options_monkey_latency_options() | system | false} | {monkey_chaos, service_options_monkey_chaos_options() | system | false} | {automatic_loading, boolean()} | {dispatcher_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {aspects_init_after, list(aspect_init_after_external())} | {aspects_request_before, list(aspect_request_before_external())} | {aspects_request_after, list(aspect_request_after_external())} | {aspects_terminate_before, list(aspect_terminate_before_external())} | {aspects_suspend, list(aspect_suspend())} | {aspects_resume, list(aspect_resume())} | {limit, limit_external()} | {owner, owner_external()} | {nice, nice_external()} | {cgroup, cgroup_external()} | {chroot, chroot_external()} | {directory, directory_external()}). -export_type([service_options_rate_request_max_options/0, service_options_count_process_dynamic_options/0, service_options_restart_delay_options/0, service_options_monkey_latency_options/0, service_options_monkey_chaos_options/0, service_options_internal_hibernate_options/0, service_options_internal/0, service_options_external/0]). -type service_id() :: <<_:128>>. % version 1 UUID (service instance id) -type service_internal() :: #internal{}. -type service_external() :: #external{}. -type service_proplist() :: nonempty_list({type, internal | external} | {prefix, cloudi:service_name_pattern()} | {module, atom() | file_path()} | {file_path, file_path()} | {args, list()} | {env, list({string(), string()})} | {dest_refresh, dest_refresh()} | {protocol, 'default' | 'local' | 'tcp' | 'udp'} | {buffer_size, 'default' | pos_integer()} | {timeout_init, timeout_initialize_value_milliseconds()} | {timeout_async, timeout_send_async_value_milliseconds()} | {timeout_sync, timeout_send_sync_value_milliseconds()} | {dest_list_deny, dest_list()} | {dest_list_allow, dest_list()} | {count_process, pos_integer() | float()} | {count_thread, pos_integer() | float()} | {max_r, non_neg_integer()} | {max_t, seconds()} | {options, service_options_internal() | service_options_external()}). -type service() :: #internal{} | #external{}. -export_type([service_id/0, service_internal/0, service_external/0, service_proplist/0, service/0]). % `"99.9999998 %"' -type availability() :: nonempty_list($0..$9 | $. | $ | $%). % `"< 99.9999998 %"' -type availability_approx() :: nonempty_list($0..$9 | $. | $ | $% | $<). % `"126 days 19 hours 1563 seconds 557199569 nanoseconds"' -type nanoseconds_string() :: nonempty_list($a..$z | $0..$9 | $ ). % `"+ 350 nanoseconds"' -type nanoseconds_string_signed() :: nonempty_list($a..$z | $0..$9 | $ | $+ | $-). % `"> 126 days 19 hours 1563 seconds 557199569 nanoseconds"' -type nanoseconds_string_approx_gt() :: nonempty_list($a..$z | $0..$9 | $ | $>). % `"< 1563 seconds 557199569 nanoseconds"' -type nanoseconds_string_approx_lt() :: nonempty_list($a..$z | $0..$9 | $ | $<). % `"126 days 19 hours 1563 seconds"' -type seconds_string() :: nonempty_list($a..$z | $0..$9 | $ ). % `"+ 10 seconds"' -type seconds_string_signed() :: nonempty_list($a..$z | $0..$9 | $ | $+ | $-). % `"0"' -type integer_string_ge_0() :: nonempty_list($0..$9). % `"11"' -type integer_string_gt_0() :: nonempty_list($0..$9). % `"0.0"' -type float_string_ge_0() :: nonempty_list($0..$9 | $.). -export_type([availability/0, availability_approx/0, nanoseconds_string/0, nanoseconds_string_signed/0, nanoseconds_string_approx_gt/0, nanoseconds_string_approx_lt/0, seconds_string/0, seconds_string_signed/0, integer_string_ge_0/0, integer_string_gt_0/0, float_string_ge_0/0]). -type service_status_internal() :: nonempty_list({type, internal} | {prefix, cloudi:service_name_pattern()} | {module, atom()} | {count_process, pos_integer()} | {pids_erlang, list(pid())} | {suspended, boolean()} | {uptime_total, nanoseconds_string()} | {uptime_running, nanoseconds_string()} | {uptime_processing, nanoseconds_string_approx_lt()} | {uptime_restarts, integer_string_ge_0()} | {downtime_day_restarting, nanoseconds_string_approx_gt()} | {downtime_week_restarting, nanoseconds_string_approx_gt()} | {downtime_month_restarting, nanoseconds_string_approx_gt()} | {downtime_year_restarting, nanoseconds_string_approx_gt()} | {interrupt_day_updating, nanoseconds_string_approx_gt()} | {interrupt_week_updating, nanoseconds_string_approx_gt()} | {interrupt_month_updating, nanoseconds_string_approx_gt()} | {interrupt_year_updating, nanoseconds_string_approx_gt()} | {interrupt_day_suspended, nanoseconds_string_approx_gt()} | {interrupt_week_suspended, nanoseconds_string_approx_gt()} | {interrupt_month_suspended, nanoseconds_string_approx_gt()} | {interrupt_year_suspended, nanoseconds_string_approx_gt()} | {availability_day_total, availability_approx()} | {availability_day_running, availability()} | {availability_day_updated, availability_approx()} | {availability_day_processing, availability_approx()} | {availability_week_total, availability_approx()} | {availability_week_running, availability()} | {availability_week_updated, availability_approx()} | {availability_week_processing, availability_approx()} | {availability_month_total, availability_approx()} | {availability_month_running, availability()} | {availability_month_updated, availability_approx()} | {availability_month_processing, availability_approx()} | {availability_year_total, availability_approx()} | {availability_year_running, availability()} | {availability_year_updated, availability_approx()} | {availability_year_processing, availability_approx()}). -type service_status_external() :: nonempty_list({type, external} | {prefix, cloudi:service_name_pattern()} | {file_path, file_path()} | {count_process, pos_integer()} | {count_thread, pos_integer()} | {pids_os, list(pos_integer())} | {pids_erlang, list(pid())} | {suspended, boolean()} | {uptime_total, nanoseconds_string()} | {uptime_running, nanoseconds_string()} | {uptime_processing, nanoseconds_string_approx_lt()} | {uptime_restarts, integer_string_ge_0()} | {downtime_day_restarting, nanoseconds_string_approx_gt()} | {downtime_week_restarting, nanoseconds_string_approx_gt()} | {downtime_month_restarting, nanoseconds_string_approx_gt()} | {downtime_year_restarting, nanoseconds_string_approx_gt()} | {interrupt_day_updating, nanoseconds_string_approx_gt()} | {interrupt_week_updating, nanoseconds_string_approx_gt()} | {interrupt_month_updating, nanoseconds_string_approx_gt()} | {interrupt_year_updating, nanoseconds_string_approx_gt()} | {interrupt_day_suspended, nanoseconds_string_approx_gt()} | {interrupt_week_suspended, nanoseconds_string_approx_gt()} | {interrupt_month_suspended, nanoseconds_string_approx_gt()} | {interrupt_year_suspended, nanoseconds_string_approx_gt()} | {availability_day_total, availability_approx()} | {availability_day_running, availability()} | {availability_day_updated, availability_approx()} | {availability_day_processing, availability_approx()} | {availability_week_total, availability_approx()} | {availability_week_running, availability()} | {availability_week_updated, availability_approx()} | {availability_week_processing, availability_approx()} | {availability_month_total, availability_approx()} | {availability_month_running, availability()} | {availability_month_updated, availability_approx()} | {availability_month_processing, availability_approx()} | {availability_year_total, availability_approx()} | {availability_year_running, availability()} | {availability_year_updated, availability_approx()} | {availability_year_processing, availability_approx()}). -type service_status() :: service_status_internal() | service_status_external(). -export_type([service_status_internal/0, service_status_external/0, service_status/0]). -type module_version() :: list(any()). -type module_state_internal_f() :: fun((ModuleVersionOld :: module_version(), ModuleVersionNew :: module_version(), StateOld :: any()) -> {ok, StateNew :: any()} | {error, Reason :: any()}). -type module_state_internal() :: module_state_internal_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type service_update_plan_internal() :: nonempty_list({type, internal} | {module, atom()} | {module_state, module_state_internal()} | {sync, boolean()} | {modules_load, list(atom())} | {modules_unload, list(atom())} | {code_paths_add, list(string())} | {code_paths_remove, list(string())} | {dest_refresh, dest_refresh()} | {timeout_init, timeout_initialize_milliseconds()} | {timeout_async, timeout_send_async_milliseconds()} | {timeout_sync, timeout_send_sync_milliseconds()} | {dest_list_deny, dest_list()} | {dest_list_allow, dest_list()} | {options, service_update_plan_options_internal()}). -type service_update_plan_external() :: nonempty_list({type, external} | {file_path, file_path()} | {args, string()} | {env, list({string(), string()})} | {sync, boolean()} | {modules_load, list(atom())} | {modules_unload, list(atom())} | {code_paths_add, list(string())} | {code_paths_remove, list(string())} | {dest_refresh, dest_refresh()} | {timeout_init, timeout_initialize_milliseconds()} | {timeout_async, timeout_send_async_milliseconds()} | {timeout_sync, timeout_send_sync_milliseconds()} | {dest_list_deny, dest_list()} | {dest_list_allow, dest_list()} | {options, service_update_plan_options_external()}). -type service_update_plan_options_internal() :: list({priority_default, priority()} | {queue_limit, undefined | non_neg_integer()} | {queue_size, undefined | pos_integer()} | {rate_request_max, service_options_rate_request_max_options() | number() | undefined} | {dest_refresh_start, dest_refresh_delay_milliseconds()} | {dest_refresh_delay, dest_refresh_delay_milliseconds()} | {request_name_lookup, sync | async} | {request_timeout_adjustment, boolean()} | {request_timeout_immediate_max, request_timeout_immediate_max_milliseconds()} | {response_timeout_adjustment, boolean()} | {response_timeout_immediate_max, response_timeout_immediate_max_milliseconds()} | {monkey_latency, service_options_monkey_latency_options() | system | false} | {monkey_chaos, service_options_monkey_chaos_options() | system | false} | {dispatcher_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {aspects_init_after, list(aspect_init_after_internal())} | {aspects_request_before, list(aspect_request_before_internal())} | {aspects_request_after, list(aspect_request_after_internal())} | {aspects_info_before, list(aspect_info_before_internal())} | {aspects_info_after, list(aspect_info_after_internal())} | {aspects_terminate_before, list(aspect_terminate_before_internal())} | {aspects_suspend, list(aspect_suspend())} | {aspects_resume, list(aspect_resume())} | {init_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {request_pid_uses, infinity | pos_integer()} | {request_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {info_pid_uses, infinity | pos_integer()} | {info_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {hibernate, list({period, period_seconds()} | {rate_request_min, number()}) | boolean()} | {reload, boolean()}). -type service_update_plan_options_external() :: list({priority_default, ?PRIORITY_HIGH..?PRIORITY_LOW} | {queue_limit, undefined | non_neg_integer()} | {queue_size, undefined | pos_integer()} | {rate_request_max, service_options_rate_request_max_options() | number() | undefined} | {dest_refresh_start, dest_refresh_delay_milliseconds()} | {dest_refresh_delay, dest_refresh_delay_milliseconds()} | {request_name_lookup, sync | async} | {request_timeout_adjustment, boolean()} | {request_timeout_immediate_max, request_timeout_immediate_max_milliseconds()} | {response_timeout_adjustment, boolean()} | {response_timeout_immediate_max, response_timeout_immediate_max_milliseconds()} | {monkey_latency, service_options_monkey_latency_options() | system | false} | {monkey_chaos, service_options_monkey_chaos_options() | system | false} | {dispatcher_pid_options, list({priority, low | normal | high} | {fullsweep_after, non_neg_integer()} | {min_heap_size, non_neg_integer()} | {min_bin_vheap_size, non_neg_integer()} | {max_heap_size, max_heap_size_options()} | {sensitive, boolean()} | {message_queue_data, off_heap | on_heap})} | {aspects_init_after, list(aspect_init_after_external())} | {aspects_request_before, list(aspect_request_before_external())} | {aspects_request_after, list(aspect_request_after_external())} | {aspects_terminate_before, list(aspect_terminate_before_external())} | {aspects_suspend, list(aspect_suspend())} | {aspects_resume, list(aspect_resume())}). -type service_update_plan() :: service_update_plan_internal() | service_update_plan_external(). -export_type([module_version/0, module_state_internal_f/0, module_state_internal/0, service_update_plan/0]). -type node_reconnect_delay_seconds() :: period_seconds(). -export_type([node_reconnect_delay_seconds/0]). -type nodes_properties() :: node() | {nodes, list(node())} | {reconnect_start, node_reconnect_delay_seconds()} | {reconnect_delay, node_reconnect_delay_seconds()} | {listen, visible | all} | {connect, visible | hidden} | {timestamp_type, erlang | os | warp} | {discovery, list({ec2, list({address, inet:ip_address()} | {port, inet:port_number()} | {ttl, non_neg_integer()})} | {multicast, list({access_key_id, string()} | {secret_access_key, string()} | {ec2_host, string()} | {groups, list(string())} | {tags, list({string(), string()} | string())})})} | {cost, list({node() | default, float()})} | {cost_precision, 0..253} | {log_reconnect, loglevel()}. -type nodes_proplist() :: list(nodes_properties()). -type nodes_set_proplist() :: nonempty_list({set, all | local} | nodes_properties()). -type node_status_local() :: nonempty_list({services_running, integer_string_ge_0()} | {services_restarted, integer_string_ge_0()} | {services_failed, integer_string_ge_0()} | {uptime, nanoseconds_string()} | {uptime_cost_total, float_string_ge_0()} | {uptime_cost_day, float_string_ge_0()} | {uptime_cost_week, float_string_ge_0()} | {uptime_cost_month, float_string_ge_0()} | {uptime_cost_year, float_string_ge_0()} | {availability_day, availability()} | {availability_week, availability()} | {availability_month, availability()} | {availability_year, availability()}). -type node_status_remote() :: nonempty_list({tracked, nanoseconds_string()} | {tracked_cost_total, float_string_ge_0()} | {tracked_cost_day, float_string_ge_0()} | {tracked_cost_week, float_string_ge_0()} | {tracked_cost_month, float_string_ge_0()} | {tracked_cost_year, float_string_ge_0()} | {connection, visible | hidden} | {tracked_disconnects, integer_string_ge_0()} | {disconnected, boolean()} | {downtime_day_disconnected, nanoseconds_string_approx_gt()} | {downtime_week_disconnected, nanoseconds_string_approx_gt()} | {downtime_month_disconnected, nanoseconds_string_approx_gt()} | {downtime_year_disconnected, nanoseconds_string_approx_gt()} | {availability_day, availability_approx()} | {availability_week, availability_approx()} | {availability_month, availability_approx()} | {availability_year, availability_approx()}). -type node_status() :: node_status_local() | node_status_remote(). -type nodes_status() :: nonempty_list({node(), node_status()}). -export_type([nodes_proplist/0, nodes_set_proplist/0, node_status_local/0, node_status_remote/0, node_status/0, nodes_status/0]). -type aspect_log_f() :: fun((Level :: loglevel_on(), Timestamp :: erlang:timestamp(), Node :: node(), Pid :: pid(), Module :: module(), Line :: pos_integer(), Function :: atom() | undefined, Arity :: arity() | undefined, MetaData :: list({atom(), any()}) | #{}, LogMessage :: iodata()) -> ok). -type aspect_log_before() :: aspect_log_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -type aspect_log_after() :: aspect_log_f() | {Module :: module(), Function :: atom()} | {{Module :: module(), Function :: atom()}}. -export_type([aspect_log_f/0, aspect_log_before/0, aspect_log_after/0]). -type loglevel() :: loglevel_on() | off. -type loglevel_on() :: fatal | error | warn | info | debug | trace. -type logging_syslog_identity() :: nonempty_string(). -type logging_syslog_facility() :: kernel | user | mail | daemon | auth0 | syslog | print | news | uucp | clock0 | auth1 | ftp | ntp | auth2 | auth3 | clock1 | local0 | local1 | local2 | local3 | local4 | local5 | local6 | local7 | non_neg_integer() | % common aliases auth | authpriv | cron | kern | lpr | security. -type logging_syslog_transport() :: local | udp | tcp | tls. -type logging_syslog_transport_options() :: list(). -type logging_syslog_protocol() :: rfc3164 | rfc5424. -type logging_syslog_path() :: nonempty_string(). -type logging_syslog_host() :: inet:ip_address() | inet:hostname(). -type logging_syslog_port() :: undefined | inet:port_number(). -type logging_syslog_set_proplist() :: list({identity, logging_syslog_identity()} | {facility, logging_syslog_facility()} | {level, loglevel() | undefined} | {transport, logging_syslog_transport()} | {transport_options, logging_syslog_transport_options()} | {protocol, logging_syslog_protocol()} | {path, logging_syslog_path()} | {host, logging_syslog_host()} | {port, logging_syslog_port()}). -type logging_formatters_set_proplist() :: list({any | nonempty_list(module()), list(fatal | error | warn | info | debug | trace | emergency | alert | critical | warning | notice | {level, fatal | error | warn | info | debug | trace | emergency | alert | critical | warning | notice} | {output, module() | undefined} | {output_args, list()} | {output_max_r, non_neg_integer()} | {output_max_t, cloudi_service_api:seconds()} | {formatter, module() | undefined} | {formatter_config, list()})}). -type iso8601() :: cloudi_timestamp:iso8601(). -type iso8601_seconds() :: cloudi_timestamp:iso8601_seconds(). % `"+3.104690100 seconds"' -type seconds_change_string() :: nonempty_list($a..$z | $0..$9 | $. | $ | $+ | $-). -type logging_status() :: list({queue_mode, async | sync | overload} | {queue_mode_sync_last_start, iso8601()} | {queue_mode_sync_last_start_event, iso8601()} | {queue_mode_sync_last_end, iso8601()} | {queue_mode_sync_last_end_event, iso8601()} | {queue_mode_sync_last_total, nanoseconds_string()} | {queue_mode_overload_last_start, iso8601()} | {queue_mode_overload_last_start_event, iso8601()} | {queue_mode_overload_last_end, iso8601()} | {queue_mode_overload_last_end_event, iso8601()} | {queue_mode_overload_last_total, nanoseconds_string()} | {time_offset_last_change, seconds_change_string()} | {time_offset_last_event, iso8601()} | {file_messages_fatal, integer_string_gt_0()} | {file_messages_error, integer_string_gt_0()} | {file_messages_warn, integer_string_gt_0()} | {file_messages_info, integer_string_gt_0()} | {file_messages_debug, integer_string_gt_0()} | {file_messages_trace, integer_string_gt_0()} | {file_sync_fail_count, integer_string_gt_0()} | {file_sync_fail_types, nonempty_list(atom())} | {file_write_fail_count, integer_string_gt_0()} | {file_write_fail_types, nonempty_list(atom())} | {file_read_fail_count, integer_string_gt_0()} | {file_read_fail_types, nonempty_list(atom())}). -type logging_proplist() :: nonempty_list({file, string() | undefined} | {level, loglevel()} | {redirect, node() | undefined} | {syslog, logging_syslog_set_proplist() | undefined} | {stdout, boolean()} | {queue_mode_async, pos_integer()} | {queue_mode_sync, pos_integer()} | {queue_mode_overload, pos_integer()} | {formatters, logging_formatters_set_proplist() | undefined} | {log_time_offset, loglevel()} | {aspects_log_before, list(aspect_log_before())} | {aspects_log_after, list(aspect_log_after())}). -export_type([loglevel/0, loglevel_on/0, logging_syslog_identity/0, logging_syslog_facility/0, logging_syslog_transport/0, logging_syslog_transport_options/0, logging_syslog_protocol/0, logging_syslog_path/0, logging_syslog_host/0, logging_syslog_port/0, logging_syslog_set_proplist/0, logging_formatters_set_proplist/0, seconds_change_string/0, logging_status/0, logging_proplist/0]). -type code_status_runtime_change() :: nonempty_list({type, internal | external} | {file_age, seconds_string()} | {file_path, file_path()} | {service_ids, nonempty_list(service_id())}). -type code_status() :: nonempty_list({build_machine, nonempty_string()} | {build_kernel_version, nonempty_string()} | {build_operating_system, nonempty_string()} | {build_erlang_otp_release, nonempty_string()} | {build_cloudi_time, nonempty_string()} | {build_cloudi_cxx_compiler_version, nonempty_string()} | {build_cloudi_cxx_dependencies_versions, nonempty_string()} | {build_erts_c_compiler_version, nonempty_string()} | {install_erlang_erts_time, iso8601_seconds()} | {install_erlang_kernel_time, iso8601_seconds()} | {install_erlang_stdlib_time, iso8601_seconds()} | {install_erlang_sasl_time, iso8601_seconds()} | {install_erlang_compiler_time, iso8601_seconds()} | {install_cloudi_time, iso8601_seconds()} | {runtime_erlang_erts_version, nonempty_string()} | {runtime_erlang_kernel_version, nonempty_string()} | {runtime_erlang_stdlib_version, nonempty_string()} | {runtime_erlang_sasl_version, nonempty_string()} | {runtime_erlang_compiler_version, nonempty_string()} | {runtime_erlang_compilation, nonempty_string()} | {runtime_cloudi_version, nonempty_string()} | {runtime_machine_processors, pos_integer()} | {runtime_start, iso8601()} | {runtime_clock, iso8601()} | {runtime_clock_offset, nanoseconds_string_signed()} | {runtime_total, nanoseconds_string()} | {runtime_cloudi_start, iso8601()} | {runtime_cloudi_total, nanoseconds_string()} | {runtime_cloudi_changes, list(code_status_runtime_change())}). -export_type([code_status_runtime_change/0, code_status/0]). %%%------------------------------------------------------------------------ %%% External interface functions %%%------------------------------------------------------------------------ % timeout for the functions below -define(TIMEOUT_SERVICE_API_MIN, ?TIMEOUT_DELTA + 1). -define(TIMEOUT_SERVICE_API_MAX, ?TIMEOUT_MAX_ERLANG). -type api_timeout_milliseconds() :: ?TIMEOUT_SERVICE_API_MIN..?TIMEOUT_SERVICE_API_MAX | infinity. -export_type([api_timeout_milliseconds/0]). %%------------------------------------------------------------------------- %% @doc %% ===Add ACL entries.=== %% Add more ACL entries to be later used when starting services. An ACL %% entry is an Erlang atom() -> list(atom() | string()) relationship which %% provides a logical grouping of service name patterns %% (e.g., {api, ["/cloudi/api/"]}). When providing a service name pattern %% for an ACL entry, a non-pattern will be assumed to be a prefix %% (i.e., "/cloudi/api/" == "/cloudi/api/*"). %% @end %%------------------------------------------------------------------------- -spec acl_add(L :: nonempty_list({atom(), acl()}), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_acl_add()}. acl_add([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:acl_add(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Remove ACL entries.=== %% Remove ACL entries that are no longer needed. Running services will %% retain their configuration, so this impacts services that are started %% in the future. %% @end %%------------------------------------------------------------------------- -spec acl_remove(L :: nonempty_list(atom()), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_acl_remove()}. acl_remove([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:acl_remove(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===List all ACL entries.=== %% @end %%------------------------------------------------------------------------- -spec acl(Timeout :: api_timeout_milliseconds()) -> {ok, list({atom(), list(cloudi_service:service_name_pattern())})} | {error, timeout | noproc}. acl(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:acl(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Get a list of all service subscriptions.=== %% When a subscription on the same service name pattern occurred %% multiple times, only a single entry is returned within the list. %% Service name patterns that are subscriptions of non-service Erlang pids %% (e.g., cloudi_service_http_cowboy websocket connection pids) will not %% be returned by this function. %% @end %%------------------------------------------------------------------------- -spec service_subscriptions(ServiceId :: binary() | string(), Timeout :: api_timeout_milliseconds()) -> {ok, list(cloudi_service:service_name_pattern())} | {error, timeout | noproc | {service_id_invalid, any()} | not_found}. service_subscriptions(ServiceId, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> case service_id_convert(ServiceId) of {ok, ServiceIdValid} -> cloudi_core_i_configurator:service_subscriptions(ServiceIdValid, Timeout); {error, _} = Error -> Error end. %%------------------------------------------------------------------------- %% @doc %% ===Add service instances.=== %% Provide service configuration using the same syntax found in the %% configuration file (i.e., /usr/local/etc/cloudi/cloudi.conf). %% @end %%------------------------------------------------------------------------- -spec services_add(L :: nonempty_list({internal, _, _, _, _, _, _, _, _, _, _, _, _, _} | {external, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _, _} | service_proplist()), Timeout :: api_timeout_milliseconds()) -> {ok, nonempty_list(service_id())} | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_services_add()}. services_add([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:services_add(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Remove service instances.=== %% Provide the Service UUIDs for the services that should be stopped. %% The Service UUID is shown in the output of services/1. When the %% service is stopped, its running instance is removed from CloudI, but %% does not impact any other running instances (even if they are the same %% service module or binary). %% @end %%------------------------------------------------------------------------- -spec services_remove(L :: nonempty_list(binary() | string()), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | {service_id_invalid, any()} | cloudi_core_i_configuration:error_reason_services_remove()}. services_remove([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> case service_ids_convert(L) of {ok, ServiceIdsValid} -> cloudi_core_i_configurator:services_remove(ServiceIdsValid, Timeout); {error, _} = Error -> Error end. %%------------------------------------------------------------------------- %% @doc %% ===Restart service instances.=== %% Provide the Service UUIDs for the services that should be restarted. %% The Service UUID is shown in the output of services/1. When the service %% is restarted, the old instance is stopped and a new instance is started. %% During the restart delay, it is possible to lose queued service %% requests and received asynchronous responses. Keeping the state %% separate between the service instances is important to prevent failures %% within the new instance. %% @end %%------------------------------------------------------------------------- -spec services_restart(L :: nonempty_list(binary() | string()), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | {service_id_invalid, any()} | cloudi_core_i_configuration:error_reason_services_restart()}. services_restart([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> case service_ids_convert(L) of {ok, ServiceIdsValid} -> cloudi_core_i_configurator:services_restart(ServiceIdsValid, Timeout); {error, _} = Error -> Error end. %%------------------------------------------------------------------------- %% @doc %% ===Suspend service instances.=== %% Provide the Service UUIDs for the services that should be suspended. %% The Service UUID is shown in the output of services/1. %% @end %%------------------------------------------------------------------------- -spec services_suspend(L :: nonempty_list(binary() | string()), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | {service_id_invalid, any()} | cloudi_core_i_configuration:error_reason_services_suspend()}. services_suspend([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> case service_ids_convert(L) of {ok, ServiceIdsValid} -> cloudi_core_i_configurator:services_suspend(ServiceIdsValid, Timeout); {error, _} = Error -> Error end. %%------------------------------------------------------------------------- %% @doc %% ===Resume service instances.=== %% Provide the Service UUIDs for the services that should be resumed. %% The Service UUID is shown in the output of services/1. %% @end %%------------------------------------------------------------------------- -spec services_resume(L :: nonempty_list(binary() | string()), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | {service_id_invalid, any()} | cloudi_core_i_configuration:error_reason_services_resume()}. services_resume([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> case service_ids_convert(L) of {ok, ServiceIdsValid} -> cloudi_core_i_configurator:services_resume(ServiceIdsValid, Timeout); {error, _} = Error -> Error end. %%------------------------------------------------------------------------- %% @doc %% ===Search service instances for matches on the provided service name.=== %% Multiple services may be returned for a single service name. Only service %% instances on the local Erlang node are searched. Service names that match %% subscriptions of non-service Erlang pids only %% (e.g., cloudi_service_http_cowboy websocket connection pids) will not %% return the service's configuration with this function. Provide a scope %% within a 2 element tuple with the service name to check a custom scope. %% @end %%------------------------------------------------------------------------- -spec services_search(Name :: {atom(), cloudi:service_name()} | cloudi:service_name(), Timeout :: api_timeout_milliseconds()) -> {ok, list({service_id(), service_internal()} | {service_id(), service_external()})} | {error, timeout | noproc | service_name_invalid | cloudi_core_i_configuration:error_reason_services_search()}. services_search(Name, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> {Scope, ServiceName} = case Name of {ScopeValue, [_ | _] = ServiceNameValue} when is_atom(ScopeValue) -> {?SCOPE_ASSIGN(ScopeValue), ServiceNameValue}; [_ | _] = ServiceNameValue -> {?SCOPE_DEFAULT, ServiceNameValue} end, try trie:is_pattern2_bytes(ServiceName) of false -> cloudi_core_i_configurator:services_search(Scope, ServiceName, Timeout); true -> {error, service_name_invalid} catch exit:badarg -> {error, service_name_invalid} end. %%------------------------------------------------------------------------- %% @doc %% ===List the current status of specific services.=== %% @end %%------------------------------------------------------------------------- -spec services_status(L :: list(binary() | string()), Timeout :: api_timeout_milliseconds()) -> {ok, nonempty_list({service_id(), service_status()})} | {error, timeout | noproc | {service_id_invalid, any()} | {service_not_found, any()}}. services_status(L, Timeout) when is_list(L), ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> ServiceIdsResult = case service_ids_convert(L) of {ok, []} -> cloudi_core_i_configurator:service_ids(Timeout); ServiceIdsResultValue -> ServiceIdsResultValue end, case ServiceIdsResult of {ok, ServiceIdsValid} -> cloudi_core_i_services_monitor:status(ServiceIdsValid, Timeout); {error, _} = Error -> Error end. %%------------------------------------------------------------------------- %% @doc %% ===Update service instances.=== %% Update service instances without losing service requests and other %% service-specific data within the Erlang VM. %% @end %%------------------------------------------------------------------------- -spec services_update(L :: nonempty_list({string() | binary(), service_update_plan()}), Timeout :: api_timeout_milliseconds()) -> {ok, ServiceIdsSetsSuccess :: nonempty_list(nonempty_list(service_id()))} | {error, {ServiceIdsSetError :: nonempty_list(service_id()), Reason :: {service_internal_update_failed | service_external_update_failed, any()}}, ServiceIdsSetsSuccess :: nonempty_list(nonempty_list(service_id()))} | {error, timeout | noproc | {service_id_invalid, any()} | cloudi_core_i_configuration:error_reason_services_update()}. services_update([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> case service_ids_convert_update(L) of {ok, LNew} -> cloudi_core_i_configurator:services_update(LNew, Timeout); {error, _} = Error -> Error end. %%------------------------------------------------------------------------- %% @doc %% ===List all service instances with each service's UUID.=== %% @end %%------------------------------------------------------------------------- -spec services(Timeout :: api_timeout_milliseconds()) -> {ok, list({service_id(), service_internal()} | {service_id(), service_external()})} | {error, timeout | noproc}. services(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:services(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Set CloudI nodes configuration.=== %% @end %%------------------------------------------------------------------------- -spec nodes_set(L :: nodes_set_proplist(), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_nodes_set()}. nodes_set([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:nodes_set(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Get CloudI nodes configuration.=== %% @end %%------------------------------------------------------------------------- -spec nodes_get(Timeout :: api_timeout_milliseconds()) -> {ok, nodes_proplist()} | {error, timeout | noproc}. nodes_get(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:nodes_get(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Add CloudI nodes.=== %% Explicitly add a CloudI node name, so that services between all other %% CloudI nodes and the added nodes can send each other service requests. %% @end %%------------------------------------------------------------------------- -spec nodes_add(L :: nonempty_list(node()), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_nodes_add()}. nodes_add([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:nodes_add(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Explicitly remove CloudI nodes.=== %% The node must be currently dead to be removed. %% @end %%------------------------------------------------------------------------- -spec nodes_remove(L :: nonempty_list(node()), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_nodes_remove()}. nodes_remove([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:nodes_remove(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===List all the CloudI nodes known to be connected.=== %% @end %%------------------------------------------------------------------------- -spec nodes_alive(Timeout :: api_timeout_milliseconds()) -> {ok, list(node())} | {error, timeout | noproc}. nodes_alive(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_nodes:alive(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===List all the CloudI nodes that are disconnected but expected to reconnect.=== %% @end %%------------------------------------------------------------------------- -spec nodes_dead(Timeout :: api_timeout_milliseconds()) -> {ok, list(node())} | {error, timeout | noproc}. nodes_dead(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_nodes:dead(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===List the current status of specific nodes.=== %% @end %%------------------------------------------------------------------------- -spec nodes_status(L :: list(node()), Timeout :: api_timeout_milliseconds()) -> {ok, nodes_status()} | {error, timeout | noproc | {node_not_found, any()}}. nodes_status(L, Timeout) when is_list(L), ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> case cloudi_core_i_nodes:status(L, Timeout) of {ok, NodesStatus} -> nodes_status_local_services(NodesStatus, Timeout); {error, _} = Error -> Error end. %%------------------------------------------------------------------------- %% @doc %% ===List both the connected and disconnected CloudI nodes.=== %% @end %%------------------------------------------------------------------------- -spec nodes(Timeout :: api_timeout_milliseconds()) -> {ok, list(node())} | {error, timeout | noproc}. nodes(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_nodes:nodes(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Set CloudI logging configuration.=== %% @end %%------------------------------------------------------------------------- -spec logging_set(L :: logging_proplist(), Timeout :: api_timeout_milliseconds()) -> ok | {error, file:posix() | badarg | system_limit}. logging_set([_ | _] = L, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:logging_set(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Modify the current log file path.=== %% @end %%------------------------------------------------------------------------- -spec logging_file_set(FilePath :: string() | undefined, Timeout :: api_timeout_milliseconds()) -> ok | {error, file:posix() | badarg | system_limit}. logging_file_set(FilePath, Timeout) when ((FilePath =:= undefined) orelse (is_list(FilePath) andalso is_integer(hd(FilePath)))), ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:logging_file_set(FilePath, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Modify the current loglevel.=== %% CloudI uses asynchronous logging with flow control (backpressure %% handling) to prevent misbehaving services from causing instability. %% @end %%------------------------------------------------------------------------- -spec logging_level_set(Level :: loglevel() | undefined, Timeout :: api_timeout_milliseconds()) -> ok. logging_level_set(Level, Timeout) when ((Level =:= fatal) orelse (Level =:= error) orelse (Level =:= warn) orelse (Level =:= info) orelse (Level =:= debug) orelse (Level =:= trace) orelse (Level =:= off) orelse (Level =:= undefined)), ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:logging_level_set(Level, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Modify the current log stdout usage.=== %% @end %%------------------------------------------------------------------------- -spec logging_stdout_set(Stdout :: boolean(), Timeout :: api_timeout_milliseconds()) -> ok. logging_stdout_set(Stdout, Timeout) when is_boolean(Stdout), ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:logging_stdout_set(Stdout, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Set the CloudI syslog configuration.=== %% @end %%------------------------------------------------------------------------- -spec logging_syslog_set(L :: logging_syslog_set_proplist() | undefined, Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_logging_syslog_set()}. logging_syslog_set(L, Timeout) when is_list(L) orelse (L =:= undefined), ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:logging_syslog_set(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Set the CloudI log formatters.=== %% lager backend (gen_event) modules are supported as 'output' modules and %% lager formatter modules are supported with or without an 'output' %% module specified. %% @end %%------------------------------------------------------------------------- -spec logging_formatters_set(L :: logging_formatters_set_proplist() | undefined, Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_logging_formatters_set()}. logging_formatters_set(L, Timeout) when is_list(L) orelse (L =:= undefined), ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:logging_formatters_set(L, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Redirect the log output.=== %% Redirect all local log output to a remote CloudI node. %% Use 'undefined' as the node name to log locally. %% @end %%------------------------------------------------------------------------- -spec logging_redirect_set(Node :: undefined | node(), Timeout :: api_timeout_milliseconds()) -> ok. logging_redirect_set(Node, Timeout) when is_atom(Node), ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:logging_redirect_set(Node, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Provide the current logging status.=== %% @end %%------------------------------------------------------------------------- -spec logging_status(Timeout :: api_timeout_milliseconds()) -> {ok, logging_status()} | {error, timeout | noproc}. logging_status(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_logger:status(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Reset the logging status.=== %% @end %%------------------------------------------------------------------------- -spec logging_status_reset(Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc}. logging_status_reset(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_logger:status_reset(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Provide the current logging configuration.=== %% @end %%------------------------------------------------------------------------- -spec logging(Timeout :: api_timeout_milliseconds()) -> {ok, logging_proplist()} | {error, timeout | noproc}. logging(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:logging(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Add a directory to the CloudI Erlang VM code server's search paths.=== %% The path is always appended to the list of search paths (you should not %% need to rely on search path order because of unique naming). %% @end %%------------------------------------------------------------------------- -spec code_path_add(Dir :: file_path(), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_code_path_add()}. code_path_add(Dir, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:code_path_add(Dir, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Remove a directory from the CloudI Erlang VM code server's search paths.=== %% This doesn't impact any running services, only services that will be %% started in the future. %% @end %%------------------------------------------------------------------------- -spec code_path_remove(Dir :: file_path(), Timeout :: api_timeout_milliseconds()) -> ok | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_code_path_remove()}. code_path_remove(Dir, Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:code_path_remove(Dir, Timeout). %%------------------------------------------------------------------------- %% @doc %% ===List all the CloudI Erlang VM code server search paths.=== %% The order is the same order the directories are searched. %% @end %%------------------------------------------------------------------------- -spec code_path(Timeout :: api_timeout_milliseconds()) -> {ok, nonempty_list(file_path())} | {error, timeout | noproc}. code_path(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> cloudi_core_i_configurator:code_path(Timeout). %%------------------------------------------------------------------------- %% @doc %% ===Provide the current CloudI Erlang VM code status.=== %% Both build and runtime information is provided with the %% service files changed after CloudI was started %% (probably due to service updates). %% @end %%------------------------------------------------------------------------- -spec code_status(Timeout :: api_timeout_milliseconds()) -> {ok, code_status()} | {error, timeout | noproc | cloudi_core_i_configuration:error_reason_code_status()}. code_status(Timeout) when ((is_integer(Timeout) andalso (Timeout >= ?TIMEOUT_SERVICE_API_MIN) andalso (Timeout =< ?TIMEOUT_SERVICE_API_MAX)) orelse (Timeout =:= infinity)) -> TimeNative = cloudi_timestamp:native_monotonic(), TimeOffset = erlang:time_offset(), TimeOS = cloudi_timestamp:native_os(), TimeNativeStart = erlang:system_info(start_time), TimeNativeTotal = TimeNative - TimeNativeStart, TimeNativeNow = TimeNative + TimeOffset, case cloudi_core_i_configurator:code_status(TimeNative, TimeOffset, Timeout) of {ok, TimeNativeConfig, RuntimeChanges} -> MicroSecondsStart = cloudi_timestamp: convert(TimeNativeStart + TimeOffset, native, microsecond), MicroSecondsNow = cloudi_timestamp: convert(TimeNativeNow, native, microsecond), NanoSecondsOffset = cloudi_timestamp: convert(TimeOS - TimeNativeNow, native, nanosecond), NanoSecondsTotal = cloudi_timestamp: convert(TimeNativeTotal, native, nanosecond), MicroSecondsStartConfig = cloudi_timestamp: convert(TimeNativeConfig + TimeOffset, native, microsecond), NanoSecondsTotalConfig = cloudi_timestamp: convert(TimeNative - TimeNativeConfig, native, nanosecond), Status = cloudi_environment:status() ++ [{runtime_start, cloudi_timestamp: microseconds_epoch_to_string(MicroSecondsStart)}, {runtime_clock, cloudi_timestamp: microseconds_epoch_to_string(MicroSecondsNow)}, {runtime_clock_offset, cloudi_timestamp: nanoseconds_to_string(NanoSecondsOffset, signed)}, {runtime_total, cloudi_timestamp: nanoseconds_to_string(NanoSecondsTotal)}, {runtime_cloudi_start, cloudi_timestamp: microseconds_epoch_to_string(MicroSecondsStartConfig)}, {runtime_cloudi_total, cloudi_timestamp: nanoseconds_to_string(NanoSecondsTotalConfig)}, {runtime_cloudi_changes, RuntimeChanges}], {ok, Status}; {error, _} = Error -> Error end. %%%------------------------------------------------------------------------ %%% Private functions %%%------------------------------------------------------------------------ nodes_status_local_services(NodesStatus, Timeout) -> nodes_status_local_services(NodesStatus, [], Timeout). nodes_status_local_services([], L, _) -> {ok, lists:reverse(L)}; nodes_status_local_services([{Node, StatusList} | NodesStatus], L, Timeout) when Node =:= node() -> case cloudi_core_i_services_monitor:node_status(Timeout) of {ok, LocalStatusList} -> {ok, lists:reverse(L, [{Node, LocalStatusList ++ StatusList} | NodesStatus])}; {error, _} = Error -> Error end; nodes_status_local_services([NodeStatus | NodesStatus], L, Timeout) -> nodes_status_local_services(NodesStatus, [NodeStatus | L], Timeout). service_ids_convert_update(L) -> service_ids_convert_update(L, []). service_ids_convert_update([], Output) -> {ok, lists:reverse(Output)}; service_ids_convert_update([{<<>>, _} = Entry | L], Output) -> service_ids_convert_update(L, [Entry | Output]); service_ids_convert_update([{"", Plan} | L], Output) -> service_ids_convert_update(L, [{<<>>, Plan} | Output]); service_ids_convert_update([{ServiceId, Plan} | L], Output) -> case service_id_convert(ServiceId) of {ok, ServiceIdValid} -> service_ids_convert_update(L, [{ServiceIdValid, Plan} | Output]); {error, _} = Error -> Error end; service_ids_convert_update([Entry | _], _) -> {error, {update_invalid, Entry}}. service_ids_convert(ServiceIds) -> service_ids_convert(ServiceIds, []). service_ids_convert([], Output) -> {ok, lists:reverse(Output)}; service_ids_convert([ServiceId | ServiceIds], Output) -> case service_id_convert(ServiceId) of {ok, ServiceIdValid} -> service_ids_convert(ServiceIds, [ServiceIdValid | Output]); {error, _} = Error -> Error end. service_id_convert(ServiceId) when is_binary(ServiceId), byte_size(ServiceId) == 16 -> {ok, ServiceId}; service_id_convert(ServiceId) -> try uuid:string_to_uuid(ServiceId) of ServiceIdValid -> {ok, ServiceIdValid} catch exit:badarg -> {error, {service_id_invalid, ServiceId}} end.