Skip to content

Commit 5c68118

Browse files
authored
Merge pull request #5851 from BengangY/private/bengangy/CP-49214
CP 49214: Upload and reposync from the bundle
2 parents d7682dc + c870b26 commit 5c68118

21 files changed

+341
-34
lines changed

ocaml/idl/datamodel.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8432,6 +8432,7 @@ let http_actions =
84328432
, []
84338433
)
84348434
)
8435+
; ("put_bundle", (Put, Constants.put_bundle_uri, true, [], _R_POOL_OP, []))
84358436
]
84368437

84378438
(* these public http actions will NOT be checked by RBAC *)

ocaml/idl/datamodel_errors.ml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1895,6 +1895,19 @@ let _ =
18951895
~doc:"The GPG public key file name in the repository is invalid." () ;
18961896
error Api_errors.repository_already_exists ["ref"]
18971897
~doc:"The repository already exists." () ;
1898+
error Api_errors.bundle_repository_already_exists ["ref"]
1899+
~doc:"The bundle repository already exists." () ;
1900+
error Api_errors.bundle_unpack_failed ["error"]
1901+
~doc:"Failed to unpack bundle file." () ;
1902+
error Api_errors.bundle_repo_not_enabled []
1903+
~doc:"Cannot sync bundle as the bundle repository is not enabled." () ;
1904+
error Api_errors.can_not_sync_updates []
1905+
~doc:"Cannot sync updates as the bundle repository is enabled." () ;
1906+
error Api_errors.bundle_repo_should_be_single_enabled []
1907+
~doc:
1908+
"If the bundle repository is enabled, it should be the only one enabled \
1909+
repository of the pool."
1910+
() ;
18981911
error Api_errors.repository_is_in_use [] ~doc:"The repository is in use." () ;
18991912
error Api_errors.repository_cleanup_failed []
19001913
~doc:"Failed to clean up local repository on coordinator." () ;
@@ -1907,6 +1920,11 @@ let _ =
19071920
"The operation could not be performed because syncing updates is in \
19081921
progress."
19091922
() ;
1923+
error Api_errors.sync_bundle_in_progress []
1924+
~doc:
1925+
"The operation could not be performed because syncing bundle is in \
1926+
progress."
1927+
() ;
19101928
error Api_errors.reposync_failed []
19111929
~doc:"Syncing with remote YUM repository failed." () ;
19121930
error Api_errors.invalid_repomd_xml [] ~doc:"The repomd.xml is invalid." () ;

ocaml/idl/datamodel_pool.ml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ let operations =
2121
; ( "sync_updates"
2222
, "Indicates this pool is in the process of syncing updates"
2323
)
24+
; ( "sync_bundle"
25+
, "Indicates this pool is in the process of syncing bundle"
26+
)
2427
; ( "get_updates"
2528
, "Indicates this pool is in the process of getting updates"
2629
)

ocaml/idl/schematest.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ let hash x = Digest.string x |> Digest.to_hex
33
(* BEWARE: if this changes, check that schema has been bumped accordingly in
44
ocaml/idl/datamodel_common.ml, usually schema_minor_vsn *)
55

6-
let last_known_schema_hash = "2a6baa01032827a321845b264c6aaae4"
6+
let last_known_schema_hash = "4417b0087b481c3038e73f170b7d4d01"
77

88
let current_schema_hash : string =
99
let open Datamodel_types in

