Class: Proxy::DHCP::KeaApi::Client

Inherits:
Object
  • Object
show all
Includes:
Log
Defined in:
lib/smart_proxy_dhcp_kea_api/kea_api_client.rb

Overview

A client for interacting with the ISC Kea DHCP server API. This class encapsulates the logic for creating JSON-RPC commands, sending them via HTTP, and handling the responses from the Kea server.

Instance Method Summary collapse

Constructor Details

#initialize(url:, username: nil, password: nil, open_timeout: 5, read_timeout: 10) ⇒ Client

Initialises a new Kea API client.

Examples:

Basic Initialization

client = Proxy::DHCP::KeaApi::Client.new(url: 'https://kea.example.com:8443')

Initialization with Custom Timeouts

client = Proxy::DHCP::KeaApi::Client.new(
  url: 'http://127.0.0.1:8000',
  username: 'myuser',
  password: 'mypassword'
  open_timeout: 2,
  read_timeout: 5
)

Parameters:

  • url (String)

    The base URL of the Kea API endpoint (e.g. 'http://127.0.0.1:8000/').

  • username (String, nil) (defaults to: nil)

    The username for HTTP Basic Authentication.

  • password (String, nil) (defaults to: nil)

    The password for HTTP Basic Authentication.

  • open_timeout (Integer) (defaults to: 5)

    Time in seconds to wait for the initial TCP connection to be established (defaults to 5).

  • read_timeout (Integer) (defaults to: 10)

    Time in seconds to wait for a response from the server after the connection is made (defaults to 10).

Raises:

  • (ArgumentError)

    if the URL is blank, malformed, or not a valid HTTP/S URL.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/smart_proxy_dhcp_kea_api/kea_api_client.rb', line 36

def initialize(url:, username: nil, password: nil, open_timeout: 5, read_timeout: 10)
  raise ArgumentError, 'Kea API URL cannot be nil or empty' if url.to_s.empty?

  @uri = URI.parse(url)

  raise ArgumentError, "Invalid Kea API URL: '#{url}' must be an HTTP or HTTPS URL" unless @uri.is_a?(URI::HTTP) || @uri.is_a?(URI::HTTPS)

  raise ArgumentError, "Invalid Kea API URL: '#{url}' is missing a host" unless @uri.host

  @username = username
  @password = password
  @open_timeout = open_timeout
  @read_timeout = read_timeout
  logger.info "Initializing Kea API client for URL: #{@uri} with timeouts (open: #{@open_timeout}s, read: #{@read_timeout}s)"
end

Instance Method Details

#post_command(service, command, arguments = {}) ⇒ Hash

Constructs and sends a command to the Kea API and handles its response. This is the main public method for interacting with the Kea server.

Examples:

Get the current DHCPv4 configuration

client = Proxy::DHCP::KeaApi::Client.new(url: 'http://localhost:8000')
config_response = client.post_command('dhcp4', 'config-get')
# => {"Dhcp4"=>{"subnet4"=>[{"id"=>1, "subnet"=>"192.168.1.0/24", ...}]}}

Add a DHCPv4 reservation

client = Proxy::DHCP::KeaApi::Client.new(url: 'http://localhost:8000')
add_response = client.post_command('dhcp4', 'reservation-add', {
  reservation: {
    'subnet-id': 1,
    'ip-address': '192.168.1.100',
    'hw-address': '00:11:22:33:44:55',
    hostname: 'my-new-host'
  }
})
# => {"text"=>"Reservation added successfully."}

Parameters:

  • service (String)

    The Kea service to target (e.g. 'dhcp4').

  • command (String)

    The command to execute (e.g. 'config-get', 'reservation-add').

  • arguments (Hash) (defaults to: {})

    A hash of arguments required by the command. Defaults to an empty hash.

Returns:

  • (Hash)

    The 'arguments' hash from the Kea API response on success.

Raises:

  • (Proxy::DHCP::Error)

    if the API returns an error or if there's a communication issue. This can be caused by underlying errors like Net::ReadTimeout, Net::OpenTimeout, Errno::ECONNREFUSED, or JSON::ParserError.

See Also:



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/smart_proxy_dhcp_kea_api/kea_api_client.rb', line 82

def post_command(service, command, arguments = {})
  header = { 'Content-Type' => 'application/json' }
  payload = {
    command: command,
    service: [service],
    arguments: arguments
  }

  # This guard clause satisfies strict linters by ensuring the host is not nil in the local scope.
  host = @uri.host
  raise 'Internal error: Kea API client URI is missing a host' unless host

  http = Net::HTTP.new(host, @uri.port)
  http.use_ssl = @uri.scheme == 'https'
  http.open_timeout = @open_timeout
  http.read_timeout = @read_timeout
  request = Net::HTTP::Post.new(@uri.request_uri, header)
  request.body = payload.to_json
  request.basic_auth(@username, @password) if @username

  logger.debug "Sending command to Kea: #{payload.inspect}"
  response = http.request(request)

  handle_response(response, command)
  # This rescue block catches specific, expected network and parsing errors,
  # wrapping them in a Foreman-specific error type for consistent handling.
rescue Net::ReadTimeout, Net::OpenTimeout, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, JSON::ParserError => e
  logger.error "Failed to send command to Kea API: #{e.class.name} - #{e.message}"
  raise Proxy::DHCP::Error, "Kea API communication error: #{e.message}"
end