smart_proxy_dhcp_kea_api 1.0.0 → 1.0.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 142ceab2eeffbc270cb77ef8193a1eabdfe44f824fb60d11f71a942b726f054b
4
- data.tar.gz: 85edbf8f08b9a9c81f1ce07ec97c2b9dff7038149ee8d2f79787c9be3fe38cdf
3
+ metadata.gz: 60b69b716ae58881effcacb442e0357e0d92a2b30b4c5be29e24439e07c9e047
4
+ data.tar.gz: c698f7bdb99f3965eb1f7eb02afe908559b29c2145e3c8870b87038c3552c101
5
5
  SHA512:
6
- metadata.gz: 410a191c0459dc5a854bc61ddf08fcba06519d458e337fd2b5eae3bc2afa68bf09fc8c1ffb1888725dbed5b5f5d688f8bdc7d421651ac05d377af264aa5f8391
7
- data.tar.gz: ef8f1adacf0b3c33405f493325d6138d69f617c3d6287bb8c6ce2acbfb31581bc9a0e2b5160c321b5b95fc69d000f365794a9fdce62cc2351350386bdebf1500
6
+ metadata.gz: bd83ca3c705b98af40b57b11b9d9d10386f43277a07884d537eda07f28ef433e3939aeb5d7ab90d351e0f1f429560ea642a9a8ce0b4a98eb60867cb037c6b1e5
7
+ data.tar.gz: e965386db272058aa1504d089cc69e3e39ada4610a2fe96ff4e2f1a2c5ee7632577430f781e0bffc16239f7243d94f5acb536ef0e6ebcefd0558541b080a018d
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  # Foreman Smart Proxy DHCP Kea API
2
-
2
+ [![Gem Version](https://badge.fury.io/rb/smart_proxy_dhcp_kea_api.svg)](https://badge.fury.io/rb/smart_proxy_dhcp_kea_api)
3
3
  [![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
4
4
 
5
5
  A Foreman Smart Proxy plugin to provide DHCP management by interacting with the ISC Kea API. This provider allows Foreman to view subnets and leases and to create and delete host reservations directly via Kea's JSON-RPC interface.
@@ -29,8 +29,36 @@ module Proxy
29
29
  # `add_record` to perform initial validation and IP selection, then building
30
30
  # the Kea-specific payload and sending it via the API client.
31
31
  #
32
- # @param options [Hash] A hash of options for the new record, typically including :mac, :ip, and :name.
32
+ # @param options [Hash] A hash containing the details for the new reservation.
33
+ # @option options [String] 'mac' The hardware address of the host.
34
+ # @option options [String] 'ip' The IP address to reserve.
35
+ # @option options [String] 'hostname' The hostname for the reservation.
36
+ # @option options [Proxy::DHCP::Subnet] :subnet The subnet object this reservation belongs to.
37
+ # @option options [String, nil] 'nextServer' (optional) The IP of the TFTP boot server.
38
+ # @option options [String, nil] 'filename' (optional) The boot filename (e.g., 'pxelinux.0').
33
39
  # @return [Proxy::DHCP::Reservation] The created reservation object.
40
+ #
41
+ # @example Add a new DHCP reservation for a host
42
+ # # Assume @provider is an instance of Proxy::DHCP::KeaApi::Provider
43
+ # # and 'subnet' is a valid Proxy::DHCP::Subnet object for '192.168.1.0/24'
44
+ # options = {
45
+ # 'mac' => 'aa:bb:cc:dd:ee:ff',
46
+ # 'hostname' => 'test-host.example.com',
47
+ # 'ip' => '192.168.1.15',
48
+ # subnet: subnet,
49
+ # 'nextServer' => 'tftp.example.com',
50
+ # 'filename' => 'pxelinux.0',
51
+ # 'routers' => ['192.168.1.1'],
52
+ # 'ntp_servers' => ['192.168.1.254']
53
+ # }
54
+ #
55
+ # reservation = @provider.add_record(options)
56
+ #
57
+ # reservation.mac #=> "aa:bb:cc:dd:ee:ff"
58
+ # reservation.ip #=> "192.168.1.15"
59
+ # reservation.name #=> "test-host.example.com"
60
+ # reservation.subnet #=> #<Proxy::DHCP::Subnet ...>
61
+ #
34
62
  def add_record(options = {})
35
63
  logger.debug "DHCP options received from Foreman: #{options.inspect}"
36
64
  record = super
@@ -51,10 +79,29 @@ module Proxy
51
79
  # Deletes a DHCP reservation from Kea.
52
80
  #
53
81
  # @param record [Proxy::DHCP::Reservation] The reservation object to be deleted.
54
- # @return [Proxy::DHCP::Reservation] The deleted reservation object.
82
+ # This object should be retrieved from the subnet service first.
83
+ # @return [Proxy::DHCP::Reservation] The object that was successfully deleted.
84
+ # @raise [Proxy::DHCP::Error] if the corresponding Kea subnet-id cannot be found or the API call fails.
85
+ #
86
+ # @example Delete a known DHCP reservation
87
+ # # Assume @provider is an instance of Proxy::DHCP::KeaApi::Provider
88
+ # mac_to_delete = 'aa:bb:cc:dd:ee:ff'
89
+ #
90
+ # # First, find the reservation object
91
+ # record_to_delete = @provider.get_record('mac' => mac_to_delete)
92
+ #
93
+ # # Now, pass the entire object to del_record
94
+ # if record_to_delete
95
+ # result = @provider.del_record(record_to_delete)
96
+ # #=> #<Proxy::DHCP::Reservation ...>
97
+ # end
98
+ #
55
99
  def del_record(record)
56
100
  logger.debug "Deleting record; #{record.inspect}"
57
- return record if record.is_a? ::Proxy::DHCP::Lease
101
+ unless record.is_a?(::Proxy::DHCP::Reservation)
102
+ logger.warn "Attempted to delete a record for MAC '#{record.mac}' but it is not a Reservation (actual type: #{record.class.name}). No action taken."
103
+ return record
104
+ end
58
105
 
59
106
  subnet_id = @subnet_service.kea_id_map[record.subnet.network]
60
107
  raise Proxy::DHCP::Error, "Unable to find Kea subnet-id for network #{record.subnet.network}" unless subnet_id
@@ -10,6 +10,8 @@ module Proxy
10
10
  # as the entry point for the Foreman Smart Proxy to load and configure the
11
11
  # plugin. It defines the plugin's name, version, dependencies on other
12
12
  # modules, default settings, and hooks into the dependency injection framework.
13
+ #
14
+ # @see Proxy::DHCP::KeaApi::PluginConfiguration For how dependencies are loaded and wired.
13
15
  class Plugin < ::Proxy::Provider
14
16
  # Registers the provider with the Smart Proxy, giving it a unique name
15
17
  # (`:dhcp_kea_api`) and sourcing the version from the VERSION constant.
@@ -60,6 +60,7 @@ module Proxy
60
60
 
61
61
  # Fetches all subnets and their associated reservations from the Kea API.
62
62
  # This single `config-get` call is the most efficient way to get all static configuration.
63
+ # @see Proxy::DHCP::KeaApi::Client#post_command
63
64
  def load_subnets_and_reservations_from_kea
64
65
  config = @client.post_command('dhcp4', 'config-get')
65
66
  subnets_data = config&.dig('Dhcp4', 'subnet4')
@@ -79,6 +80,7 @@ module Proxy
79
80
  end
80
81
 
81
82
  # Fetches all active leases from the Kea API for the subnets currently in the cache.
83
+ # @see Proxy::DHCP::KeaApi::Client#post_command
82
84
  def load_leases_from_kea
83
85
  # This guard is necessary because the `lease4-get-all` command requires
84
86
  # a list of subnet IDs to query. If no subnets were loaded, we can't get leases.
@@ -3,7 +3,7 @@
3
3
  module Proxy
4
4
  module DHCP
5
5
  module KeaApi
6
- VERSION = '1.0.0'
6
+ VERSION = '1.0.1'
7
7
  end
8
8
  end
9
9
  end
@@ -19,6 +19,16 @@ module Proxy
19
19
  # @param open_timeout [Integer] Time in seconds to wait for the initial TCP connection to be established (defaults to 5).
20
20
  # @param read_timeout [Integer] Time in seconds to wait for a response from the server after the connection is made (defaults to 10).
21
21
  # @raise [ArgumentError] if the URL is blank, malformed, or not a valid HTTP/S URL.
22
+ #
23
+ # @example Basic Initialization
24
+ # client = Proxy::DHCP::KeaApi::Client.new(url: 'https://kea.example.com:8443')
25
+ #
26
+ # @example Initialization with Custom Timeouts
27
+ # client = Proxy::DHCP::KeaApi::Client.new(
28
+ # url: 'http://127.0.0.1:8000',
29
+ # open_timeout: 2,
30
+ # read_timeout: 5
31
+ # )
22
32
  def initialize(url:, open_timeout: 5, read_timeout: 10)
23
33
  raise ArgumentError, 'Kea API URL cannot be nil or empty' if url.to_s.empty?
24
34
 
@@ -42,6 +52,23 @@ module Proxy
42
52
  #
43
53
  # @return [Hash] The 'arguments' hash from the Kea API response on success.
44
54
  # @raise [Proxy::DHCP::Error] if the API returns an error or if there's a communication issue.
55
+ #
56
+ # @example Get the current DHCPv4 configuration
57
+ # client = Proxy::DHCP::KeaApi::Client.new(url: 'http://localhost:8000')
58
+ # config_response = client.post_command('dhcp4', 'config-get')
59
+ # # => {"Dhcp4"=>{"subnet4"=>[{"id"=>1, "subnet"=>"192.168.1.0/24", ...}]}}
60
+ #
61
+ # @example Add a DHCPv4 reservation
62
+ # client = Proxy::DHCP::KeaApi::Client.new(url: 'http://localhost:8000')
63
+ # add_response = client.post_command('dhcp4', 'reservation-add', {
64
+ # reservation: {
65
+ # 'subnet-id': 1,
66
+ # 'ip-address': '192.168.1.100',
67
+ # 'hw-address': '00:11:22:33:44:55',
68
+ # hostname: 'my-new-host'
69
+ # }
70
+ # })
71
+ # # => {"text"=>"Reservation added successfully."}
45
72
  def post_command(service, command, arguments = {})
46
73
  header = { 'Content-Type' => 'application/json' }
47
74
  payload = {
@@ -82,6 +109,7 @@ module Proxy
82
109
  #
83
110
  # @return [Hash] The 'arguments' hash from the response on success.
84
111
  # @raise [Proxy::DHCP::Error] if the response indicates a failure or is malformed.
112
+ # @private
85
113
  def handle_response(response, command)
86
114
  body = JSON.parse(response.body)
87
115
  logger.debug "Received response from Kea: #{body.inspect}"
@@ -105,6 +133,7 @@ module Proxy
105
133
  # @param command [String] The original command sent, needed for special case handling.
106
134
  #
107
135
  # @return [Boolean] `true` if the response is considered a success, `false` otherwise.
136
+ # @private
108
137
  def response_successful?(result, command)
109
138
  # Universal success is result code 0.
110
139
  return true if result['result'].zero?
@@ -38,6 +38,7 @@ module Proxy
38
38
 
39
39
  # The custom client for communicating with the Kea API. This is registered as a singleton
40
40
  # so that a single, persistent HTTP connection pool is used for all API calls.
41
+ # @see Proxy::DHCP::KeaApi::Client#initialize
41
42
  container.singleton_dependency :kea_client, (lambda do
42
43
  ::Proxy::DHCP::KeaApi::Client.new(
43
44
  url: settings[:kea_api_url],
@@ -50,6 +51,7 @@ module Proxy
50
51
  # This is a singleton because we want one central, authoritative cache that all
51
52
  # requests can share. It depends on the Kea client to fetch data and the memory
52
53
  # stores to cache it.
54
+ # @see Proxy::DHCP::KeaApi::SubnetService#initialize
53
55
  container.singleton_dependency :subnet_service, (lambda do
54
56
  memory_store = container.get_dependency(:memory_store)
55
57
  ::Proxy::DHCP::KeaApi::SubnetService.new(
@@ -65,6 +67,7 @@ module Proxy
65
67
  # The main provider class that ties everything together. This is the entry point
66
68
  # for handling DHCP requests from Foreman. It depends on the subnet service,
67
69
  # the API client, and the IP blacklist service to do its job.
70
+ # @see Proxy::DHCP::KeaApi::Provider#initialize
68
71
  container.dependency :dhcp_provider, (lambda do
69
72
  ::Proxy::DHCP::KeaApi::Provider.new(
70
73
  container.get_dependency(:subnet_service),
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_proxy_dhcp_kea_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam McCarthy