ocaml/tests/dune

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
test_vm_placement test_vm_helpers test_repository test_repository_helpers
1010
test_ref test_vm_group
1111
test_livepatch test_rpm test_updateinfo test_storage_smapiv1_wrapper test_storage_quicktest test_observer
12-
test_pool_periodic_update_sync test_pkg_mgr test_tar_ext))
12+
test_pool_periodic_update_sync test_pkg_mgr test_tar_ext test_pool_repository))
1313
(libraries
1414
alcotest
1515
angstrom
@@ -79,13 +79,13 @@
7979
(tests
8080
(names test_vm_helpers test_vm_placement test_network_sriov test_vdi_cbt
8181
test_clustering test_pusb test_daemon_manager test_repository test_repository_helpers
82-
test_livepatch test_rpm test_updateinfo test_pool_periodic_update_sync test_pkg_mgr test_tar_ext)
82+
test_livepatch test_rpm test_updateinfo test_pool_periodic_update_sync test_pkg_mgr test_tar_ext test_pool_repository)
8383
(package xapi)
8484
(modes exe)
8585
(modules test_vm_helpers test_vm_placement test_network_sriov test_vdi_cbt
8686
test_event test_clustering test_cluster_host test_cluster test_pusb
8787
test_daemon_manager test_repository test_repository_helpers test_livepatch test_rpm
88-
test_updateinfo test_pool_periodic_update_sync test_pkg_mgr test_tar_ext)
88+
test_updateinfo test_pool_periodic_update_sync test_pkg_mgr test_tar_ext test_pool_repository)
8989
(libraries
9090
alcotest
9191
bos

ocaml/tests/test_pool_repository.ml

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
(*
2+
* Copyright (c) Cloud Software Group, Inc.
3+
*
4+
* This program is free software; you can redistribute it and/or modify
5+
* it under the terms of the GNU Lesser General Public License as published
6+
* by the Free Software Foundation; version 2.1 only. with the special
7+
* exception on linking described in file LICENSE.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU Lesser General Public License for more details.
13+
*)
14+
15+
module T = Test_common
16+
17+
let test_set_remote_and_bundle_repos () =
18+
let __context = T.make_test_database () in
19+
let name_label = "remote" in
20+
let name_description = "remote" in
21+
let binary_url = "https://repo.example.com" in
22+
let source_url = "https://repo-src.example.com" in
23+
let gpgkey_path = "" in
24+
let ref_remote =
25+
Repository.introduce ~__context ~name_label ~name_description ~binary_url
26+
~source_url ~update:true ~gpgkey_path
27+
in
28+
let ref_bundle =
29+
Repository.introduce_bundle ~__context ~name_label:"bundle"
30+
~name_description:"bundle"
31+
in
32+
let self = Helpers.get_pool ~__context in
33+
Alcotest.check_raises "test_set_remote_and_bundle_repos"
34+
Api_errors.(Server_error (bundle_repo_should_be_single_enabled, []))
35+
(fun () ->
36+
Xapi_pool.set_repositories ~__context ~self
37+
~value:[ref_remote; ref_bundle]
38+
)
39+
40+
let test_add_bundle_repo () =
41+
let __context = T.make_test_database () in
42+
let name_label = "remote" in
43+
let name_description = "remote" in
44+
let binary_url = "https://repo.example.com" in
45+
let source_url = "https://repo-src.example.com" in
46+
let gpgkey_path = "" in
47+
let ref_remote =
48+
Repository.introduce ~__context ~name_label ~name_description ~binary_url
49+
~source_url ~update:true ~gpgkey_path
50+
in
51+
let ref_bundle =
52+
Repository.introduce_bundle ~__context ~name_label:"bundle"
53+
~name_description:"bundle"
54+
in
55+
let self = Helpers.get_pool ~__context in
56+
Alcotest.check_raises "test_add_bundle_repo"
57+
Api_errors.(Server_error (bundle_repo_should_be_single_enabled, []))
58+
(fun () ->
59+
Xapi_pool.set_repositories ~__context ~self ~value:[ref_remote] ;
60+
Xapi_pool.add_repository ~__context ~self ~value:ref_bundle
61+
)
62+
63+
let test_add_remote_repo () =
64+
let __context = T.make_test_database () in
65+
let name_label = "remote" in
66+
let name_description = "remote" in
67+
let binary_url = "https://repo.example.com" in
68+
let source_url = "https://repo-src.example.com" in
69+
let gpgkey_path = "" in
70+
let ref_remote =
71+
Repository.introduce ~__context ~name_label ~name_description ~binary_url
72+
~source_url ~update:true ~gpgkey_path
73+
in
74+
let ref_bundle =
75+
Repository.introduce_bundle ~__context ~name_label:"bundle"
76+
~name_description:"bundle"
77+
in
78+
let self = Helpers.get_pool ~__context in
79+
Alcotest.check_raises "test_add_remote_repo"
80+
Api_errors.(Server_error (bundle_repo_should_be_single_enabled, []))
81+
(fun () ->
82+
Xapi_pool.set_repositories ~__context ~self ~value:[ref_bundle] ;
83+
Xapi_pool.add_repository ~__context ~self ~value:ref_remote
84+
)
85+
86+
let test_can_not_enable_bundle_repo_auto_sync () =
87+
let __context = T.make_test_database () in
88+
let ref_bundle =
89+
Repository.introduce_bundle ~__context ~name_label:"bundle"
90+
~name_description:"bundle"
91+
in
92+
let self = Helpers.get_pool ~__context in
93+
Alcotest.check_raises "test_can_not_enable_bundle_repo_auto_sync"
94+
Api_errors.(Server_error (can_not_sync_updates, []))
95+
(fun () ->
96+
Xapi_pool.set_repositories ~__context ~self ~value:[ref_bundle] ;
97+
Xapi_pool.set_update_sync_enabled ~__context ~self ~value:true
98+
)
99+
100+
let test =
101+
[
102+
( "test_set_remote_and_bundle_repos"
103+
, `Quick
104+
, test_set_remote_and_bundle_repos
105+
)
106+
; ("test_add_bundle_repo", `Quick, test_add_bundle_repo)
107+
; ("test_add_remote_repo", `Quick, test_add_remote_repo)
108+
; ( "test_can_not_enable_bundle_repo_auto_sync"
109+
, `Quick
110+
, test_can_not_enable_bundle_repo_auto_sync
111+
)
112+
]
113+
114+
let () =
115+
Suite_init.harness_init () ;
116+
Alcotest.run "Test Pool Repository suite" [("Test_pool_repository", test)]

ocaml/tests/test_repository.ml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,9 @@ let test_introduce_duplicate_bundle_repo () =
101101
in
102102

103103
Alcotest.check_raises "test_introduce_duplicate_bundle_repo"
104-
Api_errors.(Server_error (repository_already_exists, [Ref.string_of ref]))
104+
Api_errors.(
105+
Server_error (bundle_repository_already_exists, [Ref.string_of ref])
106+
)
105107
(fun () ->
106108
Repository.introduce_bundle ~__context ~name_label:name_label_1
107109
~name_description:name_description_1

ocaml/xapi-cli-server/cli_frontend.ml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3091,6 +3091,17 @@ let rec cmdtable_data : (string * cmd_spec) list =
30913091
; flags= []
30923092
}
30933093
)
3094+
; ( "pool-sync-bundle"
3095+
, {
3096+
reqd= ["filename"]
3097+
; optn= []
3098+
; help=
3099+
"Upload and unpack a bundle file, after that, sync the bundle \
3100+
repository."
3101+
; implementation= With_fd Cli_operations.pool_sync_bundle
3102+
; flags= []
3103+
}
3104+
)
30943105
; ( "host-ha-xapi-healthcheck"
30953106
, {
30963107
reqd= []

ocaml/xapi-cli-server/cli_operations.ml

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2462,8 +2462,7 @@ let parse_host_uuid ?(default_master = true) rpc session_id params =
24622462
let hosts = Client.Host.get_all ~rpc ~session_id in
24632463
let standalone = List.length hosts = 1 in
24642464
if standalone || default_master then
2465-
let pool = List.hd (Client.Pool.get_all ~rpc ~session_id) in
2466-
Client.Pool.get_master ~rpc ~session_id ~self:pool
2465+
get_master ~rpc ~session_id
24672466
else
24682467
failwith "Required parameter not found: host-uuid"
24692468
@@ -3989,7 +3988,7 @@ let vm_install_real printer rpc session_id template name description params =
39893988
, [Features.name_of_feature Features.PCI_device_for_auto_update]
39903989
)
39913990
in
3992-
let pool = List.hd (Client.Pool.get_all ~rpc ~session_id) in
3991+
let pool = get_pool ~rpc ~session_id in
39933992
let policy_vendor_device_is_ok =
39943993
not (Client.Pool.get_policy_no_vendor_device ~rpc ~session_id ~self:pool)
39953994
in
@@ -5133,11 +5132,6 @@ let vm_cd_insert printer rpc session_id params =
51335132
let host_careful_op op warnings fd _printer rpc session_id params =
51345133
let uuid = List.assoc "uuid" params in
51355134
let host = Client.Host.get_by_uuid ~rpc ~session_id ~uuid in
5136-
let pool = List.hd (Client.Pool.get_all ~rpc ~session_id) in
5137-
let _ (* unused variable 'pool_master' *) =
5138-
Client.Pool.get_master ~rpc ~session_id ~self:pool
5139-
in
5140-
(* if pool_master = host then failwith "Cannot forget pool master"; *)
51415135
let force = get_bool_param params "force" in
51425136
let go () = ignore (op ~rpc ~session_id ~self:host) in
51435137
if force then
@@ -6605,11 +6599,11 @@ let host_disable_local_storage_caching _printer rpc session_id params =
66056599
)
66066600

