smart_proxy_dhcp_kea_api 1.0.1 → 1.1.0
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 +4 -4
- data/lib/.DS_Store +0 -0
- data/lib/smart_proxy_dhcp_kea_api/dhcp_kea_api_plugin.rb +4 -0
- data/lib/smart_proxy_dhcp_kea_api/dhcp_kea_api_subnet_service.rb +13 -1
- data/lib/smart_proxy_dhcp_kea_api/dhcp_kea_api_version.rb +2 -1
- data/lib/smart_proxy_dhcp_kea_api/kea_api_client.rb +24 -14
- data/lib/smart_proxy_dhcp_kea_api/plugin_configuration.rb +2 -0
- data/lib/smart_proxy_dhcp_kea_api.rb +6 -0
- data/smart_proxy_dhcp_kea_api.gemspec +15 -1
- metadata +146 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 42b1eec7524d54aa43e9f202c85cb88a92fbfcdf3dbf91a42df43e20d000ac1c
|
4
|
+
data.tar.gz: 66ae862538c0fc90345eb7a32e487ef63ef536c37cac572a07adfff9d39bb978
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5cf2dfcf2d1b5b52efa98f274b9abd4d777b5b62182f048401040a01baf3f7c32e70cf38921d7e596090a993b684ac19748257e8e2d67d9f35479ef0cc6f823c
|
7
|
+
data.tar.gz: 1c54018b7438505c0d8de97337a0363435498c29682e93d7699ffacb2933e7f4af57037c52bbe180b6273066b2c48e6712b06bf3484a83902715e585931d656b
|
data/lib/.DS_Store
ADDED
Binary file
|
@@ -23,8 +23,12 @@ module Proxy
|
|
23
23
|
|
24
24
|
# Defines the default settings for this provider. These values are used if
|
25
25
|
# they are not explicitly overridden in a user's settings file
|
26
|
+
# The `kea_api_username` and `kea_api_password` can be used to enable
|
27
|
+
# HTTP Basic Authentication if required by the Kea control agent.
|
26
28
|
# (e.g. `/etc/foreman-proxy/settings.d/dhcp_kea_api.yml`).
|
27
29
|
default_settings kea_api_url: 'http://127.0.0.1:8000/',
|
30
|
+
kea_api_username: nil,
|
31
|
+
kea_api_password: nil,
|
28
32
|
blacklist_duration_minutes: 5,
|
29
33
|
open_timeout: 5,
|
30
34
|
read_timeout: 10
|
@@ -31,7 +31,7 @@ module Proxy
|
|
31
31
|
# @param reservations_by_ip [Proxy::MemoryStore] A memory store for reservations, passed to the parent class.
|
32
32
|
# @param reservations_by_mac [Proxy::MemoryStore] A memory store for reservations, passed to the parent class.
|
33
33
|
# @param reservations_by_name [Proxy::MemoryStore] A memory store for reservations, passed to the parent class.
|
34
|
-
|
34
|
+
# @return [void]
|
35
35
|
# rubocop:disable Metrics/ParameterLists
|
36
36
|
def initialize(client, leases_by_ip, leases_by_mac, reservations_by_ip, reservations_by_mac, reservations_by_name)
|
37
37
|
@client = client
|
@@ -47,6 +47,8 @@ module Proxy
|
|
47
47
|
#
|
48
48
|
# @return [true] on success.
|
49
49
|
# @raise [Proxy::DHCP::Error] if any part of the loading process fails.
|
50
|
+
# @see #load_subnets_and_reservations_from_kea
|
51
|
+
# @see #load_leases_from_kea
|
50
52
|
# rubocop:disable Naming/PredicateMethod
|
51
53
|
def load!
|
52
54
|
subnets.clear
|
@@ -60,6 +62,9 @@ module Proxy
|
|
60
62
|
|
61
63
|
# Fetches all subnets and their associated reservations from the Kea API.
|
62
64
|
# This single `config-get` call is the most efficient way to get all static configuration.
|
65
|
+
# @return [void]
|
66
|
+
# @raise [Proxy::DHCP::Error] if the API call fails.
|
67
|
+
# @raise [IPAddr::InvalidAddressError] if a subnet address from Kea is invalid.
|
63
68
|
# @see Proxy::DHCP::KeaApi::Client#post_command
|
64
69
|
def load_subnets_and_reservations_from_kea
|
65
70
|
config = @client.post_command('dhcp4', 'config-get')
|
@@ -80,6 +85,8 @@ module Proxy
|
|
80
85
|
end
|
81
86
|
|
82
87
|
# Fetches all active leases from the Kea API for the subnets currently in the cache.
|
88
|
+
# @return [void]
|
89
|
+
# @raise [Proxy::DHCP::Error] if the API call fails.
|
83
90
|
# @see Proxy::DHCP::KeaApi::Client#post_command
|
84
91
|
def load_leases_from_kea
|
85
92
|
# This guard is necessary because the `lease4-get-all` command requires
|
@@ -114,6 +121,8 @@ module Proxy
|
|
114
121
|
# Foreman Subnet and Reservation objects, and adds them to the cache.
|
115
122
|
#
|
116
123
|
# @param subnet_data [Hash] The hash representing a single subnet from Kea's `config-get` response.
|
124
|
+
# @return [void]
|
125
|
+
# @raise [IPAddr::InvalidAddressError] if the subnet string is not a valid IP address.
|
117
126
|
def process_subnet(subnet_data)
|
118
127
|
ip_object = IPAddr.new(subnet_data['subnet'])
|
119
128
|
subnet_addr = ip_object.to_s
|
@@ -142,6 +151,7 @@ module Proxy
|
|
142
151
|
#
|
143
152
|
# @param subnet_data [Hash] The hash representing a single subnet.
|
144
153
|
# @return [Array<String>, nil] An array of router IP addresses, or nil if none are found.
|
154
|
+
# @note The router data in Kea is a single comma-separated string which must be split into an array.
|
145
155
|
def extract_routers(subnet_data)
|
146
156
|
# The router data is a comma-separated string which must be split into an array.
|
147
157
|
subnet_data['option-data']&.find { |opt| opt['name'] == 'routers' }&.[]('data')&.split(',')
|
@@ -151,6 +161,7 @@ module Proxy
|
|
151
161
|
#
|
152
162
|
# @param subnet_data [Hash] The hash representing a single subnet.
|
153
163
|
# @return [Array<String>, nil] A two-element array containing the start and end of the range, or nil.
|
164
|
+
# @note The pool range is a hyphen-separated string (e.g. "10.0.0.10-10.0.0.20").
|
154
165
|
def extract_range(subnet_data)
|
155
166
|
# The pool range is a hyphen-separated string (e.g. "10.0.0.10-10.0.0.20").
|
156
167
|
pool_string = subnet_data.dig('pools', 0, 'pool')
|
@@ -161,6 +172,7 @@ module Proxy
|
|
161
172
|
#
|
162
173
|
# @param res_data [Hash] The hash representing a single reservation.
|
163
174
|
# @param subnet [Proxy::DHCP::Subnet] The subnet object this reservation belongs to.
|
175
|
+
# @return [void]
|
164
176
|
def process_reservation(res_data, subnet)
|
165
177
|
record = ::Proxy::DHCP::Reservation.new(res_data['hostname'], res_data['ip-address'], res_data['hw-address'], subnet)
|
166
178
|
# Add the reservation to the parent class's cache, making it searchable.
|
@@ -16,6 +16,8 @@ module Proxy
|
|
16
16
|
# Initialises a new Kea API client.
|
17
17
|
#
|
18
18
|
# @param url [String] The base URL of the Kea API endpoint (e.g. 'http://127.0.0.1:8000/').
|
19
|
+
# @param username [String, nil] The username for HTTP Basic Authentication.
|
20
|
+
# @param password [String, nil] The password for HTTP Basic Authentication.
|
19
21
|
# @param open_timeout [Integer] Time in seconds to wait for the initial TCP connection to be established (defaults to 5).
|
20
22
|
# @param read_timeout [Integer] Time in seconds to wait for a response from the server after the connection is made (defaults to 10).
|
21
23
|
# @raise [ArgumentError] if the URL is blank, malformed, or not a valid HTTP/S URL.
|
@@ -26,10 +28,12 @@ module Proxy
|
|
26
28
|
# @example Initialization with Custom Timeouts
|
27
29
|
# client = Proxy::DHCP::KeaApi::Client.new(
|
28
30
|
# url: 'http://127.0.0.1:8000',
|
31
|
+
# username: 'myuser',
|
32
|
+
# password: 'mypassword'
|
29
33
|
# open_timeout: 2,
|
30
34
|
# read_timeout: 5
|
31
35
|
# )
|
32
|
-
def initialize(url:, open_timeout: 5, read_timeout: 10)
|
36
|
+
def initialize(url:, username: nil, password: nil, open_timeout: 5, read_timeout: 10)
|
33
37
|
raise ArgumentError, 'Kea API URL cannot be nil or empty' if url.to_s.empty?
|
34
38
|
|
35
39
|
@uri = URI.parse(url)
|
@@ -38,6 +42,8 @@ module Proxy
|
|
38
42
|
|
39
43
|
raise ArgumentError, "Invalid Kea API URL: '#{url}' is missing a host" unless @uri.host
|
40
44
|
|
45
|
+
@username = username
|
46
|
+
@password = password
|
41
47
|
@open_timeout = open_timeout
|
42
48
|
@read_timeout = read_timeout
|
43
49
|
logger.info "Initializing Kea API client for URL: #{@uri} with timeouts (open: #{@open_timeout}s, read: #{@read_timeout}s)"
|
@@ -49,9 +55,10 @@ module Proxy
|
|
49
55
|
# @param service [String] The Kea service to target (e.g. 'dhcp4').
|
50
56
|
# @param command [String] The command to execute (e.g. 'config-get', 'reservation-add').
|
51
57
|
# @param arguments [Hash] A hash of arguments required by the command. Defaults to an empty hash.
|
52
|
-
#
|
53
58
|
# @return [Hash] The 'arguments' hash from the Kea API response on success.
|
54
59
|
# @raise [Proxy::DHCP::Error] if the API returns an error or if there's a communication issue.
|
60
|
+
# This can be caused by underlying errors like `Net::ReadTimeout`, `Net::OpenTimeout`,
|
61
|
+
# `Errno::ECONNREFUSED`, or `JSON::ParserError`.
|
55
62
|
#
|
56
63
|
# @example Get the current DHCPv4 configuration
|
57
64
|
# client = Proxy::DHCP::KeaApi::Client.new(url: 'http://localhost:8000')
|
@@ -69,6 +76,9 @@ module Proxy
|
|
69
76
|
# }
|
70
77
|
# })
|
71
78
|
# # => {"text"=>"Reservation added successfully."}
|
79
|
+
#
|
80
|
+
# @see https://kea.readthedocs.io/en/latest/api.html General Kea Management API documentation.
|
81
|
+
# @see https://kea.readthedocs.io/en/latest/api.html#ref-reservation-add For the `reservation-add` command.
|
72
82
|
def post_command(service, command, arguments = {})
|
73
83
|
header = { 'Content-Type' => 'application/json' }
|
74
84
|
payload = {
|
@@ -87,16 +97,16 @@ module Proxy
|
|
87
97
|
http.read_timeout = @read_timeout
|
88
98
|
request = Net::HTTP::Post.new(@uri.request_uri, header)
|
89
99
|
request.body = payload.to_json
|
100
|
+
request.basic_auth(@username, @password) if @username && @password
|
90
101
|
|
91
102
|
logger.debug "Sending command to Kea: #{payload.inspect}"
|
92
103
|
response = http.request(request)
|
93
104
|
|
94
105
|
handle_response(response, command)
|
95
|
-
# This rescue block catches
|
96
|
-
#
|
97
|
-
|
98
|
-
|
99
|
-
logger.error "Failed to send command to Kea API: #{e.message}"
|
106
|
+
# This rescue block catches specific, expected network and parsing errors,
|
107
|
+
# wrapping them in a Foreman-specific error type for consistent handling.
|
108
|
+
rescue Net::ReadTimeout, Net::OpenTimeout, Errno::ECONNREFUSED, Errno::EHOSTUNREACH, JSON::ParserError => e
|
109
|
+
logger.error "Failed to send command to Kea API: #{e.class.name} - #{e.message}"
|
100
110
|
raise Proxy::DHCP::Error, "Kea API communication error: #{e.message}"
|
101
111
|
end
|
102
112
|
|
@@ -106,9 +116,9 @@ module Proxy
|
|
106
116
|
#
|
107
117
|
# @param response [Net::HTTPResponse] The raw response object from the HTTP request.
|
108
118
|
# @param command [String] The original command that was sent, used for context-specific handling.
|
109
|
-
#
|
110
119
|
# @return [Hash] The 'arguments' hash from the response on success.
|
111
|
-
# @raise [Proxy::DHCP::Error] if the response indicates a failure or is
|
120
|
+
# @raise [Proxy::DHCP::Error] if the response indicates a failure, is malformed, or is empty.
|
121
|
+
# @raise [JSON::ParserError] if the response body is not valid JSON.
|
112
122
|
# @private
|
113
123
|
def handle_response(response, command)
|
114
124
|
body = JSON.parse(response.body)
|
@@ -119,7 +129,7 @@ module Proxy
|
|
119
129
|
|
120
130
|
# If the response is successful, return its arguments. Otherwise, raise an error.
|
121
131
|
if response_successful?(result, command)
|
122
|
-
# Provide a fallback of '{}' to prevent returning nil if 'arguments' key is missing.
|
132
|
+
# Provide a fallback of '{}' to prevent returning nil if the 'arguments' key is missing.
|
123
133
|
result['arguments'] || {}
|
124
134
|
else
|
125
135
|
error_message = result['text'] || 'Unknown error from Kea API'
|
@@ -131,16 +141,16 @@ module Proxy
|
|
131
141
|
#
|
132
142
|
# @param result [Hash] The parsed result hash from the Kea response body.
|
133
143
|
# @param command [String] The original command sent, needed for special case handling.
|
134
|
-
#
|
135
144
|
# @return [Boolean] `true` if the response is considered a success, `false` otherwise.
|
145
|
+
#
|
146
|
+
# @see https://kea.readthedocs.io/en/stable/api.html For documentation on Kea API result codes.
|
136
147
|
# @private
|
137
148
|
def response_successful?(result, command)
|
138
149
|
# Universal success is result code 0.
|
139
150
|
return true if result['result'].zero?
|
140
|
-
# Special case: 'lease4-get-all' is successful even with result code 3 (no leases found).
|
141
|
-
return true if command == 'lease4-get-all' && result['result'] == 3
|
142
151
|
|
143
|
-
|
152
|
+
# Special case: 'lease4-get-all' is successful even with result code 3 (no leases found).
|
153
|
+
command == 'lease4-get-all' && result['result'] == 3
|
144
154
|
end
|
145
155
|
end
|
146
156
|
end
|
@@ -42,6 +42,8 @@ module Proxy
|
|
42
42
|
container.singleton_dependency :kea_client, (lambda do
|
43
43
|
::Proxy::DHCP::KeaApi::Client.new(
|
44
44
|
url: settings[:kea_api_url],
|
45
|
+
username: settings[:kea_api_username],
|
46
|
+
password: settings[:kea_api_password],
|
45
47
|
open_timeout: settings[:open_timeout],
|
46
48
|
read_timeout: settings[:read_timeout]
|
47
49
|
)
|
@@ -1,10 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# The top-level namespace for the Foreman Smart Proxy application.
|
4
|
+
# All core Smart Proxy modules and plugins are defined within this namespace.
|
3
5
|
module Proxy
|
6
|
+
# The namespace for DHCP-related functionality within the Foreman Smart Proxy.
|
7
|
+
# All DHCP providers and their associated services are defined here.
|
4
8
|
module DHCP
|
5
9
|
# The top-level namespace for this DHCP provider. All classes, modules,
|
6
10
|
# and services related to the Kea API integration will be defined within
|
7
11
|
# this KeaApi module to prevent naming conflicts with other plugins.
|
12
|
+
# @see Proxy::DHCP::KeaApi::Client
|
13
|
+
# @see Proxy::DHCP::KeaApi::SubnetService
|
8
14
|
module KeaApi; end
|
9
15
|
end
|
10
16
|
end
|
@@ -14,11 +14,25 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.description = 'Provides DHCP management for Foreman via the ISC Kea API, requiring the host_cmds and lease_cmds hooks.'
|
15
15
|
s.license = 'GPL-3.0-only'
|
16
16
|
s.required_ruby_version = '>= 3.0', '< 4'
|
17
|
+
s.metadata = {
|
18
|
+
'bug_tracker_uri' => 'https://gitlab.surrey.ac.uk/sm0049/smart-proxy-dhcp-kea-api/-/issues',
|
19
|
+
'homepage_uri' => 'https://gitlab.surrey.ac.uk/sm0049/smart-proxy-dhcp-kea-api',
|
20
|
+
'rubygems_mfa_required' => 'true'
|
21
|
+
}
|
17
22
|
|
18
23
|
s.files = Dir.glob('{lib}/**/*', File::FNM_DOTMATCH).reject { |f| File.directory?(f) }
|
19
24
|
s.files += %w[LICENSE README.md smart_proxy_dhcp_kea_api.gemspec]
|
20
25
|
|
21
26
|
s.require_paths = ['lib']
|
22
27
|
|
23
|
-
s.
|
28
|
+
s.add_development_dependency "bundler"
|
29
|
+
s.add_development_dependency "concurrent-ruby"
|
30
|
+
s.add_development_dependency "rack-test"
|
31
|
+
s.add_development_dependency "rake"
|
32
|
+
s.add_development_dependency "rspec"
|
33
|
+
s.add_development_dependency "rubocop"
|
34
|
+
s.add_development_dependency "rubocop-rspec"
|
35
|
+
s.add_development_dependency "yard"
|
36
|
+
s.add_development_dependency "yard-rspec"
|
37
|
+
s.add_development_dependency "webmock"
|
24
38
|
end
|
metadata
CHANGED
@@ -1,15 +1,155 @@
|
|
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
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sam McCarthy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-07-
|
12
|
-
dependencies:
|
11
|
+
date: 2025-07-22 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: concurrent-ruby
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rack-test
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rubocop
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop-rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: yard
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: yard-rspec
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: webmock
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
13
153
|
description: Provides DHCP management for Foreman via the ISC Kea API, requiring the
|
14
154
|
host_cmds and lease_cmds hooks.
|
15
155
|
email:
|
@@ -19,6 +159,7 @@ extra_rdoc_files: []
|
|
19
159
|
files:
|
20
160
|
- LICENSE
|
21
161
|
- README.md
|
162
|
+
- lib/.DS_Store
|
22
163
|
- lib/smart_proxy_dhcp_kea_api.rb
|
23
164
|
- lib/smart_proxy_dhcp_kea_api/dhcp_kea_api_main.rb
|
24
165
|
- lib/smart_proxy_dhcp_kea_api/dhcp_kea_api_plugin.rb
|
@@ -31,6 +172,8 @@ homepage: https://gitlab.surrey.ac.uk/sm0049/smart-proxy-dhcp-kea-api
|
|
31
172
|
licenses:
|
32
173
|
- GPL-3.0-only
|
33
174
|
metadata:
|
175
|
+
bug_tracker_uri: https://gitlab.surrey.ac.uk/sm0049/smart-proxy-dhcp-kea-api/-/issues
|
176
|
+
homepage_uri: https://gitlab.surrey.ac.uk/sm0049/smart-proxy-dhcp-kea-api
|
34
177
|
rubygems_mfa_required: 'true'
|
35
178
|
post_install_message:
|
36
179
|
rdoc_options: []
|