]>
git.proxmox.com Git - ceph.git/blob - ceph/src/cephadm/tests/test_cephadm.py
5487f43b3a88ccb85a6233fe41659f3bd6fe549f
10 with
patch ( 'builtins.open' , create
= True ):
11 from importlib
. machinery
import SourceFileLoader
12 cd
= SourceFileLoader ( 'cephadm' , 'cephadm' ). load_module ()
14 class TestCephAdm ( object ):
15 def test_is_not_fsid ( self
):
16 assert not cd
. is_fsid ( 'no-uuid' )
18 def test_is_fsid ( self
):
19 assert cd
. is_fsid ( 'e863154d-33c7-4350-bca5-921e0467e55b' )
21 def test__get_parser_image ( self
):
22 args
= cd
._ parse
_ args
([ '--image' , 'foo' , 'version' ])
23 assert args
. image
== 'foo'
25 def test_CustomValidation ( self
):
26 assert cd
._ parse
_ args
([ 'deploy' , '--name' , 'mon.a' , '--fsid' , 'fsid' ])
28 with pytest
. raises ( SystemExit ):
29 cd
._ parse
_ args
([ 'deploy' , '--name' , 'wrong' , '--fsid' , 'fsid' ])
31 @pytest . mark
. parametrize ( "test_input, expected" , [
32 ( "podman version 1.6.2" , ( 1 , 6 , 2 )),
33 ( "podman version 1.6.2-stable2" , ( 1 , 6 , 2 )),
35 def test_parse_podman_version ( self
, test_input
, expected
):
36 assert cd
._ parse
_ podman
_ version
( test_input
) == expected
38 def test_parse_podman_version_invalid ( self
):
39 with pytest
. raises ( ValueError ) as res
:
40 cd
._ parse
_ podman
_ version
( 'podman version inval.id' )
41 assert 'inval' in str ( res
. value
)
43 @pytest . mark
. parametrize ( "test_input, expected" , [
46 default via 192.168.178.1 dev enxd89ef3f34260 proto dhcp metric 100
47 10.0.0.0/8 via 10.4.0.1 dev tun0 proto static metric 50
48 10.3.0.0/21 via 10.4.0.1 dev tun0 proto static metric 50
49 10.4.0.1 dev tun0 proto kernel scope link src 10.4.0.2 metric 50
50 137.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50
51 138.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50
52 139.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50
53 140.1.0.0/17 via 10.4.0.1 dev tun0 proto static metric 50
54 141.1.0.0/16 via 10.4.0.1 dev tun0 proto static metric 50
55 169.254.0.0/16 dev docker0 scope link metric 1000
56 172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1
57 192.168.39.0/24 dev virbr1 proto kernel scope link src 192.168.39.1 linkdown
58 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown
59 192.168.178.0/24 dev enxd89ef3f34260 proto kernel scope link src 192.168.178.28 metric 100
60 192.168.178.1 dev enxd89ef3f34260 proto static scope link metric 100
61 195.135.221.12 via 192.168.178.1 dev enxd89ef3f34260 proto static metric 100
64 '10.4.0.1' : [ '10.4.0.2' ],
65 '172.17.0.0/16' : [ '172.17.0.1' ],
66 '192.168.39.0/24' : [ '192.168.39.1' ],
67 '192.168.122.0/24' : [ '192.168.122.1' ],
68 '192.168.178.0/24' : [ '192.168.178.28' ]
72 default via 10.3.64.1 dev eno1 proto static metric 100
73 10.3.64.0/24 dev eno1 proto kernel scope link src 10.3.64.23 metric 100
74 10.3.64.0/24 dev eno1 proto kernel scope link src 10.3.64.27 metric 100
75 10.88.0.0/16 dev cni-podman0 proto kernel scope link src 10.88.0.1 linkdown
76 172.21.0.0/20 via 172.21.3.189 dev tun0
77 172.21.1.0/20 via 172.21.3.189 dev tun0
78 172.21.2.1 via 172.21.3.189 dev tun0
79 172.21.3.1 dev tun0 proto kernel scope link src 172.21.3.2
80 172.21.4.0/24 via 172.21.3.1 dev tun0
81 172.21.5.0/24 via 172.21.3.1 dev tun0
82 172.21.6.0/24 via 172.21.3.1 dev tun0
83 172.21.7.0/24 via 172.21.3.1 dev tun0
84 192.168.122.0/24 dev virbr0 proto kernel scope link src 192.168.122.1 linkdown
87 '10.3.64.0/24' : [ '10.3.64.23' , '10.3.64.27' ],
88 '10.88.0.0/16' : [ '10.88.0.1' ],
89 '172.21.3.1' : [ '172.21.3.2' ],
90 '192.168.122.0/24' : [ '192.168.122.1' ]}
93 def test_parse_ipv4_route ( self
, test_input
, expected
):
94 assert cd
._ parse
_ ipv
4_ route
( test_input
) == expected
96 @pytest . mark
. parametrize ( "test_routes, test_ips, expected" , [
99 ::1 dev lo proto kernel metric 256 pref medium
100 fdbc:7574:21fe:9200::/64 dev wlp2s0 proto ra metric 600 pref medium
101 fdd8:591e:4969:6363::/64 dev wlp2s0 proto ra metric 600 pref medium
102 fde4:8dba:82e1::/64 dev eth1 proto kernel metric 256 expires 1844sec pref medium
103 fe80::/64 dev tun0 proto kernel metric 256 pref medium
104 fe80::/64 dev wlp2s0 proto kernel metric 600 pref medium
105 default dev tun0 proto static metric 50 pref medium
106 default via fe80::2480:28ec:5097:3fe2 dev wlp2s0 proto ra metric 20600 pref medium
109 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
110 inet6 ::1/128 scope host
111 valid_lft forever preferred_lft forever
112 2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
113 inet6 fdd8:591e:4969:6363:4c52:cafe:8dd4:dc4/64 scope global temporary dynamic
114 valid_lft 86394sec preferred_lft 14394sec
115 inet6 fdbc:7574:21fe:9200:4c52:cafe:8dd4:dc4/64 scope global temporary dynamic
116 valid_lft 6745sec preferred_lft 3145sec
117 inet6 fdd8:591e:4969:6363:103a:abcd:af1f:57f3/64 scope global temporary deprecated dynamic
118 valid_lft 86394sec preferred_lft 0sec
119 inet6 fdbc:7574:21fe:9200:103a:abcd:af1f:57f3/64 scope global temporary deprecated dynamic
120 valid_lft 6745sec preferred_lft 0sec
121 inet6 fdd8:591e:4969:6363:a128:1234:2bdd:1b6f/64 scope global temporary deprecated dynamic
122 valid_lft 86394sec preferred_lft 0sec
123 inet6 fdbc:7574:21fe:9200:a128:1234:2bdd:1b6f/64 scope global temporary deprecated dynamic
124 valid_lft 6745sec preferred_lft 0sec
125 inet6 fdd8:591e:4969:6363:d581:4321:380b:3905/64 scope global temporary deprecated dynamic
126 valid_lft 86394sec preferred_lft 0sec
127 inet6 fdbc:7574:21fe:9200:d581:4321:380b:3905/64 scope global temporary deprecated dynamic
128 valid_lft 6745sec preferred_lft 0sec
129 inet6 fe80::1111:2222:3333:4444/64 scope link noprefixroute
130 valid_lft forever preferred_lft forever
131 inet6 fde4:8dba:82e1:0:ec4a:e402:e9df:b357/64 scope global temporary dynamic
132 valid_lft 1074sec preferred_lft 1074sec
133 inet6 fde4:8dba:82e1:0:5054:ff:fe72:61af/64 scope global dynamic mngtmpaddr
134 valid_lft 1074sec preferred_lft 1074sec
135 12: tun0: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 state UNKNOWN qlen 100
136 inet6 fe80::cafe:cafe:cafe:cafe/64 scope link stable-privacy
137 valid_lft forever preferred_lft forever
141 "fdbc:7574:21fe:9200::/64" : [ "fdbc:7574:21fe:9200:4c52:cafe:8dd4:dc4" ,
142 "fdbc:7574:21fe:9200:103a:abcd:af1f:57f3" ,
143 "fdbc:7574:21fe:9200:a128:1234:2bdd:1b6f" ,
144 "fdbc:7574:21fe:9200:d581:4321:380b:3905" ],
145 "fdd8:591e:4969:6363::/64" : [ "fdd8:591e:4969:6363:4c52:cafe:8dd4:dc4" ,
146 "fdd8:591e:4969:6363:103a:abcd:af1f:57f3" ,
147 "fdd8:591e:4969:6363:a128:1234:2bdd:1b6f" ,
148 "fdd8:591e:4969:6363:d581:4321:380b:3905" ],
149 "fde4:8dba:82e1::/64" : [ "fde4:8dba:82e1:0:ec4a:e402:e9df:b357" ,
150 "fde4:8dba:82e1:0:5054:ff:fe72:61af" ],
151 "fe80::/64" : [ "fe80::1111:2222:3333:4444" ,
152 "fe80::cafe:cafe:cafe:cafe" ]
155 def test_parse_ipv6_route ( self
, test_routes
, test_ips
, expected
):
156 assert cd
._ parse
_ ipv
6_ route
( test_routes
, test_ips
) == expected
158 def test_is_ipv6 ( self
):
159 cd
. logger
= mock
. Mock ()
160 for good
in ( "[::1]" , "::1" ,
161 "fff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" ):
162 assert cd
. is_ipv6 ( good
)
163 for bad
in ( "127.0.0.1" ,
164 "ffff:ffff:ffff:ffff:ffff:ffff:ffff:fffg" ,
165 "1:2:3:4:5:6:7:8:9" , "fd00::1::1" , "[fg::1]" ):
166 assert not cd
. is_ipv6 ( bad
)
168 def test_unwrap_ipv6 ( self
):
169 def unwrap_test ( address
, expected
):
170 assert cd
. unwrap_ipv6 ( address
) == expected
173 ( '::1' , '::1' ), ( '[::1]' , '::1' ),
174 ( '[fde4:8dba:82e1:0:5054:ff:fe6a:357]' , 'fde4:8dba:82e1:0:5054:ff:fe6a:357' ),
175 ( 'can actually be any string' , 'can actually be any string' ),
176 ( '[but needs to be stripped] ' , '[but needs to be stripped] ' )]
177 for address
, expected
in tests
:
178 unwrap_test ( address
, expected
)
180 def test_wrap_ipv6 ( self
):
181 def wrap_test ( address
, expected
):
182 assert cd
. wrap_ipv6 ( address
) == expected
185 ( '::1' , '[::1]' ), ( '[::1]' , '[::1]' ),
186 ( 'fde4:8dba:82e1:0:5054:ff:fe6a:357' ,
187 '[fde4:8dba:82e1:0:5054:ff:fe6a:357]' ),
188 ( 'myhost.example.com' , 'myhost.example.com' ),
189 ( '192.168.0.1' , '192.168.0.1' ),
190 ( '' , '' ), ( 'fd00::1::1' , 'fd00::1::1' )]
191 for address
, expected
in tests
:
192 wrap_test ( address
, expected
)
194 @mock . patch ( 'cephadm.call_throws' )
195 @mock . patch ( 'cephadm.get_parm' )
196 def test_registry_login ( self
, get_parm
, call_throws
):
198 # test normal valid login with url, username and password specified
199 call_throws
. return_value
= '' , '' , 0
200 args
= cd
._ parse
_ args
([ 'registry-login' , '--registry-url' , 'sample-url' , '--registry-username' , 'sample-user' , '--registry-password' , 'sample-pass' ])
202 retval
= cd
. command_registry_login ()
205 # test bad login attempt with invalid arguments given
206 args
= cd
._ parse
_ args
([ 'registry-login' , '--registry-url' , 'bad-args-url' ])
208 with pytest
. raises ( Exception ) as e
:
209 assert cd
. command_registry_login ()
210 assert str ( e
. value
) == ( 'Invalid custom registry arguments received. To login to a custom registry include '
211 '--registry-url, --registry-username and --registry-password options or --registry-json option' )
213 # test normal valid login with json file
214 get_parm
. return_value
= { "url" : "sample-url" , "username" : "sample-username" , "password" : "sample-password" }
215 args
= cd
._ parse
_ args
([ 'registry-login' , '--registry-json' , 'sample-json' ])
217 retval
= cd
. command_registry_login ()
220 # test bad login attempt with bad json file
221 get_parm
. return_value
= { "bad-json" : "bad-json" }
222 args
= cd
._ parse
_ args
([ 'registry-login' , '--registry-json' , 'sample-json' ])
224 with pytest
. raises ( Exception ) as e
:
225 assert cd
. command_registry_login ()
226 assert str ( e
. value
) == ( "json provided for custom registry login did not include all necessary fields. "
227 "Please setup json file as \n "
229 " \" url \" : \" REGISTRY_URL \" , \n "
230 " \" username \" : \" REGISTRY_USERNAME \" , \n "
231 " \" password \" : \" REGISTRY_PASSWORD \"\n "
234 # test login attempt with valid arguments where login command fails
235 call_throws
. side_effect
= Exception
236 args
= cd
._ parse
_ args
([ 'registry-login' , '--registry-url' , 'sample-url' , '--registry-username' , 'sample-user' , '--registry-password' , 'sample-pass' ])
238 with pytest
. raises ( Exception ) as e
:
239 cd
. command_registry_login ()
240 assert str ( e
. value
) == "Failed to login to custom registry @ sample-url as sample-user with given password"
242 def test_get_image_info_from_inspect ( self
):
244 out
= """204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1,["docker.io/ceph/ceph@sha256:1cc9b824e1b076cdff52a9aa3f0cc8557d879fb2fbbba0cafed970aca59a3992"]"""
245 r
= cd
. get_image_info_from_inspect ( out
, 'registry/ceph/ceph:latest' )
247 'image_id' : '204a01f9b0b6710dd0c0af7f37ce7139c47ff0f0105d778d7104c69282dfbbf1' ,
248 'repo_digest' : 'docker.io/ceph/ceph@sha256:1cc9b824e1b076cdff52a9aa3f0cc8557d879fb2fbbba0cafed970aca59a3992'
252 out
= """sha256:16f4549cf7a8f112bbebf7946749e961fbbd1b0838627fe619aab16bc17ce552,["quay.ceph.io/ceph-ci/ceph@sha256:4e13da36c1bd6780b312a985410ae678984c37e6a9493a74c87e4a50b9bda41f"]"""
253 r
= cd
. get_image_info_from_inspect ( out
, 'registry/ceph/ceph:latest' )
255 'image_id' : '16f4549cf7a8f112bbebf7946749e961fbbd1b0838627fe619aab16bc17ce552' ,
256 'repo_digest' : 'quay.ceph.io/ceph-ci/ceph@sha256:4e13da36c1bd6780b312a985410ae678984c37e6a9493a74c87e4a50b9bda41f'
259 def test_dict_get ( self
):
260 result
= cd
. dict_get ({ 'a' : 1 }, 'a' , require
= True )
262 result
= cd
. dict_get ({ 'a' : 1 }, 'b' )
263 assert result
is None
264 result
= cd
. dict_get ({ 'a' : 1 }, 'b' , default
= 2 )
267 def test_dict_get_error ( self
):
268 with pytest
. raises ( cd
. Error
):
269 cd
. dict_get ({ 'a' : 1 }, 'b' , require
= True )
271 def test_dict_get_join ( self
):
272 result
= cd
. dict_get_join ({ 'foo' : [ 'a' , 'b' ]}, 'foo' )
273 assert result
== 'a \n b'
274 result
= cd
. dict_get_join ({ 'foo' : [ 1 , 2 ]}, 'foo' )
275 assert result
== '1 \n 2'
276 result
= cd
. dict_get_join ({ 'bar' : 'a' }, 'bar' )
278 result
= cd
. dict_get_join ({ 'a' : 1 }, 'a' )
281 def test_last_local_images ( self
):
283 docker.io/ceph/daemon-base@
284 docker.io/ceph/ceph:v15.2.5
285 docker.io/ceph/daemon-base:octopus
287 image
= cd
._ filter
_l ast
_l ocal
_ ceph
_ image
( out
)
288 assert image
== 'docker.io/ceph/ceph:v15.2.5'
291 class TestCustomContainer ( unittest
. TestCase
):
292 cc
: cd
. CustomContainer
295 self
. cc
= cd
. CustomContainer (
296 'e863154d-33c7-4350-bca5-921e0467e55b' ,
299 'entrypoint' : 'bash' ,
305 'envs' : [ 'SECRET=password' ],
306 'ports' : [ 8080 , 8443 ],
308 '/CONFIG_DIR' : '/foo/conf' ,
309 'bar/config' : '/bar:ro'
314 'source=/CONFIG_DIR' ,
315 'destination=/foo/conf' ,
321 'destination=/bar:ro' ,
326 image
= 'docker.io/library/hello-world:latest'
329 def test_entrypoint ( self
):
330 self
. assertEqual ( self
. cc
. entrypoint
, 'bash' )
332 def test_uid_gid ( self
):
333 self
. assertEqual ( self
. cc
. uid
, 65534 )
334 self
. assertEqual ( self
. cc
. gid
, 1000 )
336 def test_ports ( self
):
337 self
. assertEqual ( self
. cc
. ports
, [ 8080 , 8443 ])
339 def test_get_container_args ( self
):
340 result
= self
. cc
. get_container_args ()
341 self
. assertEqual ( result
, [
346 def test_get_container_envs ( self
):
347 result
= self
. cc
. get_container_envs ()
348 self
. assertEqual ( result
, [ 'SECRET=password' ])
350 def test_get_container_mounts ( self
):
351 result
= self
. cc
. get_container_mounts ( '/xyz' )
352 self
. assertDictEqual ( result
, {
353 '/CONFIG_DIR' : '/foo/conf' ,
354 '/xyz/bar/config' : '/bar:ro'
357 def test_get_container_binds ( self
):
358 result
= self
. cc
. get_container_binds ( '/xyz' )
359 self
. assertEqual ( result
, [
362 'source=/CONFIG_DIR' ,
363 'destination=/foo/conf' ,
368 'source=/xyz/bar/config' ,
369 'destination=/bar:ro' ,