66076601
let pool_enable_local_storage_caching _printer rpc session_id _params =
6608-
let pool = List.hd (Client.Pool.get_all ~rpc ~session_id) in
6602+
let pool = get_pool ~rpc ~session_id in
66096603
Client.Pool.enable_local_storage_caching ~rpc ~session_id ~self:pool
66106604

66116605
let pool_disable_local_storage_caching _printer rpc session_id _params =
6612-
let pool = List.hd (Client.Pool.get_all ~rpc ~session_id) in
6606+
let pool = get_pool ~rpc ~session_id in
66136607
Client.Pool.disable_local_storage_caching ~rpc ~session_id ~self:pool
66146608

66156609
let pool_apply_edition printer rpc session_id params =
@@ -6692,8 +6686,7 @@ let host_backup fd _printer rpc session_id params =
66926686
let pool_dump_db fd _printer rpc session_id params =
66936687
let filename = List.assoc "file-name" params in
66946688
let make_command task_id =
6695-
let pool = List.hd (Client.Pool.get_all ~rpc ~session_id) in
6696-
let master = Client.Pool.get_master ~rpc ~session_id ~self:pool in
6689+
let master = get_master ~rpc ~session_id in
66976690
let master_address =
66986691
Client.Host.get_address ~rpc ~session_id ~self:master
66996692
in
@@ -6769,6 +6762,36 @@ let pool_get_guest_secureboot_readiness printer rpc session_id params =
67696762
(Record_util.pool_guest_secureboot_readiness_to_string result)
67706763
)
67716764

