reload_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. package daemon // import "github.com/docker/docker/daemon"
  2. import (
  3. "os"
  4. "reflect"
  5. "sort"
  6. "testing"
  7. "time"
  8. "github.com/docker/docker/daemon/config"
  9. "github.com/docker/docker/daemon/images"
  10. "github.com/docker/docker/pkg/discovery"
  11. _ "github.com/docker/docker/pkg/discovery/memory"
  12. "github.com/docker/docker/registry"
  13. "github.com/docker/libnetwork"
  14. "github.com/sirupsen/logrus"
  15. "gotest.tools/v3/assert"
  16. is "gotest.tools/v3/assert/cmp"
  17. )
  18. // muteLogs suppresses logs that are generated during the test
  19. func muteLogs() {
  20. logrus.SetLevel(logrus.ErrorLevel)
  21. }
  22. func TestDaemonReloadLabels(t *testing.T) {
  23. daemon := &Daemon{
  24. configStore: &config.Config{
  25. CommonConfig: config.CommonConfig{
  26. Labels: []string{"foo:bar"},
  27. },
  28. },
  29. imageService: images.NewImageService(images.ImageServiceConfig{}),
  30. }
  31. muteLogs()
  32. valuesSets := make(map[string]interface{})
  33. valuesSets["labels"] = "foo:baz"
  34. newConfig := &config.Config{
  35. CommonConfig: config.CommonConfig{
  36. Labels: []string{"foo:baz"},
  37. ValuesSet: valuesSets,
  38. },
  39. }
  40. if err := daemon.Reload(newConfig); err != nil {
  41. t.Fatal(err)
  42. }
  43. label := daemon.configStore.Labels[0]
  44. if label != "foo:baz" {
  45. t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
  46. }
  47. }
  48. func TestDaemonReloadAllowNondistributableArtifacts(t *testing.T) {
  49. daemon := &Daemon{
  50. configStore: &config.Config{},
  51. imageService: images.NewImageService(images.ImageServiceConfig{}),
  52. }
  53. muteLogs()
  54. var err error
  55. // Initialize daemon with some registries.
  56. daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
  57. AllowNondistributableArtifacts: []string{
  58. "127.0.0.0/8",
  59. "10.10.1.11:5000",
  60. "10.10.1.22:5000", // This will be removed during reload.
  61. "docker1.com",
  62. "docker2.com", // This will be removed during reload.
  63. },
  64. })
  65. if err != nil {
  66. t.Fatal(err)
  67. }
  68. registries := []string{
  69. "127.0.0.0/8",
  70. "10.10.1.11:5000",
  71. "10.10.1.33:5000", // This will be added during reload.
  72. "docker1.com",
  73. "docker3.com", // This will be added during reload.
  74. }
  75. newConfig := &config.Config{
  76. CommonConfig: config.CommonConfig{
  77. ServiceOptions: registry.ServiceOptions{
  78. AllowNondistributableArtifacts: registries,
  79. },
  80. ValuesSet: map[string]interface{}{
  81. "allow-nondistributable-artifacts": registries,
  82. },
  83. },
  84. }
  85. if err := daemon.Reload(newConfig); err != nil {
  86. t.Fatal(err)
  87. }
  88. var actual []string
  89. serviceConfig := daemon.RegistryService.ServiceConfig()
  90. for _, value := range serviceConfig.AllowNondistributableArtifactsCIDRs {
  91. actual = append(actual, value.String())
  92. }
  93. actual = append(actual, serviceConfig.AllowNondistributableArtifactsHostnames...)
  94. sort.Strings(registries)
  95. sort.Strings(actual)
  96. assert.Check(t, is.DeepEqual(registries, actual))
  97. }
  98. func TestDaemonReloadMirrors(t *testing.T) {
  99. daemon := &Daemon{
  100. imageService: images.NewImageService(images.ImageServiceConfig{}),
  101. }
  102. muteLogs()
  103. var err error
  104. daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
  105. InsecureRegistries: []string{},
  106. Mirrors: []string{
  107. "https://mirror.test1.example.com",
  108. "https://mirror.test2.example.com", // this will be removed when reloading
  109. "https://mirror.test3.example.com", // this will be removed when reloading
  110. },
  111. })
  112. if err != nil {
  113. t.Fatal(err)
  114. }
  115. daemon.configStore = &config.Config{}
  116. type pair struct {
  117. valid bool
  118. mirrors []string
  119. after []string
  120. }
  121. loadMirrors := []pair{
  122. {
  123. valid: false,
  124. mirrors: []string{"10.10.1.11:5000"}, // this mirror is invalid
  125. after: []string{},
  126. },
  127. {
  128. valid: false,
  129. mirrors: []string{"mirror.test1.com"}, // this mirror is invalid
  130. after: []string{},
  131. },
  132. {
  133. valid: false,
  134. mirrors: []string{"10.10.1.11:5000", "mirror.test1.example.com"}, // mirrors are invalid
  135. after: []string{},
  136. },
  137. {
  138. valid: true,
  139. mirrors: []string{"https://mirror.test1.example.com", "https://mirror.test4.example.com"},
  140. after: []string{"https://mirror.test1.example.com/", "https://mirror.test4.example.com/"},
  141. },
  142. }
  143. for _, value := range loadMirrors {
  144. valuesSets := make(map[string]interface{})
  145. valuesSets["registry-mirrors"] = value.mirrors
  146. newConfig := &config.Config{
  147. CommonConfig: config.CommonConfig{
  148. ServiceOptions: registry.ServiceOptions{
  149. Mirrors: value.mirrors,
  150. },
  151. ValuesSet: valuesSets,
  152. },
  153. }
  154. err := daemon.Reload(newConfig)
  155. if !value.valid && err == nil {
  156. // mirrors should be invalid, should be a non-nil error
  157. t.Fatalf("Expected daemon reload error with invalid mirrors: %s, while get nil", value.mirrors)
  158. }
  159. if value.valid {
  160. if err != nil {
  161. // mirrors should be valid, should be no error
  162. t.Fatal(err)
  163. }
  164. registryService := daemon.RegistryService.ServiceConfig()
  165. if len(registryService.Mirrors) != len(value.after) {
  166. t.Fatalf("Expected %d daemon mirrors %s while get %d with %s",
  167. len(value.after),
  168. value.after,
  169. len(registryService.Mirrors),
  170. registryService.Mirrors)
  171. }
  172. dataMap := map[string]struct{}{}
  173. for _, mirror := range registryService.Mirrors {
  174. if _, exist := dataMap[mirror]; !exist {
  175. dataMap[mirror] = struct{}{}
  176. }
  177. }
  178. for _, address := range value.after {
  179. if _, exist := dataMap[address]; !exist {
  180. t.Fatalf("Expected %s in daemon mirrors, while get none", address)
  181. }
  182. }
  183. }
  184. }
  185. }
  186. func TestDaemonReloadInsecureRegistries(t *testing.T) {
  187. daemon := &Daemon{
  188. imageService: images.NewImageService(images.ImageServiceConfig{}),
  189. }
  190. muteLogs()
  191. var err error
  192. // initialize daemon with existing insecure registries: "127.0.0.0/8", "10.10.1.11:5000", "10.10.1.22:5000"
  193. daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
  194. InsecureRegistries: []string{
  195. "127.0.0.0/8",
  196. "10.10.1.11:5000",
  197. "10.10.1.22:5000", // this will be removed when reloading
  198. "docker1.example.com",
  199. "docker2.example.com", // this will be removed when reloading
  200. },
  201. })
  202. if err != nil {
  203. t.Fatal(err)
  204. }
  205. daemon.configStore = &config.Config{}
  206. insecureRegistries := []string{
  207. "127.0.0.0/8", // this will be kept
  208. "10.10.1.11:5000", // this will be kept
  209. "10.10.1.33:5000", // this will be newly added
  210. "docker1.example.com", // this will be kept
  211. "docker3.example.com", // this will be newly added
  212. }
  213. valuesSets := make(map[string]interface{})
  214. valuesSets["insecure-registries"] = insecureRegistries
  215. newConfig := &config.Config{
  216. CommonConfig: config.CommonConfig{
  217. ServiceOptions: registry.ServiceOptions{
  218. InsecureRegistries: insecureRegistries,
  219. },
  220. ValuesSet: valuesSets,
  221. },
  222. }
  223. if err := daemon.Reload(newConfig); err != nil {
  224. t.Fatal(err)
  225. }
  226. // After Reload, daemon.RegistryService will be changed which is useful
  227. // for registry communication in daemon.
  228. registries := daemon.RegistryService.ServiceConfig()
  229. // After Reload(), newConfig has come to registries.InsecureRegistryCIDRs and registries.IndexConfigs in daemon.
  230. // Then collect registries.InsecureRegistryCIDRs in dataMap.
  231. // When collecting, we need to convert CIDRS into string as a key,
  232. // while the times of key appears as value.
  233. dataMap := map[string]int{}
  234. for _, value := range registries.InsecureRegistryCIDRs {
  235. if _, ok := dataMap[value.String()]; !ok {
  236. dataMap[value.String()] = 1
  237. } else {
  238. dataMap[value.String()]++
  239. }
  240. }
  241. for _, value := range registries.IndexConfigs {
  242. if _, ok := dataMap[value.Name]; !ok {
  243. dataMap[value.Name] = 1
  244. } else {
  245. dataMap[value.Name]++
  246. }
  247. }
  248. // Finally compare dataMap with the original insecureRegistries.
  249. // Each value in insecureRegistries should appear in daemon's insecure registries,
  250. // and each can only appear exactly ONCE.
  251. for _, r := range insecureRegistries {
  252. if value, ok := dataMap[r]; !ok {
  253. t.Fatalf("Expected daemon insecure registry %s, got none", r)
  254. } else if value != 1 {
  255. t.Fatalf("Expected only 1 daemon insecure registry %s, got %d", r, value)
  256. }
  257. }
  258. // assert if "10.10.1.22:5000" is removed when reloading
  259. if value, ok := dataMap["10.10.1.22:5000"]; ok {
  260. t.Fatalf("Expected no insecure registry of 10.10.1.22:5000, got %d", value)
  261. }
  262. // assert if "docker2.com" is removed when reloading
  263. if value, ok := dataMap["docker2.example.com"]; ok {
  264. t.Fatalf("Expected no insecure registry of docker2.com, got %d", value)
  265. }
  266. }
  267. func TestDaemonReloadNotAffectOthers(t *testing.T) {
  268. daemon := &Daemon{
  269. imageService: images.NewImageService(images.ImageServiceConfig{}),
  270. }
  271. muteLogs()
  272. daemon.configStore = &config.Config{
  273. CommonConfig: config.CommonConfig{
  274. Labels: []string{"foo:bar"},
  275. Debug: true,
  276. },
  277. }
  278. valuesSets := make(map[string]interface{})
  279. valuesSets["labels"] = "foo:baz"
  280. newConfig := &config.Config{
  281. CommonConfig: config.CommonConfig{
  282. Labels: []string{"foo:baz"},
  283. ValuesSet: valuesSets,
  284. },
  285. }
  286. if err := daemon.Reload(newConfig); err != nil {
  287. t.Fatal(err)
  288. }
  289. label := daemon.configStore.Labels[0]
  290. if label != "foo:baz" {
  291. t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
  292. }
  293. debug := daemon.configStore.Debug
  294. if !debug {
  295. t.Fatal("Expected debug 'enabled', got 'disabled'")
  296. }
  297. }
  298. func TestDaemonDiscoveryReload(t *testing.T) {
  299. daemon := &Daemon{
  300. imageService: images.NewImageService(images.ImageServiceConfig{}),
  301. }
  302. muteLogs()
  303. daemon.configStore = &config.Config{
  304. CommonConfig: config.CommonConfig{
  305. ClusterStore: "memory://127.0.0.1",
  306. ClusterAdvertise: "127.0.0.1:3333",
  307. },
  308. }
  309. if err := daemon.initDiscovery(daemon.configStore); err != nil {
  310. t.Fatal(err)
  311. }
  312. expected := discovery.Entries{
  313. &discovery.Entry{Host: "127.0.0.1", Port: "3333"},
  314. }
  315. select {
  316. case <-time.After(10 * time.Second):
  317. t.Fatal("timeout waiting for discovery")
  318. case <-daemon.discoveryWatcher.ReadyCh():
  319. }
  320. stopCh := make(chan struct{})
  321. defer close(stopCh)
  322. ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
  323. select {
  324. case <-time.After(1 * time.Second):
  325. t.Fatal("failed to get discovery advertisements in time")
  326. case e := <-ch:
  327. if !reflect.DeepEqual(e, expected) {
  328. t.Fatalf("expected %v, got %v\n", expected, e)
  329. }
  330. case e := <-errCh:
  331. t.Fatal(e)
  332. }
  333. valuesSets := make(map[string]interface{})
  334. valuesSets["cluster-store"] = "memory://127.0.0.1:2222"
  335. valuesSets["cluster-advertise"] = "127.0.0.1:5555"
  336. newConfig := &config.Config{
  337. CommonConfig: config.CommonConfig{
  338. ClusterStore: "memory://127.0.0.1:2222",
  339. ClusterAdvertise: "127.0.0.1:5555",
  340. ValuesSet: valuesSets,
  341. },
  342. }
  343. expected = discovery.Entries{
  344. &discovery.Entry{Host: "127.0.0.1", Port: "5555"},
  345. }
  346. if err := daemon.Reload(newConfig); err != nil {
  347. t.Fatal(err)
  348. }
  349. select {
  350. case <-time.After(10 * time.Second):
  351. t.Fatal("timeout waiting for discovery")
  352. case <-daemon.discoveryWatcher.ReadyCh():
  353. }
  354. ch, errCh = daemon.discoveryWatcher.Watch(stopCh)
  355. select {
  356. case <-time.After(1 * time.Second):
  357. t.Fatal("failed to get discovery advertisements in time")
  358. case e := <-ch:
  359. if !reflect.DeepEqual(e, expected) {
  360. t.Fatalf("expected %v, got %v\n", expected, e)
  361. }
  362. case e := <-errCh:
  363. t.Fatal(e)
  364. }
  365. }
  366. func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
  367. daemon := &Daemon{
  368. imageService: images.NewImageService(images.ImageServiceConfig{}),
  369. }
  370. daemon.configStore = &config.Config{}
  371. muteLogs()
  372. valuesSet := make(map[string]interface{})
  373. valuesSet["cluster-store"] = "memory://127.0.0.1:2222"
  374. valuesSet["cluster-advertise"] = "127.0.0.1:5555"
  375. newConfig := &config.Config{
  376. CommonConfig: config.CommonConfig{
  377. ClusterStore: "memory://127.0.0.1:2222",
  378. ClusterAdvertise: "127.0.0.1:5555",
  379. ValuesSet: valuesSet,
  380. },
  381. }
  382. expected := discovery.Entries{
  383. &discovery.Entry{Host: "127.0.0.1", Port: "5555"},
  384. }
  385. if err := daemon.Reload(newConfig); err != nil {
  386. t.Fatal(err)
  387. }
  388. select {
  389. case <-time.After(10 * time.Second):
  390. t.Fatal("timeout waiting for discovery")
  391. case <-daemon.discoveryWatcher.ReadyCh():
  392. }
  393. stopCh := make(chan struct{})
  394. defer close(stopCh)
  395. ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
  396. select {
  397. case <-time.After(1 * time.Second):
  398. t.Fatal("failed to get discovery advertisements in time")
  399. case e := <-ch:
  400. if !reflect.DeepEqual(e, expected) {
  401. t.Fatalf("expected %v, got %v\n", expected, e)
  402. }
  403. case e := <-errCh:
  404. t.Fatal(e)
  405. }
  406. }
  407. func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) {
  408. daemon := &Daemon{
  409. imageService: images.NewImageService(images.ImageServiceConfig{}),
  410. }
  411. daemon.configStore = &config.Config{
  412. CommonConfig: config.CommonConfig{
  413. ClusterStore: "memory://127.0.0.1",
  414. },
  415. }
  416. valuesSets := make(map[string]interface{})
  417. valuesSets["cluster-advertise"] = "127.0.0.1:5555"
  418. newConfig := &config.Config{
  419. CommonConfig: config.CommonConfig{
  420. ClusterAdvertise: "127.0.0.1:5555",
  421. ValuesSet: valuesSets,
  422. },
  423. }
  424. expected := discovery.Entries{
  425. &discovery.Entry{Host: "127.0.0.1", Port: "5555"},
  426. }
  427. if err := daemon.Reload(newConfig); err != nil {
  428. t.Fatal(err)
  429. }
  430. select {
  431. case <-daemon.discoveryWatcher.ReadyCh():
  432. case <-time.After(10 * time.Second):
  433. t.Fatal("Timeout waiting for discovery")
  434. }
  435. stopCh := make(chan struct{})
  436. defer close(stopCh)
  437. ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
  438. select {
  439. case <-time.After(1 * time.Second):
  440. t.Fatal("failed to get discovery advertisements in time")
  441. case e := <-ch:
  442. if !reflect.DeepEqual(e, expected) {
  443. t.Fatalf("expected %v, got %v\n", expected, e)
  444. }
  445. case e := <-errCh:
  446. t.Fatal(e)
  447. }
  448. }
  449. func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) {
  450. if os.Getuid() != 0 {
  451. t.Skip("root required")
  452. }
  453. daemon := &Daemon{
  454. imageService: images.NewImageService(images.ImageServiceConfig{}),
  455. }
  456. daemon.configStore = &config.Config{}
  457. valuesSet := make(map[string]interface{})
  458. valuesSet["network-diagnostic-port"] = 2000
  459. enableConfig := &config.Config{
  460. CommonConfig: config.CommonConfig{
  461. NetworkDiagnosticPort: 2000,
  462. ValuesSet: valuesSet,
  463. },
  464. }
  465. disableConfig := &config.Config{
  466. CommonConfig: config.CommonConfig{},
  467. }
  468. netOptions, err := daemon.networkOptions(enableConfig, nil, nil)
  469. if err != nil {
  470. t.Fatal(err)
  471. }
  472. controller, err := libnetwork.New(netOptions...)
  473. if err != nil {
  474. t.Fatal(err)
  475. }
  476. daemon.netController = controller
  477. // Enable/Disable the server for some iterations
  478. for i := 0; i < 10; i++ {
  479. enableConfig.CommonConfig.NetworkDiagnosticPort++
  480. if err := daemon.Reload(enableConfig); err != nil {
  481. t.Fatal(err)
  482. }
  483. // Check that the diagnostic is enabled
  484. if !daemon.netController.IsDiagnosticEnabled() {
  485. t.Fatalf("diagnostic should be enable")
  486. }
  487. // Reload
  488. if err := daemon.Reload(disableConfig); err != nil {
  489. t.Fatal(err)
  490. }
  491. // Check that the diagnostic is disabled
  492. if daemon.netController.IsDiagnosticEnabled() {
  493. t.Fatalf("diagnostic should be disable")
  494. }
  495. }
  496. enableConfig.CommonConfig.NetworkDiagnosticPort++
  497. // 2 times the enable should not create problems
  498. if err := daemon.Reload(enableConfig); err != nil {
  499. t.Fatal(err)
  500. }
  501. // Check that the diagnostic is enabled
  502. if !daemon.netController.IsDiagnosticEnabled() {
  503. t.Fatalf("diagnostic should be enable")
  504. }
  505. // Check that another reload does not cause issues
  506. if err := daemon.Reload(enableConfig); err != nil {
  507. t.Fatal(err)
  508. }
  509. // Check that the diagnostic is enable
  510. if !daemon.netController.IsDiagnosticEnabled() {
  511. t.Fatalf("diagnostic should be enable")
  512. }
  513. }