foreman_netbox 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ module SyncHost
5
+ module SyncVirtualMachine
6
+ class Validate
7
+ include ::Interactor
8
+
9
+ def call
10
+ validator = ForemanNetbox::VirtualMachineContract.new.call(netbox_params)
11
+
12
+ return if validator.success?
13
+
14
+ message = validator.errors
15
+ .messages
16
+ .map { |m| "#{m.path} #{m.text}" }
17
+ .to_sentence
18
+ context.fail!(error: _('Invalid Virtual Machine parameters: %s') % message)
19
+ end
20
+
21
+ delegate :netbox_params, to: :context
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ class SyncHostJob < ::ApplicationJob
5
+ queue_as :netbox_queue
6
+
7
+ def perform(host_id)
8
+ Host::Managed.find(host_id)&.push_to_netbox
9
+ end
10
+
11
+ rescue_from(StandardError) do |error|
12
+ Foreman::Logging.logger('background').error("Netbox: Error #{error}: #{error.backtrace}")
13
+ end
14
+
15
+ def humanized_name
16
+ _('Push host to Netbox')
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ class API
5
+ def self.client
6
+ NetboxClientRuby.configure do |config|
7
+ config.netbox.api_base_url = "#{Setting::Netbox['netbox_url']}/api"
8
+ config.netbox.auth.token = Setting::Netbox['netbox_api_token']
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ module HostExtensions
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ include ::Orchestration::Netbox
9
+ end
10
+
11
+ def netbox_facet
12
+ @netbox_facet ||= super || ForemanNetbox::NetboxFacet.new(host: self)
13
+ end
14
+
15
+ def push_to_netbox_async
16
+ ForemanNetbox::SyncHostJob.perform_later(id)
17
+ end
18
+
19
+ def push_to_netbox
20
+ ForemanNetbox::SyncHost::Organizer.call(host: self)
21
+ end
22
+
23
+ def delete_from_netbox
24
+ ForemanNetbox::DeleteHost::Organizer.call(host: self)
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ module LocationExtensions
5
+ def netbox_site_name
6
+ parameters.fetch('netbox_site', name)
7
+ end
8
+
9
+ def netbox_site_slug
10
+ netbox_site_name&.parameterize
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ module Nic
5
+ module BaseExtensions
6
+ def netbox_name
7
+ identifier || (mac && "Interface #{mac}")
8
+ end
9
+
10
+ def netbox_ips
11
+ [netbox_ip, netbox_ip6].compact
12
+ end
13
+
14
+ def netbox_ip
15
+ ip && subnet && "#{ip}/#{subnet.cidr}"
16
+ end
17
+
18
+ def netbox_ip6
19
+ ip6 && subnet6 && "#{ip6}/#{subnet6.cidr}"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ module UserUsergroupCommonExtensions
5
+ NETBOX_TENANT_MAX_LENGTH = 30
6
+
7
+ def netbox_tenant_name
8
+ return name unless name.length > NETBOX_TENANT_MAX_LENGTH
9
+
10
+ name_length = NETBOX_TENANT_MAX_LENGTH - id.to_s.length - 1
11
+ "#{name.to_s.truncate(name_length, omission: '')}-#{id}"
12
+ end
13
+
14
+ def netbox_tenant_slug
15
+ netbox_tenant_name&.parameterize
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ class NetboxFacet < ApplicationRecord
5
+ include Facets::Base
6
+
7
+ COMMON_PARAMS = %i[interfaces ip_addresses tenant].freeze
8
+ DEVICE_PARAMS = %i[device device_role device_type manufacturer site].freeze
9
+ VIRTUAL_MACHINE_PARAMS = %i[virtual_machine cluster cluster_type].freeze
10
+
11
+ validates :host, presence: true, allow_blank: false
12
+ validates :url, uniqueness: true
13
+
14
+ def synchronization_success?
15
+ !synchronization_error
16
+ end
17
+
18
+ def netbox_params
19
+ ForemanNetbox::NetboxParameters.call(host)
20
+ end
21
+
22
+ def cached_netbox_params
23
+ ForemanNetbox::CachedNetboxParameters.call(host)
24
+ end
25
+
26
+ def netbox_params_diff
27
+ ForemanNetbox::NetboxParametersComparator.call(cached_netbox_params, netbox_params)
28
+ end
29
+
30
+ def netbox_will_change?
31
+ netbox_params_diff.keys.any?
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Orchestration
4
+ module Netbox
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ after_validation :queue_netbox_push, if: :netbox_orchestration_allowed?
9
+ before_destroy :queue_netbox_destroy
10
+ end
11
+
12
+ delegate :netbox_will_change?, :netbox_params_diff, to: :netbox_facet
13
+
14
+ protected
15
+
16
+ def netbox_orchestration_allowed?
17
+ Setting::Netbox[:netbox_orchestration_enabled] && netbox_will_change?
18
+ end
19
+
20
+ def queue_netbox_push
21
+ return unless errors.empty? && managed?
22
+
23
+ ::Foreman::Logging.logger('foreman_netbox/import')
24
+ .info("Queued import of #{name} to Netbox. Changes that will be sent: #{netbox_params_diff}")
25
+
26
+ post_queue.create(name: _('Push host %s to Netbox') % self, priority: 100,
27
+ action: [self, :set_netbox])
28
+ end
29
+
30
+ def queue_netbox_destroy
31
+ return unless errors.empty? && managed?
32
+
33
+ queue.create(name: _('Delete host %s from Netbox') % self, priority: 60,
34
+ action: [self, :del_netbox])
35
+ end
36
+
37
+ def set_netbox
38
+ ::Foreman::Logging.logger('foreman_netbox/import')
39
+ .info("Pushing #{name} to Netbox")
40
+
41
+ push_to_netbox_async
42
+ rescue StandardError => e
43
+ ::Foreman::Logging.logger('foreman_netbox/import')
44
+ .error("Failed to push #{name} to Netbox. Error #{e}: #{e.backtrace}")
45
+
46
+ failure format(_('Failed to push %{name} to Netbox: %{message}\n '), name: name, message: e.message), e
47
+ end
48
+
49
+ def del_netbox
50
+ ::Foreman::Logging.logger('foreman_netbox/import')
51
+ .info("Deleting #{name} from Netbox")
52
+
53
+ result = delete_from_netbox
54
+ return true if result.success?
55
+
56
+ raise Foreman::Exception, result.error
57
+ rescue StandardError => e
58
+ ::Foreman::Logging.logger('foreman_netbox/import')
59
+ .error("Failed to delete #{name} from Netbox. Error #{e}: #{e.backtrace}")
60
+
61
+ failure format(_('Failed to delete %{name} from Netbox: %{message}\n '), name: name, message: e.message), e
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Setting
4
+ class Netbox < ::Setting
5
+ BLANK_ATTRS << 'netbox_url'
6
+ BLANK_ATTRS << 'netbox_api_token'
7
+ URI_BLANK_ATTRS << 'netbox_url'
8
+
9
+ def self.default_settings
10
+ [
11
+ set('netbox_url', N_('URL where Netbox is reachable'), nil, N_('Netbox URL')),
12
+ set('netbox_api_token', N_('API token to Netbox'), nil, N_('Netbox API token'), nil, encrypted: true),
13
+ set('netbox_orchestration_enabled', N_('Enable Netbox Orchestration'), false, N_('Netbox Orchestration'))
14
+ ]
15
+ end
16
+
17
+ def self.load_defaults
18
+ # Check the table exists
19
+ return unless super
20
+
21
+ transaction do
22
+ default_settings.each { |s| create! s.update(category: 'Setting::Netbox') }
23
+ end
24
+
25
+ true
26
+ end
27
+
28
+ def self.humanized_category
29
+ N_('Netbox')
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ class CachedNetboxParameters
5
+ def self.call(host)
6
+ new(host).call
7
+ end
8
+
9
+ def initialize(host)
10
+ @is_compute = host.compute?
11
+ @data = host.netbox_facet.raw_data&.deep_symbolize_keys || {}
12
+ @result = {}
13
+ end
14
+
15
+ def call
16
+ additional_params = is_compute ? ForemanNetbox::NetboxFacet::VIRTUAL_MACHINE_PARAMS : ForemanNetbox::NetboxFacet::DEVICE_PARAMS
17
+ (ForemanNetbox::NetboxFacet::COMMON_PARAMS + additional_params).map { |key| send("read_#{key}") }
18
+
19
+ result
20
+ end
21
+
22
+ private
23
+
24
+ attr_reader :data, :is_compute
25
+ attr_accessor :result
26
+
27
+ def read_interfaces
28
+ return unless data.keys.include?(:interfaces)
29
+
30
+ result[:interfaces] = data.fetch(:interfaces, {}).fetch(:results, []).map do |interface|
31
+ interface.slice(:name, :mac_address, :tags)
32
+ .merge(type: interface.fetch(:type, {}).slice(:value))
33
+ .compact
34
+ end
35
+ end
36
+
37
+ def read_ip_addresses
38
+ return unless data.keys.include?(:ip_addresses)
39
+
40
+ result[:ip_addresses] = data.fetch(:ip_addresses, {}).fetch(:results, []).map do |ip_address|
41
+ ip_address.slice(:address, :tags)
42
+ .merge(interface: ip_address.fetch(:interface, {}).slice(:name))
43
+ end
44
+ end
45
+
46
+ def read_virtual_machine
47
+ return unless data.keys.include?(:virtual_machine)
48
+
49
+ result[:virtual_machine] = data.fetch(:virtual_machine, {}).slice(:name, :vcpus, :memory, :disk, :tags)
50
+ end
51
+
52
+ def read_tenant
53
+ return unless data.keys.include?(:tenant)
54
+
55
+ result[:tenant] = data.fetch(:tenant, {}).slice(:name, :slug, :tags)
56
+ end
57
+
58
+ def read_cluster
59
+ return unless data.keys.include?(:cluster)
60
+
61
+ result[:cluster] = data.fetch(:cluster, {}).slice(:name, :tags)
62
+ end
63
+
64
+ def read_cluster_type
65
+ return unless data.keys.include?(:cluster_type)
66
+
67
+ result[:cluster_type] = data.fetch(:cluster_type, {}).slice(:name, :slug)
68
+ end
69
+
70
+ def read_device
71
+ return unless data.keys.include?(:device)
72
+
73
+ result[:device] = data.fetch(:device, {})
74
+ .slice(:name, :serial, :tags)
75
+ .compact
76
+ .reject { |k, v| k == :serial && v.blank? }
77
+ end
78
+
79
+ def read_device_role
80
+ return unless data.keys.include?(:device_role)
81
+
82
+ result[:device_role] = data.fetch(:device_role, {}).slice(:name, :color, :slug)
83
+ end
84
+
85
+ def read_device_type
86
+ return unless data.keys.include?(:device_type)
87
+
88
+ result[:device_type] = data.fetch(:device_type, {}).slice(:model, :slug, :tags)
89
+ end
90
+
91
+ def read_manufacturer
92
+ return unless data.keys.include?(:manufacturer)
93
+
94
+ result[:manufacturer] = data.fetch(:manufacturer, {}).slice(:name, :slug)
95
+ end
96
+
97
+ def read_site
98
+ return unless data.keys.include?(:site)
99
+
100
+ result[:site] = data.fetch(:site, {}).slice(:name, :slug, :tags)
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ForemanNetbox
4
+ # rubocop:disable Metrics/ClassLength
5
+ class NetboxParameters
6
+ UNKNOWN = 'Unknown'
7
+ DEFAULT_TAGS = ['foreman'].freeze
8
+ DEFAULT_INTERFACE_TYPE = 'virtual'
9
+ CLUSTER_TYPES = {
10
+ :'Foreman::Model::Vmware' => {
11
+ name: 'VMware ESXi',
12
+ slug: 'vmware-esxi'
13
+ }
14
+ }.freeze
15
+ DEVICE_ROLE = {
16
+ name: 'SERVER',
17
+ color: '9e9e9e',
18
+ slug: 'server'
19
+ }.freeze
20
+
21
+ def self.call(host)
22
+ new(host).call
23
+ end
24
+
25
+ def initialize(host)
26
+ @host = host
27
+ end
28
+
29
+ def call
30
+ additional_params = host.compute? ? ForemanNetbox::NetboxFacet::VIRTUAL_MACHINE_PARAMS : ForemanNetbox::NetboxFacet::DEVICE_PARAMS
31
+
32
+ (ForemanNetbox::NetboxFacet::COMMON_PARAMS + additional_params).map do |param|
33
+ send(param)
34
+ end.reduce({}, :merge)
35
+ end
36
+
37
+ private
38
+
39
+ attr_accessor :host
40
+
41
+ delegate :netbox_facet, to: :host
42
+ delegate :cached_netbox_params, to: :netbox_facet
43
+
44
+ def netbox_compute_attributes
45
+ @netbox_compute_attributes ||= host.compute_object.yield_self do |compute_object|
46
+ {
47
+ vcpus: compute_object&.cpus,
48
+ memory: compute_object&.memory_mb,
49
+ disk: compute_object&.volumes&.map(&:size_gb)&.reduce(&:+),
50
+ cluster: compute_object&.cluster
51
+ }.compact
52
+ end
53
+ end
54
+
55
+ def tenant
56
+ {
57
+ tenant: {
58
+ name: host.owner&.netbox_tenant_name,
59
+ slug: host.owner&.netbox_tenant_slug,
60
+ tags: DEFAULT_TAGS
61
+ }
62
+ }
63
+ end
64
+
65
+ def device
66
+ {
67
+ device: {
68
+ name: host.name,
69
+ serial: host.facts.deep_symbolize_keys[:serialnumber],
70
+ tags: DEFAULT_TAGS
71
+ }
72
+ }
73
+ end
74
+
75
+ def device_role
76
+ {
77
+ device_role: DEVICE_ROLE
78
+ }
79
+ end
80
+
81
+ def device_type
82
+ model = host.facts.deep_symbolize_keys[:productname] || host.facts.deep_symbolize_keys[:'dmi::product::name'] || UNKNOWN
83
+
84
+ {
85
+ device_type: {
86
+ model: model,
87
+ slug: model.parameterize,
88
+ tags: DEFAULT_TAGS
89
+ }
90
+ }
91
+ end
92
+
93
+ def manufacturer
94
+ name = host.facts.deep_symbolize_keys[:manufacturer] || host.facts.deep_symbolize_keys[:'dmi::manufacturer'] || UNKNOWN
95
+
96
+ {
97
+ manufacturer: {
98
+ name: name,
99
+ slug: cached_netbox_params.dig(:manufacturer, :slug) || name.parameterize
100
+ }
101
+ }
102
+ end
103
+
104
+ def site
105
+ {
106
+ site: {
107
+ name: host.location&.netbox_site_name,
108
+ slug: host.location&.netbox_site_slug,
109
+ tags: DEFAULT_TAGS
110
+ }
111
+ }
112
+ end
113
+
114
+ def interfaces
115
+ {
116
+ interfaces: host.interfaces.map do |interface|
117
+ identifier = interface.identifier.present? && interface.identifier
118
+ mac_address = interface.mac&.upcase
119
+
120
+ {
121
+ name: identifier || (mac_address && "Interface #{mac_address}"),
122
+ mac_address: mac_address,
123
+ type: {
124
+ value: DEFAULT_INTERFACE_TYPE
125
+ },
126
+ tags: DEFAULT_TAGS
127
+ }
128
+ end
129
+ }
130
+ end
131
+
132
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
133
+ def ip_addresses
134
+ {
135
+ ip_addresses: host.interfaces.map do |interface|
136
+ [
137
+ interface.ip && interface.subnet && "#{interface.ip}/#{interface.subnet.cidr}",
138
+ interface.ip6 && interface.subnet6 && "#{interface.ip6}/#{interface.subnet6.cidr}"
139
+ ].compact.map do |ip_address|
140
+ identifier = interface.identifier.present? && interface.identifier
141
+ mac_address = interface.mac&.upcase
142
+
143
+ {
144
+ address: ip_address,
145
+ interface: {
146
+ name: identifier || (mac_address && "Interface #{mac_address}")
147
+ },
148
+ tags: DEFAULT_TAGS
149
+ }
150
+ end
151
+ end.flatten
152
+ }
153
+ end
154
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
155
+
156
+ def virtual_machine
157
+ {
158
+ virtual_machine: netbox_compute_attributes.slice(
159
+ :vcpus, :memory, :disk
160
+ ).merge(
161
+ name: host.name,
162
+ tags: DEFAULT_TAGS
163
+ )
164
+ }
165
+ end
166
+
167
+ def cluster
168
+ {
169
+ cluster: {
170
+ name: netbox_compute_attributes[:cluster],
171
+ tags: DEFAULT_TAGS
172
+ }.compact
173
+ }
174
+ end
175
+
176
+ def cluster_type
177
+ type = host.compute_resource&.type&.to_sym
178
+
179
+ {
180
+ cluster_type: CLUSTER_TYPES.fetch(type, nil)
181
+ }
182
+ end
183
+ end
184
+ # rubocop:enable Metrics/ClassLength
185
+ end