diff --git a/doc/content/design/host-ntp-time.md b/doc/content/design/host-ntp-time.md index 3a3309ac9c0..8770e404141 100644 --- a/doc/content/design/host-ntp-time.md +++ b/doc/content/design/host-ntp-time.md @@ -38,8 +38,7 @@ cache for the getter APIs. New fields: `host.ntp_mode`, enum host_ntp_mode(DHCP, Custom, Factory, Disabled) -`host.ntp_custom_servers`, string set -`host.ntp_enabled`, bool +`host.ntp_custom_servers`, string set New APIs: `host.set_ntp_mode`, `host.set_ntp_custom_servers`, `host.get_ntp_mode`, `host.get_ntp_custom_servers`, `host.get_ntp_servers_status` @@ -201,7 +200,6 @@ host.timezone host.set_timezone host.list_timezones host.get_timezone -host.get_ntp_enabled host.get_ntp_synchronized host.set_ntp_mode host.get_ntp_mode diff --git a/ocaml/idl/datamodel_common.ml b/ocaml/idl/datamodel_common.ml index 12c548580b1..2d51f5b5714 100644 --- a/ocaml/idl/datamodel_common.ml +++ b/ocaml/idl/datamodel_common.ml @@ -10,7 +10,7 @@ open Datamodel_roles to leave a gap for potential hotfixes needing to increment the schema version.*) let schema_major_vsn = 5 -let schema_minor_vsn = 791 +let schema_minor_vsn = 792 (* Historical schema versions just in case this is useful later *) let rio_schema_major_vsn = 5 diff --git a/ocaml/idl/datamodel_host.ml b/ocaml/idl/datamodel_host.ml index 0caa87793ea..afbdfbacb74 100644 --- a/ocaml/idl/datamodel_host.ml +++ b/ocaml/idl/datamodel_host.ml @@ -2579,11 +2579,10 @@ let host_ntp_mode = Enum ( "host_ntp_mode" , [ - ("ntp_mode_dhcp", "Using NTP servers assigned by DHCP to sync time") - ; ( "ntp_mode_custom" - , "Using custom NTP servers configured by user to sync time" - ) - ; ("ntp_mode_default", "Using default NTP servers to sync time") + ("DHCP", "Using NTP servers assigned by DHCP to sync time") + ; ("Custom", "Using custom NTP servers configured by user to sync time") + ; ("Factory", "Using built-in NTP servers to sync time") + ; ("Disabled", "NTP is disabled on the host") ] ) @@ -2606,16 +2605,6 @@ let set_ntp_custom_servers = ] ~allowed_roles:_R_POOL_OP () -let disable_ntp = - call ~name:"disable_ntp" ~lifecycle:[] ~doc:"Disable NTP on the host" - ~params:[(Ref _host, "self", "The host")] - ~allowed_roles:_R_POOL_OP () - -let enable_ntp = - call ~name:"enable_ntp" ~lifecycle:[] ~doc:"Enable NTP on the host" - ~params:[(Ref _host, "self", "The host")] - ~allowed_roles:_R_POOL_OP () - let get_ntp_servers_status = call ~name:"get_ntp_servers_status" ~lifecycle:[] ~doc:"Get the NTP servers status on the host" @@ -2822,8 +2811,6 @@ let t = ; set_max_cstate ; set_ntp_mode ; set_ntp_custom_servers - ; disable_ntp - ; enable_ntp ; get_ntp_servers_status ; set_timezone ; list_timezones @@ -3297,15 +3284,12 @@ let t = ~default_value:(Some (VBool false)) "secure_boot" "Whether the host has booted in secure boot mode" ; field ~qualifier:DynamicRO ~lifecycle:[] ~ty:host_ntp_mode - ~default_value:(Some (VEnum "ntp_mode_dhcp")) "ntp_mode" + ~default_value:(Some (VEnum "Factory")) "ntp_mode" "Indicates NTP servers are assigned by DHCP, or configured by \ - user, or the default servers" + user, or the factory servers, or NTP is disabled" ; field ~qualifier:DynamicRO ~lifecycle:[] ~ty:(Set String) ~default_value:(Some (VSet [])) "ntp_custom_servers" - "The set of NTP servers configured for the host" - ; field ~qualifier:DynamicRO ~lifecycle:[] ~ty:Bool - ~default_value:(Some (VBool false)) "ntp_enabled" - "Reflects whether NTP is enabled on the host" + "Custom NTP servers configured by users, used in Custom NTP mode" ; field ~qualifier:DynamicRO ~lifecycle:[] ~ty:String ~default_value:(Some (VString "UTC")) "timezone" "The time zone identifier as defined in the IANA Time Zone Database" diff --git a/ocaml/idl/datamodel_lifecycle.ml b/ocaml/idl/datamodel_lifecycle.ml index a98e52d1dd0..38b68763627 100644 --- a/ocaml/idl/datamodel_lifecycle.ml +++ b/ocaml/idl/datamodel_lifecycle.ml @@ -97,8 +97,16 @@ let prototyped_of_field = function Some "22.26.0" | "SM", "host_pending_features" -> Some "24.37.0" + | "host", "timezone" -> + Some "25.37.0-next" + | "host", "ntp_custom_servers" -> + Some "25.37.0-next" + | "host", "ntp_mode" -> + Some "25.37.0-next" | "host", "secure_boot" -> Some "25.31.0" + | "host", "max_cstate" -> + Some "25.37.0-next" | "host", "ssh_auto_mode" -> Some "25.27.0" | "host", "console_idle_timeout" -> @@ -225,6 +233,22 @@ let prototyped_of_message = function Some "22.26.0" | "VTPM", "create" -> Some "22.26.0" + | "host", "set_servertime" -> + Some "25.37.0-next" + | "host", "get_ntp_synchronized" -> + Some "25.37.0-next" + | "host", "list_timezones" -> + Some "25.37.0-next" + | "host", "set_timezone" -> + Some "25.37.0-next" + | "host", "get_ntp_servers_status" -> + Some "25.37.0-next" + | "host", "set_ntp_custom_servers" -> + Some "25.37.0-next" + | "host", "set_ntp_mode" -> + Some "25.37.0-next" + | "host", "set_max_cstate" -> + Some "25.37.0-next" | "host", "update_firewalld_service_status" -> Some "25.34.0" | "host", "get_tracked_user_agents" -> diff --git a/ocaml/idl/schematest.ml b/ocaml/idl/schematest.ml index 78af76524a2..e0658e78ac6 100644 --- a/ocaml/idl/schematest.ml +++ b/ocaml/idl/schematest.ml @@ -3,7 +3,7 @@ let hash x = Digest.string x |> Digest.to_hex (* BEWARE: if this changes, check that schema has been bumped accordingly in ocaml/idl/datamodel_common.ml, usually schema_minor_vsn *) -let last_known_schema_hash = "c72edb27945bceb074de3fa54381ddd4" +let last_known_schema_hash = "d8cb04ccddfd91ca3f0f9074dcf7c219" let current_schema_hash : string = let open Datamodel_types in diff --git a/ocaml/tests/common/test_common.ml b/ocaml/tests/common/test_common.ml index c71f57b72d7..9d5101999b3 100644 --- a/ocaml/tests/common/test_common.ml +++ b/ocaml/tests/common/test_common.ml @@ -224,8 +224,8 @@ let make_host2 ~__context ?(ref = Ref.make ()) ?(uuid = make_uuid ()) ~pending_guidances_recommended:[] ~pending_guidances_full:[] ~last_update_hash:"" ~ssh_enabled:true ~ssh_enabled_timeout:0L ~ssh_expiry:Date.epoch ~console_idle_timeout:0L ~ssh_auto_mode:false - ~max_cstate:"" ~secure_boot:false ~ntp_mode:`ntp_mode_dhcp - ~ntp_custom_servers:[] ~ntp_enabled:false ~timezone:"UTC" ; + ~max_cstate:"" ~secure_boot:false ~ntp_mode:`Factory ~ntp_custom_servers:[] + ~timezone:"UTC" ; ref let make_pif ~__context ~network ~host ?(device = "eth0") diff --git a/ocaml/xapi-cli-server/cli_frontend.ml b/ocaml/xapi-cli-server/cli_frontend.ml index aac42eef8b2..39e0c8ce51f 100644 --- a/ocaml/xapi-cli-server/cli_frontend.ml +++ b/ocaml/xapi-cli-server/cli_frontend.ml @@ -1098,24 +1098,6 @@ let rec cmdtable_data : (string * cmd_spec) list = ; flags= [Neverforward] } ) - ; ( "host-enable-ntp" - , { - reqd= [] - ; optn= [] - ; help= "Enable ntp service on the host." - ; implementation= No_fd Cli_operations.host_enable_ntp - ; flags= [Host_selectors] - } - ) - ; ( "host-disable-ntp" - , { - reqd= [] - ; optn= [] - ; help= "Disable ntp service on the host." - ; implementation= No_fd Cli_operations.host_disable_ntp - ; flags= [Host_selectors] - } - ) ; ( "patch-upload" , { reqd= ["file-name"] diff --git a/ocaml/xapi-cli-server/cli_operations.ml b/ocaml/xapi-cli-server/cli_operations.ml index 3b49f0cd589..eb6a0eb3a80 100644 --- a/ocaml/xapi-cli-server/cli_operations.ml +++ b/ocaml/xapi-cli-server/cli_operations.ml @@ -7820,26 +7820,6 @@ let host_disable_ssh _printer rpc session_id params = params [] ) -let host_enable_ntp _printer rpc session_id params = - ignore - (do_host_op rpc session_id - (fun _ host -> - let host = host.getref () in - Client.Host.enable_ntp ~rpc ~session_id ~self:host - ) - params [] - ) - -let host_disable_ntp _printer rpc session_id params = - ignore - (do_host_op rpc session_id - (fun _ host -> - let host = host.getref () in - Client.Host.disable_ntp ~rpc ~session_id ~self:host - ) - params [] - ) - module SDN_controller = struct let introduce printer rpc session_id params = let port = diff --git a/ocaml/xapi-cli-server/records.ml b/ocaml/xapi-cli-server/records.ml index 1ec8705f34d..4d3d19f5a22 100644 --- a/ocaml/xapi-cli-server/records.ml +++ b/ocaml/xapi-cli-server/records.ml @@ -3423,9 +3423,6 @@ let host_record rpc session_id host = ) ) () - ; make_field ~name:"ntp_enabled" - ~get:(fun () -> string_of_bool (x ()).API.host_ntp_enabled) - () ; make_field ~name:"timezone" ~get:(fun () -> (x ()).API.host_timezone) ~set:(fun value -> diff --git a/ocaml/xapi/message_forwarding.ml b/ocaml/xapi/message_forwarding.ml index 27e2d94c508..5f6c3a0d3bc 100644 --- a/ocaml/xapi/message_forwarding.ml +++ b/ocaml/xapi/message_forwarding.ml @@ -4152,18 +4152,6 @@ functor let remote_fn = Client.Host.set_ntp_custom_servers ~self ~value in do_op_on ~local_fn ~__context ~host:self ~remote_fn - let enable_ntp ~__context ~self = - info "Host.enable_ntp: host='%s'" (host_uuid ~__context self) ; - let local_fn = Local.Host.enable_ntp ~self in - let remote_fn = Client.Host.enable_ntp ~self in - do_op_on ~local_fn ~__context ~host:self ~remote_fn - - let disable_ntp ~__context ~self = - info "Host.disable_ntp: host='%s'" (host_uuid ~__context self) ; - let local_fn = Local.Host.disable_ntp ~self in - let remote_fn = Client.Host.disable_ntp ~self in - do_op_on ~local_fn ~__context ~host:self ~remote_fn - let get_ntp_servers_status ~__context ~self = info "Host.get_ntp_servers_status: host = '%s'" (host_uuid ~__context self) ; @@ -4195,7 +4183,7 @@ functor info "Host.set_servertime : host = '%s'; value = '%s'" (host_uuid ~__context self) (Clock.Date.to_rfc3339 value) ; - if Db.Host.get_ntp_enabled ~__context ~self then + if Db.Host.get_ntp_mode ~__context ~self <> `Disabled then raise (Api_errors.Server_error (Api_errors.not_allowed_when_ntp_is_enabled, [Ref.string_of self]) diff --git a/ocaml/xapi/xapi_globs.ml b/ocaml/xapi/xapi_globs.ml index a9021154bd0..e46cbb41d7a 100644 --- a/ocaml/xapi/xapi_globs.ml +++ b/ocaml/xapi/xapi_globs.ml @@ -1425,9 +1425,9 @@ let nvidia_gpumon_detach = ref false let failed_login_alert_freq = ref 3600 -let default_ntp_servers = ref [] +let factory_ntp_servers = ref [] -let legacy_default_ntp_servers = ref [] +let legacy_factory_ntp_servers = ref [] let other_options = [ @@ -1916,16 +1916,16 @@ let other_options = , (fun () -> !timedatectl) , "Path to the timedatectl executable" ) - ; gen_list_option "legacy-default-ntp-servers" + ; gen_list_option "legacy-factory-ntp-servers" "space-separated list of legacy default NTP servers" (fun s -> s) (fun s -> s) - legacy_default_ntp_servers - ; gen_list_option "default-ntp-servers" + legacy_factory_ntp_servers + ; gen_list_option "factory-ntp-servers" "space-separated list of default NTP servers" (fun s -> s) (fun s -> s) - default_ntp_servers + factory_ntp_servers ] (* The options can be set with the variable xapiflags in /etc/sysconfig/xapi. diff --git a/ocaml/xapi/xapi_host.ml b/ocaml/xapi/xapi_host.ml index ef12de4f739..cab55e2e05c 100644 --- a/ocaml/xapi/xapi_host.ml +++ b/ocaml/xapi/xapi_host.ml @@ -1094,8 +1094,8 @@ let create ~__context ~uuid ~name_label ~name_description:_ ~hostname ~address ~recommended_guidances:[] ~latest_synced_updates_applied:`unknown ~pending_guidances_recommended:[] ~pending_guidances_full:[] ~ssh_enabled ~ssh_enabled_timeout ~ssh_expiry ~console_idle_timeout ~ssh_auto_mode - ~max_cstate:"" ~secure_boot ~ntp_mode:`ntp_mode_dhcp ~ntp_custom_servers:[] - ~ntp_enabled:false ~timezone:"UTC" ; + ~max_cstate:"" ~secure_boot ~ntp_mode:`Factory ~ntp_custom_servers:[] + ~timezone:"UTC" ; (* If the host we're creating is us, make sure its set to live *) Db.Host_metrics.set_last_updated ~__context ~self:metrics ~value:(Date.now ()) ; Db.Host_metrics.set_live ~__context ~self:metrics ~value:host_is_us ; @@ -3471,90 +3471,90 @@ let sync_max_cstate ~__context ~host = let set_ntp_mode ~__context ~self ~value = let current_mode = Db.Host.get_ntp_mode ~__context ~self in - let ntp_enabled = Db.Host.get_ntp_enabled ~__context ~self in if current_mode <> value then ( let open Xapi_host_ntp in - let ensure_custom_servers_exist servers = + let ensure_servers_exist servers msg = if servers = [] then - raise - Api_errors.( - Server_error - ( invalid_ntp_config - , ["Can't set ntp_mode_custom when ntp_custom_servers is empty"] - ) - ) + raise Api_errors.(Server_error (invalid_ntp_config, [msg])) + in + let enter_mode = function + | `DHCP -> + add_dhcp_ntp_servers () + | `Custom -> + let custom_servers = + Db.Host.get_ntp_custom_servers ~__context ~self + in + ensure_servers_exist custom_servers + "Can't set ntp_mode to Custom when ntp_custom_servers is empty" ; + set_servers_in_conf custom_servers + | `Factory -> + let factory_servers = !Xapi_globs.factory_ntp_servers in + ensure_servers_exist factory_servers + "Can't set ntp_mode to Factory when factory ntp servers is empty" ; + set_servers_in_conf factory_servers + | `Disabled -> + () + in + let exit_mode = function + | `DHCP -> + remove_dhcp_ntp_servers () + | `Custom | `Factory -> + clear_servers_in_conf () + | `Disabled -> + () in - let default_servers = !Xapi_globs.default_ntp_servers in ( match (current_mode, value) with - | `ntp_mode_dhcp, `ntp_mode_custom -> - let custom_servers = Db.Host.get_ntp_custom_servers ~__context ~self in - ensure_custom_servers_exist custom_servers ; - remove_dhcp_ntp_servers () ; - set_servers_in_conf custom_servers - | `ntp_mode_default, `ntp_mode_custom -> - let custom_servers = Db.Host.get_ntp_custom_servers ~__context ~self in - ensure_custom_servers_exist custom_servers ; - set_servers_in_conf custom_servers - | _, `ntp_mode_dhcp -> - clear_servers_in_conf () ; add_dhcp_ntp_servers () - | `ntp_mode_dhcp, `ntp_mode_default -> - remove_dhcp_ntp_servers () ; - set_servers_in_conf default_servers - | `ntp_mode_custom, `ntp_mode_default -> - set_servers_in_conf default_servers - | _, _ -> - () + | `Disabled, next -> + enter_mode next ; enable_ntp_service () + | _, `Disabled -> + exit_mode current_mode ; disable_ntp_service () + | current, next -> + exit_mode current ; + enter_mode next ; + Xapi_host_ntp.restart_ntp_service () ) ; - if ntp_enabled then Xapi_host_ntp.restart_ntp_service () ; Db.Host.set_ntp_mode ~__context ~self ~value ) let set_ntp_custom_servers ~__context ~self ~value = let current_mode = Db.Host.get_ntp_mode ~__context ~self in match (current_mode, value) with - | `ntp_mode_custom, [] -> + | `Custom, [] -> raise Api_errors.( Server_error ( invalid_ntp_config - , ["Can't set ntp_custom_servers empty when ntp_mode is custom"] + , ["Can't set ntp_custom_servers empty when ntp_mode is Custom"] ) ) - | `ntp_mode_custom, servers -> + | `Custom, servers -> Xapi_host_ntp.set_servers_in_conf servers ; Xapi_host_ntp.restart_ntp_service () ; Db.Host.set_ntp_custom_servers ~__context ~self ~value | _ -> Db.Host.set_ntp_custom_servers ~__context ~self ~value -let enable_ntp ~__context ~self = - Xapi_host_ntp.enable_ntp_service () ; - Db.Host.set_ntp_enabled ~__context ~self ~value:true - -let disable_ntp ~__context ~self = - Xapi_host_ntp.disable_ntp_service () ; - Db.Host.set_ntp_enabled ~__context ~self ~value:false - let sync_ntp_config ~__context ~host = Xapi_host_ntp.promote_legacy_default_servers () ; let servers = Xapi_host_ntp.get_servers_from_conf () in let is_ntp_dhcp_enabled = Xapi_host_ntp.is_ntp_dhcp_enabled () in + let ntp_enabled = Xapi_host_ntp.is_ntp_service_active () in let ntp_mode = - match (is_ntp_dhcp_enabled, servers) with - | true, _ -> - `ntp_mode_dhcp - | false, s + match (ntp_enabled, is_ntp_dhcp_enabled, servers) with + | false, _, _ -> + `Disabled + | _, true, _ -> + `DHCP + | _, false, s when Xapi_stdext_std.Listext.List.set_equiv s - !Xapi_globs.default_ntp_servers -> - `ntp_mode_default - | false, _ -> - `ntp_mode_custom + !Xapi_globs.factory_ntp_servers -> + `Factory + | _, false, _ -> + `Custom in Db.Host.set_ntp_mode ~__context ~self:host ~value:ntp_mode ; - if ntp_mode = `ntp_mode_custom then - Db.Host.set_ntp_custom_servers ~__context ~self:host ~value:servers ; - let ntp_enabled = Xapi_host_ntp.is_ntp_service_active () in - Db.Host.set_ntp_enabled ~__context ~self:host ~value:ntp_enabled + if ntp_mode = `Custom then + Db.Host.set_ntp_custom_servers ~__context ~self:host ~value:servers let get_ntp_servers_status ~__context ~self:_ = if Xapi_host_ntp.is_ntp_service_active () then diff --git a/ocaml/xapi/xapi_host.mli b/ocaml/xapi/xapi_host.mli index fb05236ae53..0bfc60077b1 100644 --- a/ocaml/xapi/xapi_host.mli +++ b/ocaml/xapi/xapi_host.mli @@ -619,10 +619,6 @@ val set_ntp_mode : val set_ntp_custom_servers : __context:Context.t -> self:API.ref_host -> value:string list -> unit -val enable_ntp : __context:Context.t -> self:API.ref_host -> unit - -val disable_ntp : __context:Context.t -> self:API.ref_host -> unit - val sync_ntp_config : __context:Context.t -> host:API.ref_host -> unit val get_ntp_servers_status : diff --git a/ocaml/xapi/xapi_host_ntp.ml b/ocaml/xapi/xapi_host_ntp.ml index 942490d1276..f44021b9bb1 100644 --- a/ocaml/xapi/xapi_host_ntp.ml +++ b/ocaml/xapi/xapi_host_ntp.ml @@ -51,6 +51,9 @@ let get_dhcp_ntp_server interface = ) let add_dhcp_ntp_servers () = + let ntp_dhcp_dir = !Xapi_globs.ntp_dhcp_dir in + if not (Sys.file_exists ntp_dhcp_dir && Sys.is_directory ntp_dhcp_dir) then + Xapi_stdext_unix.Unixext.mkdir_rec ntp_dhcp_dir 0o755 ; get_dhclient_interfaces () |> List.iter (fun interface -> match get_dhcp_ntp_server interface with @@ -72,16 +75,17 @@ let remove_dhcp_ntp_servers () = Sys.remove (!Xapi_globs.ntp_dhcp_dir // fname) ) -let restart_ntp_service () = - Xapi_systemctl.restart ~wait_until_success:false !Xapi_globs.ntp_service - let enable_ntp_service () = - Xapi_systemctl.enable ~wait_until_success:false !Xapi_globs.ntp_service ; - Xapi_systemctl.start ~wait_until_success:false !Xapi_globs.ntp_service + Helpers.call_script !Xapi_globs.timedatectl ["set-ntp"; "true"] |> ignore let disable_ntp_service () = - Xapi_systemctl.stop ~wait_until_success:false !Xapi_globs.ntp_service ; - Xapi_systemctl.disable ~wait_until_success:false !Xapi_globs.ntp_service + Helpers.call_script !Xapi_globs.timedatectl ["set-ntp"; "false"] |> ignore + +let restart_ntp_service () = + (* Make sure the NTP service is enabled before restarting, and the timedatectl + ntp enabled status is consistent with the service state *) + enable_ntp_service () ; + Xapi_systemctl.restart ~wait_until_success:false !Xapi_globs.ntp_service let is_ntp_service_active () = Fe_systemctl.is_active ~service:!Xapi_globs.ntp_service @@ -162,8 +166,8 @@ let get_servers_status () = let promote_legacy_default_servers () = let servers = get_servers_from_conf () in - let legacy = !Xapi_globs.legacy_default_ntp_servers in - let defaults = !Xapi_globs.default_ntp_servers in + let legacy = !Xapi_globs.legacy_factory_ntp_servers in + let defaults = !Xapi_globs.factory_ntp_servers in if legacy <> [] && defaults <> [] diff --git a/ocaml/xapi/xapi_host_ntp.mli b/ocaml/xapi/xapi_host_ntp.mli index 8d8fdfe5b4a..b496c741423 100644 --- a/ocaml/xapi/xapi_host_ntp.mli +++ b/ocaml/xapi/xapi_host_ntp.mli @@ -22,12 +22,12 @@ val clear_servers_in_conf : unit -> unit val promote_legacy_default_servers : unit -> unit -val restart_ntp_service : unit -> unit - val enable_ntp_service : unit -> unit val disable_ntp_service : unit -> unit +val restart_ntp_service : unit -> unit + val is_ntp_service_active : unit -> bool val get_servers_from_conf : unit -> string list