6765+
let pool_sync_bundle fd _printer rpc session_id params =
6766+
let filename_opt = List.assoc_opt "filename" params in
6767+
match filename_opt with
6768+
| Some filename ->
6769+
let make_command task_id =
6770+
let master = get_master ~rpc ~session_id in
6771+
let master_address =
6772+
Client.Host.get_address ~rpc ~session_id ~self:master
6773+
in
6774+
let uri =
6775+
Uri.(
6776+
make ~scheme:"http" ~host:master_address
6777+
~path:Constants.put_bundle_uri
6778+
~query:
6779+
[
6780+
("session_id", [Ref.string_of session_id])
6781+
; ("task_id", [Ref.string_of task_id])
6782+
]
6783+
()
6784+
|> to_string
6785+
)
6786+
in
6787+
debug "%s: requesting HttpPut('%s','%s')" __FUNCTION__ filename uri ;
6788+
HttpPut (filename, uri)
6789+
in
6790+
ignore
6791+
(track_http_operation fd rpc session_id make_command "upload bundle")
6792+
| None ->
6793+
failwith "Required parameter not found: filename"
6794+
67726795
let host_restore fd _printer rpc session_id params =
67736796
let filename = List.assoc "file-name" params in
67746797
let op _ host =

ocaml/xapi-cli-server/cli_util.ml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,14 @@ open Client
2626

2727
let finally = Xapi_stdext_pervasives.Pervasiveext.finally
2828

29+
let internal_error fmt =
30+
Printf.ksprintf
31+
(fun str ->
32+
error "%s" str ;
33+
raise Api_errors.(Server_error (internal_error, [str]))
34+
)
35+
fmt
36+
2937
let log_exn_continue msg f x =
3038
try f x
3139
with e -> debug "Ignoring exception: %s while %s" (Printexc.to_string e) msg
@@ -334,3 +342,14 @@ let error_of_exn e =
334342
let string_of_exn exn =
335343
let e, l = error_of_exn exn in
336344
Printf.sprintf "%s: [ %s ]" e (String.concat "; " l)
345+
346+
let get_pool ~rpc ~session_id =
347+
match Client.Pool.get_all ~rpc ~session_id with
348+
| [] ->
349+
internal_error "Remote host does not belong to a pool."
350+
| pool :: _ ->
351+
pool
352+
353+
let get_master ~rpc ~session_id =
354+
let pool = get_pool ~rpc ~session_id in
355+
Client.Pool.get_master ~rpc ~session_id ~self:pool

0 commit comments

Comments
 (0)