foreman_netbox 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (156) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +619 -0
  3. data/README.md +50 -0
  4. data/Rakefile +50 -0
  5. data/app/contracts/foreman_netbox/device_contract.rb +42 -0
  6. data/app/contracts/foreman_netbox/params/interface_params.rb +16 -0
  7. data/app/contracts/foreman_netbox/params/ip_address_params.rb +15 -0
  8. data/app/contracts/foreman_netbox/params/tenant_params.rb +13 -0
  9. data/app/contracts/foreman_netbox/virtual_machine_contract.rb +29 -0
  10. data/app/interactors/foreman_netbox/concerns/facts.rb +11 -0
  11. data/app/interactors/foreman_netbox/concerns/primary_ips.rb +25 -0
  12. data/app/interactors/foreman_netbox/delete_host/delete_device.rb +20 -0
  13. data/app/interactors/foreman_netbox/delete_host/delete_virtual_machine.rb +20 -0
  14. data/app/interactors/foreman_netbox/delete_host/organizer.rb +12 -0
  15. data/app/interactors/foreman_netbox/sync_host/organizer.rb +35 -0
  16. data/app/interactors/foreman_netbox/sync_host/sync_device/create.rb +36 -0
  17. data/app/interactors/foreman_netbox/sync_host/sync_device/find.rb +41 -0
  18. data/app/interactors/foreman_netbox/sync_host/sync_device/organizer.rb +30 -0
  19. data/app/interactors/foreman_netbox/sync_host/sync_device/save_netbox_url.rb +29 -0
  20. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_role/create.rb +32 -0
  21. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_role/find.rb +28 -0
  22. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_role/organizer.rb +20 -0
  23. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/create.rb +34 -0
  24. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/find.rb +28 -0
  25. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/organizer.rb +22 -0
  26. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/sync_manufacturer/create.rb +34 -0
  27. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/sync_manufacturer/find.rb +40 -0
  28. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/sync_manufacturer/organizer.rb +22 -0
  29. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/update.rb +33 -0
  30. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/create.rb +37 -0
  31. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/delete.rb +36 -0
  32. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/find.rb +30 -0
  33. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/organizer.rb +23 -0
  34. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/create.rb +46 -0
  35. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/delete.rb +40 -0
  36. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/find.rb +32 -0
  37. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/organizer.rb +24 -0
  38. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/update.rb +39 -0
  39. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/update.rb +38 -0
  40. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_site/create.rb +32 -0
  41. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_site/find.rb +28 -0
  42. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_site/organizer.rb +25 -0
  43. data/app/interactors/foreman_netbox/sync_host/sync_device/sync_site/update.rb +35 -0
  44. data/app/interactors/foreman_netbox/sync_host/sync_device/update.rb +85 -0
  45. data/app/interactors/foreman_netbox/sync_host/sync_device/validate.rb +25 -0
  46. data/app/interactors/foreman_netbox/sync_host/sync_tenant/create.rb +30 -0
  47. data/app/interactors/foreman_netbox/sync_host/sync_tenant/find.rb +26 -0
  48. data/app/interactors/foreman_netbox/sync_host/sync_tenant/organizer.rb +19 -0
  49. data/app/interactors/foreman_netbox/sync_host/sync_tenant/update.rb +33 -0
  50. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/create.rb +34 -0
  51. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/find.rb +34 -0
  52. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/organizer.rb +28 -0
  53. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/save_netbox_url.rb +31 -0
  54. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/create.rb +35 -0
  55. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/find.rb +28 -0
  56. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/organizer.rb +22 -0
  57. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/sync_cluster_type/create.rb +34 -0
  58. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/sync_cluster_type/find.rb +32 -0
  59. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/sync_cluster_type/organizer.rb +22 -0
  60. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/update.rb +35 -0
  61. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/create.rb +33 -0
  62. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/delete.rb +36 -0
  63. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/find.rb +30 -0
  64. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/organizer.rb +23 -0
  65. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/create.rb +46 -0
  66. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/delete.rb +40 -0
  67. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/find.rb +28 -0
  68. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/organizer.rb +24 -0
  69. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/update.rb +39 -0
  70. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/update.rb +38 -0
  71. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/update.rb +82 -0
  72. data/app/interactors/foreman_netbox/sync_host/sync_virtual_machine/validate.rb +25 -0
  73. data/app/jobs/foreman_netbox/sync_host_job.rb +19 -0
  74. data/app/lib/foreman_netbox/api.rb +12 -0
  75. data/app/models/concerns/foreman_netbox/host_extensions.rb +27 -0
  76. data/app/models/concerns/foreman_netbox/location_extensions.rb +13 -0
  77. data/app/models/concerns/foreman_netbox/nic/base_extensions.rb +23 -0
  78. data/app/models/concerns/foreman_netbox/user_usergroup_common_extensions.rb +18 -0
  79. data/app/models/foreman_netbox/netbox_facet.rb +34 -0
  80. data/app/models/orchestration/netbox.rb +64 -0
  81. data/app/models/setting/netbox.rb +32 -0
  82. data/app/services/foreman_netbox/cached_netbox_parameters.rb +103 -0
  83. data/app/services/foreman_netbox/netbox_parameters.rb +185 -0
  84. data/app/services/foreman_netbox/netbox_parameters_comparator.rb +96 -0
  85. data/app/views/hosts/_netbox_tab.html.erb +28 -0
  86. data/config/routes.rb +4 -0
  87. data/db/migrate/20200527135812_create_netbox_facet.rb +12 -0
  88. data/db/migrate/20200604141933_add_sync_info_to_netbox_facet.rb +8 -0
  89. data/db/migrate/20200708093607_add_raw_data_to_netbox_facet.rb +7 -0
  90. data/lib/foreman_netbox.rb +6 -0
  91. data/lib/foreman_netbox/engine.rb +64 -0
  92. data/lib/foreman_netbox/version.rb +5 -0
  93. data/lib/tasks/foreman_netbox_tasks.rake +67 -0
  94. data/test/factories/host.rb +17 -0
  95. data/test/factories/netbox_facet.rb +17 -0
  96. data/test/fixtures/facts/k8s_physical_host.json +328 -0
  97. data/test/fixtures/facts/rhel_physical_host.json +512 -0
  98. data/test/fixtures/facts/rhel_virtual_host.json +455 -0
  99. data/test/fixtures/netbox_device_raw_data.json +330 -0
  100. data/test/fixtures/netbox_virtual_machine_raw_data.json +241 -0
  101. data/test/integration/foreman_netbox/sync_k8s_physical_host_test.rb +81 -0
  102. data/test/integration/foreman_netbox/sync_rhel_physical_host_test.rb +81 -0
  103. data/test/integration/foreman_netbox/sync_rhel_virtual_host_test.rb +93 -0
  104. data/test/interactors/foreman_netbox/sync_host/organizer_test.rb +78 -0
  105. data/test/interactors/foreman_netbox/sync_host/sync_device/create_test.rb +65 -0
  106. data/test/interactors/foreman_netbox/sync_host/sync_device/find_test.rb +105 -0
  107. data/test/interactors/foreman_netbox/sync_host/sync_device/save_netbox_url_test.rb +39 -0
  108. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_device_role/create_test.rb +45 -0
  109. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_device_role/find_test.rb +58 -0
  110. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/create_test.rb +55 -0
  111. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/find_test.rb +63 -0
  112. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/sync_manufacturer/create_test.rb +48 -0
  113. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/sync_manufacturer/find_test.rb +105 -0
  114. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_device_type/update_test.rb +54 -0
  115. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/create_test.rb +51 -0
  116. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/delete_test.rb +41 -0
  117. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/find_test.rb +53 -0
  118. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/create_test.rb +80 -0
  119. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/delete_test.rb +72 -0
  120. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/find_test.rb +51 -0
  121. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/sync_ip_addresses/update_test.rb +64 -0
  122. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_interfaces/update_test.rb +92 -0
  123. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_site/create_test.rb +51 -0
  124. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_site/find_test.rb +59 -0
  125. data/test/interactors/foreman_netbox/sync_host/sync_device/sync_site/update_test.rb +54 -0
  126. data/test/interactors/foreman_netbox/sync_host/sync_device/update_test.rb +188 -0
  127. data/test/interactors/foreman_netbox/sync_host/sync_tenant/create_test.rb +50 -0
  128. data/test/interactors/foreman_netbox/sync_host/sync_tenant/find_test.rb +58 -0
  129. data/test/interactors/foreman_netbox/sync_host/sync_tenant/update_test.rb +59 -0
  130. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/create_test.rb +74 -0
  131. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/find_test.rb +77 -0
  132. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/save_netbox_url_test.rb +39 -0
  133. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/create_test.rb +54 -0
  134. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/find_test.rb +58 -0
  135. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/sync_cluster_type/create_test.rb +50 -0
  136. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/sync_cluster_type/find_test.rb +65 -0
  137. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_cluster/update_test.rb +54 -0
  138. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/create_test.rb +53 -0
  139. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/delete_test.rb +37 -0
  140. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/find_test.rb +53 -0
  141. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/create_test.rb +80 -0
  142. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/delete_test.rb +73 -0
  143. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/find_test.rb +51 -0
  144. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/sync_ip_addresses/update_test.rb +64 -0
  145. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/sync_interfaces/update_test.rb +88 -0
  146. data/test/interactors/foreman_netbox/sync_host/sync_virtual_machine/update_test.rb +171 -0
  147. data/test/jobs/foreman_netbox/sync_host_job_test.rb +14 -0
  148. data/test/models/foreman_netbox/location_test.rb +42 -0
  149. data/test/models/foreman_netbox/netbox_facet_test.rb +219 -0
  150. data/test/models/foreman_netbox/nics/base_test.rb +81 -0
  151. data/test/models/foreman_netbox/usergroup_test.rb +23 -0
  152. data/test/models/host/managed_test.rb +63 -0
  153. data/test/services/foreman_netbox/netbox_attributes_test.rb +278 -0
  154. data/test/services/foreman_netbox/netbox_parameters_comparator_test.rb +136 -0
  155. data/test/test_plugin_helper.rb +25 -0
  156. metadata +343 -0
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ class SyncK8sPhysicalHostTest < ActiveSupport::TestCase
6
+ setup do
7
+ setup_netbox_integration_test
8
+ end
9
+
10
+ subject { ForemanNetbox::SyncHost::Organizer.call(host: host) }
11
+
12
+ let(:hostname) { 'k8s_physical_host' }
13
+ let(:file) { file_fixture("facts/#{hostname}.json").read }
14
+ let(:facts_json) { JSON.parse(file) }
15
+ let(:host) do
16
+ FactoryBot.build_stubbed(
17
+ :host,
18
+ hostname: "#{hostname}.tier.example.com",
19
+ owner: FactoryBot.build_stubbed(:usergroup, name: 'Owner'),
20
+ location: FactoryBot.build_stubbed(:location, name: 'Location'),
21
+ interfaces: [
22
+ FactoryBot.build_stubbed(
23
+ :nic_base,
24
+ identifier: 'eth0',
25
+ mac: 'C3:CD:63:54:21:60',
26
+ ip: '10.0.0.7',
27
+ subnet: FactoryBot.build_stubbed(:subnet_ipv4, organizations: [], locations: [])
28
+ ),
29
+ FactoryBot.build_stubbed(
30
+ :nic_base,
31
+ identifier: 'eth1',
32
+ mac: '45:E9:6A:83:02:20',
33
+ ip6: '1600:0:2d0:202::17',
34
+ subnet6: FactoryBot.build_stubbed(:subnet_ipv6, organizations: [], locations: [])
35
+ )
36
+ ]
37
+ ).tap do |host|
38
+ host.stubs(:ip).returns(host.interfaces.find(&:ip).ip)
39
+ host.stubs(:ip6).returns(host.interfaces.find(&:ip6).ip6)
40
+ host.stubs(:compute?).returns(false)
41
+ host.stubs(:facts).returns(facts_json)
42
+ end
43
+ end
44
+
45
+ test 'sync host' do
46
+ ForemanNetbox::NetboxFacet.any_instance.expects(:update).twice.returns(true)
47
+
48
+ assert subject.success?
49
+
50
+ assert_equal host.name, subject.device.name
51
+ assert_equal host.owner.netbox_tenant_name, subject.device.tenant.name
52
+ assert_equal host.location.netbox_site_name, subject.device.site.name
53
+ assert_equal host.facts['manufacturer'], subject.device.device_type.manufacturer.name
54
+ assert_equal host.facts['productname'], subject.device.device_type.model
55
+ assert_equal host.facts['serialnumber'], subject.device.serial
56
+
57
+ assert_equal IPAddress.parse("#{host.ip}/24"), subject.device.primary_ip4.address
58
+ assert_equal IPAddress.parse("#{host.ip6}/64"), subject.device.primary_ip6.address
59
+ host.interfaces.each do |h_interface|
60
+ nx_interface = subject.interfaces.find { |i| i.name == h_interface.identifier }
61
+
62
+ assert nx_interface.present?
63
+
64
+ h_interface.netbox_ips.each do |h_ip|
65
+ assert subject.ip_addresses.find { |nx_ip| nx_ip.interface.id == nx_interface.id && nx_ip.address == IPAddress.parse(h_ip) }.present?
66
+ end
67
+ end
68
+
69
+ expected_tags = ForemanNetbox::NetboxParameters::DEFAULT_TAGS
70
+ assert_equal expected_tags, subject.device.tags
71
+ assert_equal expected_tags, subject.device_type.tags
72
+ assert_equal expected_tags, subject.site.tags
73
+ assert_equal expected_tags, subject.tenant.tags
74
+ subject.interfaces.reload.each do |interface|
75
+ assert_equal expected_tags, interface.tags
76
+ end
77
+ subject.ip_addresses.reload.each do |interface|
78
+ assert_equal expected_tags, interface.tags
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ class SyncRhelPhysicalHostTest < ActiveSupport::TestCase
6
+ setup do
7
+ setup_netbox_integration_test
8
+ end
9
+
10
+ subject { ForemanNetbox::SyncHost::Organizer.call(host: host) }
11
+
12
+ let(:hostname) { 'rhel_physical_host' }
13
+ let(:file) { file_fixture("facts/#{hostname}.json").read }
14
+ let(:facts_json) { JSON.parse(file) }
15
+ let(:host) do
16
+ FactoryBot.build_stubbed(
17
+ :host,
18
+ hostname: "#{hostname}.tier.example.com",
19
+ owner: FactoryBot.build_stubbed(:usergroup, name: SecureRandom.hex(16)),
20
+ location: FactoryBot.build_stubbed(:location, name: 'Location'),
21
+ interfaces: [
22
+ FactoryBot.build_stubbed(
23
+ :nic_base,
24
+ identifier: 'eth0',
25
+ mac: 'C3:CD:63:54:21:61',
26
+ ip: '10.0.0.8',
27
+ subnet: FactoryBot.build_stubbed(:subnet_ipv4, organizations: [], locations: [])
28
+ ),
29
+ FactoryBot.build_stubbed(
30
+ :nic_base,
31
+ identifier: 'eth1',
32
+ mac: '45:E9:6A:83:02:21',
33
+ ip6: '1600:0:2d0:202::18',
34
+ subnet6: FactoryBot.build_stubbed(:subnet_ipv6, organizations: [], locations: [])
35
+ )
36
+ ]
37
+ ).tap do |host|
38
+ host.stubs(:ip).returns(host.interfaces.find(&:ip).ip)
39
+ host.stubs(:ip6).returns(host.interfaces.find(&:ip6).ip6)
40
+ host.stubs(:compute?).returns(false)
41
+ host.stubs(:facts).returns(facts_json)
42
+ end
43
+ end
44
+
45
+ test 'sync host' do
46
+ ForemanNetbox::NetboxFacet.any_instance.expects(:update).twice.returns(true)
47
+
48
+ assert subject.success?
49
+
50
+ assert_equal host.name, subject.device.name
51
+ assert_equal host.owner.netbox_tenant_name, subject.device.tenant.name
52
+ assert_equal host.location.netbox_site_name, subject.device.site.name
53
+ assert_equal host.facts['manufacturer'], subject.device.device_type.manufacturer.name
54
+ assert_equal host.facts['productname'], subject.device.device_type.model
55
+ assert_equal host.facts['serialnumber'], subject.device.serial
56
+
57
+ assert_equal IPAddress.parse("#{host.ip}/24"), subject.device.primary_ip4.address
58
+ assert_equal IPAddress.parse("#{host.ip6}/64"), subject.device.primary_ip6.address
59
+ host.interfaces.each do |h_interface|
60
+ nx_interface = subject.interfaces.find { |i| i.name == h_interface.identifier }
61
+
62
+ assert nx_interface.present?
63
+
64
+ h_interface.netbox_ips.each do |h_ip|
65
+ assert subject.ip_addresses.find { |nx_ip| nx_ip.interface.id == nx_interface.id && nx_ip.address == IPAddress.parse(h_ip) }.present?
66
+ end
67
+ end
68
+
69
+ expected_tags = ForemanNetbox::NetboxParameters::DEFAULT_TAGS
70
+ assert_equal expected_tags, subject.device.tags
71
+ assert_equal expected_tags, subject.device_type.tags
72
+ assert_equal expected_tags, subject.site.tags
73
+ assert_equal expected_tags, subject.tenant.tags
74
+ subject.interfaces.reload.each do |interface|
75
+ assert_equal expected_tags, interface.tags
76
+ end
77
+ subject.ip_addresses.reload.each do |interface|
78
+ assert_equal expected_tags, interface.tags
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ class SyncRhelVirtualHostTest < ActiveSupport::TestCase
6
+ setup do
7
+ setup_netbox_integration_test
8
+ end
9
+
10
+ subject { ForemanNetbox::SyncHost::Organizer.call(host: host) }
11
+
12
+ let(:hostname) { 'rhel_virtual_host' }
13
+ let(:file) { file_fixture("facts/#{hostname}.json").read }
14
+ let(:facts_json) { JSON.parse(file) }
15
+ let(:host) do
16
+ FactoryBot.build_stubbed(
17
+ :host,
18
+ hostname: "#{hostname}.tier.example.com",
19
+ owner: FactoryBot.build_stubbed(:usergroup, name: 'Owner'),
20
+ interfaces: [
21
+ FactoryBot.build_stubbed(
22
+ :nic_base,
23
+ identifier: 'eth0',
24
+ mac: 'C3:CD:63:54:21:62',
25
+ ip: '10.0.0.9',
26
+ subnet: FactoryBot.build_stubbed(:subnet_ipv4, organizations: [], locations: [])
27
+ ),
28
+ FactoryBot.build_stubbed(
29
+ :nic_base,
30
+ identifier: 'eth1',
31
+ mac: '45:E9:6A:83:02:22',
32
+ ip6: '1600:0:2d0:202::19',
33
+ subnet6: FactoryBot.build_stubbed(:subnet_ipv6, organizations: [], locations: [])
34
+ )
35
+ ]
36
+ ).tap do |host|
37
+ host.stubs(:ip).returns(host.interfaces.find(&:ip).ip)
38
+ host.stubs(:ip6).returns(host.interfaces.find(&:ip6).ip6)
39
+ host.stubs(:compute?).returns(true)
40
+ host.stubs(:compute_resource).returns(
41
+ OpenStruct.new(type: 'Foreman::Model::Vmware')
42
+ )
43
+ host.stubs(:compute_object).returns(
44
+ OpenStruct.new(
45
+ cluster: 'CLUSTER',
46
+ cpus: 1,
47
+ memory_mb: 1024,
48
+ volumes: [
49
+ OpenStruct.new(size_gb: 120)
50
+ ]
51
+ )
52
+ )
53
+ host.stubs(:facts).returns(facts_json)
54
+ end
55
+ end
56
+
57
+ test 'sync host' do
58
+ ForemanNetbox::NetboxFacet.any_instance.expects(:update).twice.returns(true)
59
+
60
+ assert subject.success?
61
+
62
+ assert_equal host.name, subject.virtual_machine.name
63
+ assert_equal host.owner.netbox_tenant_name, subject.virtual_machine.tenant.name
64
+ assert_equal host.compute_object.cpus, subject.virtual_machine.vcpus
65
+ assert_equal host.compute_object.memory_mb, subject.virtual_machine.memory
66
+ assert_equal host.compute_object.volumes.first.size_gb, subject.virtual_machine.disk
67
+ assert_equal host.compute_object.cluster, subject.virtual_machine.cluster.name
68
+ assert_equal 'VMware ESXi', subject.cluster_type.name
69
+
70
+ assert_equal IPAddress.parse("#{host.ip}/24"), subject.virtual_machine.primary_ip4.address
71
+ assert_equal IPAddress.parse("#{host.ip6}/64"), subject.virtual_machine.primary_ip6.address
72
+ host.interfaces.each do |h_interface|
73
+ nx_interface = subject.interfaces.find { |i| i.name == h_interface.identifier }
74
+
75
+ assert nx_interface.present?
76
+
77
+ h_interface.netbox_ips.each do |h_ip|
78
+ assert subject.ip_addresses.find { |nx_ip| nx_ip.interface.id == nx_interface.id && nx_ip.address == IPAddress.parse(h_ip) }.present?
79
+ end
80
+ end
81
+
82
+ expected_tags = ForemanNetbox::NetboxParameters::DEFAULT_TAGS
83
+ assert_equal expected_tags, subject.virtual_machine.tags
84
+ assert_equal expected_tags, subject.tenant.tags
85
+ assert_equal expected_tags, subject.cluster.tags
86
+ subject.interfaces.reload.each do |interface|
87
+ assert_equal expected_tags, interface.tags
88
+ end
89
+ subject.ip_addresses.reload.each do |interface|
90
+ assert_equal expected_tags, interface.tags
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ class SyncHostOrganizerTest < ActiveSupport::TestCase
6
+ subject { ForemanNetbox::SyncHost::Organizer.call(host: host) }
7
+
8
+ let(:host) do
9
+ FactoryBot.create(:host).tap do |host|
10
+ host.stubs(:interfaces).returns([])
11
+ host.stubs(:facts).returns({ serialnumber: 'abc123' })
12
+ end
13
+ end
14
+ let(:tags) { ForemanNetbox::NetboxParameters::DEFAULT_TAGS }
15
+
16
+ setup do
17
+ setup_default_netbox_settings
18
+ # rubocop:disable Layout/FirstArrayElementIndentation
19
+ stub_get_netbox_request('tenancy/tenants.json?limit=50&slug=admin-user', results: [
20
+ { id: 1, name: host.owner.name, slug: host.owner.name.parameterize, tags: tags }
21
+ ])
22
+ stub_get_netbox_request('dcim/sites.json?limit=50&slug=location-1', results: [
23
+ { id: 1, name: host.location.netbox_site_name, slug: host.location.netbox_site_slug, tags: tags }
24
+ ])
25
+ stub_get_netbox_request('dcim/device-roles.json?limit=50&slug=server', results: [
26
+ { id: 1, name: 'Device Role', slug: 'server' }
27
+ ])
28
+ stub_get_netbox_request('dcim/manufacturers.json?limit=50&slug=unknown', results: [
29
+ { id: 1, name: 'Unknown', slug: 'unknown' }
30
+ ])
31
+ stub_get_netbox_request('dcim/device-types.json?limit=50&slug=unknown', results: [
32
+ { id: 1, name: 'Unknown', slug: 'unknown', tags: tags }
33
+ ])
34
+ stub_get_netbox_request("dcim/devices.json?limit=50&serial=#{host.facts[:serialnumber]}", results: [
35
+ { id: 1, name: host.name, serial: host.facts[:serialnumber], tags: tags }
36
+ ])
37
+ stub_get_netbox_request('dcim/interfaces.json?device_id=1&limit=50', results: [])
38
+ stub_get_netbox_request('ipam/ip-addresses.json?device_id=1&limit=50', results: [])
39
+ # rubocop:enable Layout/FirstArrayElementIndentation
40
+ end
41
+
42
+ test 'save synchronization status when it succeeds' do
43
+ stub_request(:patch, "#{Setting::Netbox[:netbox_url]}/api/dcim/devices/1.json").to_return(
44
+ status: 200, headers: { 'Content-Type': 'application/json' },
45
+ body: { id: 1 }.to_json
46
+ )
47
+ subject
48
+ host.reload
49
+
50
+ assert_not_nil host.netbox_facet.synchronized_at
51
+ assert_equal "#{Setting::Netbox[:netbox_url]}/dcim/devices/1", host.netbox_facet.url
52
+ assert_nil host.netbox_facet.synchronization_error
53
+ end
54
+
55
+ test 'save synchronization status when it fails' do
56
+ stub_request(:patch, "#{Setting::Netbox[:netbox_url]}/api/dcim/devices/1.json").to_return(
57
+ status: 500, headers: { 'Content-Type': 'application/json' }
58
+ )
59
+ subject
60
+ host.reload
61
+
62
+ assert_not_nil host.netbox_facet.synchronized_at
63
+ assert_nil host.netbox_facet.url
64
+ assert_equal 'ForemanNetbox::SyncHost::SyncDevice::Update: 500 Remote Error', host.netbox_facet.synchronization_error
65
+ end
66
+
67
+ private
68
+
69
+ def stub_get_netbox_request(path, results:)
70
+ stub_request(:get, "#{Setting::Netbox[:netbox_url]}/api/#{path}").to_return(
71
+ status: 200, headers: { 'Content-Type': 'application/json' },
72
+ body: {
73
+ count: 1,
74
+ results: results
75
+ }.to_json
76
+ )
77
+ end
78
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ class CreateDeviceTest < ActiveSupport::TestCase
6
+ subject do
7
+ ForemanNetbox::SyncHost::SyncDevice::Create.call(
8
+ host: host,
9
+ netbox_params: host.netbox_facet.netbox_params,
10
+ device_type: device_type,
11
+ device_role: device_role,
12
+ site: site,
13
+ tenant: tenant,
14
+ device: device
15
+ )
16
+ end
17
+
18
+ let(:device_id) { 1 }
19
+ let(:host) do
20
+ FactoryBot.build_stubbed(:host, hostname: 'host.dev.example.com').tap do |host|
21
+ host.stubs(:facts).returns({ 'serialnumber' => 'abc123' })
22
+ end
23
+ end
24
+ let(:device_type) { OpenStruct.new(id: 1) }
25
+ let(:device_role) { OpenStruct.new(id: 1) }
26
+ let(:site) { OpenStruct.new(id: 1) }
27
+ let(:tenant) { OpenStruct.new(id: 1) }
28
+ let(:netbox_device_params) { host.netbox_facet.netbox_params.fetch(:device) }
29
+
30
+ setup do
31
+ setup_default_netbox_settings
32
+ end
33
+
34
+ context 'when device is not assigned to the context' do
35
+ let(:device) { nil }
36
+
37
+ it 'creates a device' do
38
+ stub_post = stub_request(:post, "#{Setting[:netbox_url]}/api/dcim/devices/").with(
39
+ body: {
40
+ name: netbox_device_params[:name],
41
+ serial: netbox_device_params[:serial],
42
+ tags: netbox_device_params[:tags],
43
+ device_type: device_type.id,
44
+ device_role: device_role.id,
45
+ site: site.id,
46
+ tenant: tenant.id
47
+ }.to_json
48
+ ).to_return(
49
+ status: 201, headers: { 'Content-Type': 'application/json' },
50
+ body: { id: device_id }.to_json
51
+ )
52
+
53
+ assert_equal device_id, subject.device.id
54
+ assert_requested(stub_post)
55
+ end
56
+ end
57
+
58
+ context 'when device is already assigned to the context' do
59
+ let(:device) { OpenStruct.new(id: device_id) }
60
+
61
+ it 'does not create a device' do
62
+ assert_equal device_id, subject.device.id
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_plugin_helper'
4
+
5
+ class FindDeviceTest < ActiveSupport::TestCase
6
+ subject { ForemanNetbox::SyncHost::SyncDevice::Find.call(host: host, netbox_params: host.netbox_facet.netbox_params) }
7
+
8
+ let(:host) do
9
+ FactoryBot.build_stubbed(:host).tap do |host|
10
+ host.stubs(:mac).returns('C3:CD:63:54:21:62')
11
+ host.stubs(:facts).returns({ 'serialnumber' => 'abc123' })
12
+ end
13
+ end
14
+
15
+ setup do
16
+ setup_default_netbox_settings
17
+ end
18
+
19
+ context 'when device already exists in Netbox' do
20
+ test 'find device by host name' do
21
+ stub_get_by_serial = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
22
+ query: { limit: 50, serial: host.netbox_facet.netbox_params.dig(:device, :serial) }
23
+ ).to_return(
24
+ status: 200, headers: { 'Content-Type': 'application/json' },
25
+ body: { count: 0, results: [] }.to_json
26
+ )
27
+ stub_get_by_mac_addres = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
28
+ query: { limit: 50, mac_address: host.mac }
29
+ ).to_return(
30
+ status: 200, headers: { 'Content-Type': 'application/json' },
31
+ body: { count: 0, results: [] }.to_json
32
+ )
33
+ stub_get_by_name = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
34
+ query: { limit: 50, name: host.name }
35
+ ).to_return(
36
+ status: 200, headers: { 'Content-Type': 'application/json' },
37
+ body: { count: 1, results: [{ id: 1, name: host.name }] }.to_json
38
+ )
39
+
40
+ assert_equal 1, subject.device.id
41
+ assert_requested(stub_get_by_serial)
42
+ assert_requested(stub_get_by_mac_addres)
43
+ assert_requested(stub_get_by_name)
44
+ end
45
+
46
+ test 'find device by mac address' do
47
+ stub_get_by_serial = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
48
+ query: { limit: 50, serial: host.netbox_facet.netbox_params.dig(:device, :serial) }
49
+ ).to_return(
50
+ status: 200, headers: { 'Content-Type': 'application/json' },
51
+ body: { count: 0, results: [] }.to_json
52
+ )
53
+ stub_get_by_mac_addres = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
54
+ query: { limit: 50, mac_address: host.mac }
55
+ ).to_return(
56
+ status: 200, headers: { 'Content-Type': 'application/json' },
57
+ body: { count: 1, results: [{ id: 1, name: host.netbox_facet.netbox_params.dig(:device, :name) }] }.to_json
58
+ )
59
+
60
+ assert_equal 1, subject.device.id
61
+ assert_requested(stub_get_by_serial)
62
+ assert_requested(stub_get_by_mac_addres)
63
+ end
64
+
65
+ test 'find device by serial number' do
66
+ stub_get_by_serial = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
67
+ query: { limit: 50, serial: host.netbox_facet.netbox_params.dig(:device, :serial) }
68
+ ).to_return(
69
+ status: 200, headers: { 'Content-Type': 'application/json' },
70
+ body: { count: 1, results: [{ id: 1, name: host.name }] }.to_json
71
+ )
72
+
73
+ assert_equal 1, subject.device.id
74
+ assert_requested(stub_get_by_serial)
75
+ end
76
+ end
77
+
78
+ context 'when device does not exist in NetBox' do
79
+ it 'does not assign device to context' do
80
+ stub_get_by_serial = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
81
+ query: { limit: 50, serial: host.netbox_facet.netbox_params.dig(:device, :serial) }
82
+ ).to_return(
83
+ status: 200, headers: { 'Content-Type': 'application/json' },
84
+ body: { count: 0, results: [] }.to_json
85
+ )
86
+ stub_get_by_mac_addres = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
87
+ query: { limit: 50, mac_address: host.mac }
88
+ ).to_return(
89
+ status: 200, headers: { 'Content-Type': 'application/json' },
90
+ body: { count: 0, results: [] }.to_json
91
+ )
92
+ stub_get_by_name = stub_request(:get, "#{Setting[:netbox_url]}/api/dcim/devices.json").with(
93
+ query: { limit: 50, name: host.netbox_facet.netbox_params.dig(:device, :name) }
94
+ ).to_return(
95
+ status: 200, headers: { 'Content-Type': 'application/json' },
96
+ body: { count: 0, results: [] }.to_json
97
+ )
98
+
99
+ assert_nil subject.site
100
+ assert_requested(stub_get_by_serial)
101
+ assert_requested(stub_get_by_mac_addres)
102
+ assert_requested(stub_get_by_name)
103
+ end
104
+ end
105
+ end