Class: Proxy::Netbox::NetboxClient

Inherits:
Object
  • Object
show all
Includes:
Ipam::IpamHelper, Ipam::IpamValidator, Log
Defined in:
lib/smart_proxy_ipam/netbox/netbox_client.rb

Overview

Implementation class for External IPAM provider Netbox

Constant Summary

Constants included from Ipam::IpamHelper

Ipam::IpamHelper::ERRORS, Ipam::IpamHelper::MAX_IP_RETRIES

Instance Method Summary collapse

Methods included from Ipam::IpamValidator

#validate_cidr!, #validate_ip!, #validate_ip_in_cidr!, #validate_mac!, #validate_required_params!

Methods included from Ipam::IpamHelper

#cache_next_ip, #find_new_ip, #get_request_group, #increment_ip, #provider, #usable_ip

Constructor Details

#initialize(conf) ⇒ NetboxClient

Returns a new instance of NetboxClient.



19
20
21
22
23
24
25
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 19

def initialize(conf)
  @api_base = "#{conf[:url]}/api/"
  @token = conf[:token]
  @api_resource = Proxy::Ipam::ApiResource.new(api_base: @api_base, token: "Token #{@token}")
  @ip_cache = Proxy::Ipam::IpCache.instance
  @ip_cache.set_provider_name('netbox')
end

Instance Method Details

#add_ip_to_subnet(ip, params) ⇒ Object



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 131

def add_ip_to_subnet(ip, params)
  desc = 'Address auto added by Foreman'
  address = "#{ip}/#{params[:cidr].split('/').last}"
  group_name = params[:group_name]

  if group_name.nil? || group_name.empty?
    data = { address: address, nat_outside: 0, description: desc }
  else
    group_id = get_group_id(group_name)
    data = { vrf: group_id, address: address, nat_outside: 0, description: desc }
  end

  response = @api_resource.post('ipam/ip-addresses/', data.to_json)
  return nil if response.code == '201'
  { error: "Unable to add #{address} in External IPAM server" }
end

#authenticated?Boolean

Returns:

  • (Boolean)


184
185
186
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 184

def authenticated?
  !@token.nil?
end

#delete_ip_from_subnet(ip, params) ⇒ Object



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 148

def delete_ip_from_subnet(ip, params)
  group_name = params[:group_name]

  if group_name.nil? || group_name.empty?
    params = URI.encode_www_form({ address: ip })
  else
    group_id = get_group_id(group_name)
    params = URI.encode_www_form({ address: ip, vrf_id: group_id })
  end

  response = @api_resource.get("ipam/ip-addresses/?#{params}")
  json_body = JSON.parse(response.body)

  return { error: ERRORS[:no_ip] } if json_body['count'].zero?

  address_id = json_body['results'][0]['id']
  response = @api_resource.delete("ipam/ip-addresses/#{address_id}/")
  return nil if response.code == '204'
  { error: "Unable to delete #{ip} in External IPAM server" }
end

#get_group_id(group_name) ⇒ Object



88
89
90
91
92
93
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 88

def get_group_id(group_name)
  return nil if group_name.nil? || group_name.empty?
  group = get_ipam_group(group_name)
  raise ERRORS[:no_group] if group.nil?
  group[:id]
end

#get_ipam_group(group_name) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 71

def get_ipam_group(group_name)
  raise ERRORS[:groups_not_supported] unless groups_supported?
  # TODO: Fix encoding of params in a common way for all providers
  params = URI.encode_www_form({ name: URI.decode(group_name) })
  response = @api_resource.get("ipam/vrfs/?#{params}")
  json_body = JSON.parse(response.body)
  return nil if json_body['count'].zero?

  group = {
    id: json_body['results'][0]['id'],
    name: json_body['results'][0]['name'],
    description: json_body['results'][0]['description']
  }

  return group if json_body['results']
end

#get_ipam_groupsObject



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 54

def get_ipam_groups
  response = @api_resource.get('ipam/vrfs/')
  json_body = JSON.parse(response.body)
  groups = []

  return groups if json_body['count'].zero?

  json_body['results'].each do |group|
    groups.push({
      name: group['name'],
      description: group['description']
    })
  end

  groups
end

#get_ipam_subnet(cidr, group_name = nil) ⇒ Object



27
28
29
30
31
32
33
34
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 27

def get_ipam_subnet(cidr, group_name = nil)
  if group_name.nil? || group_name.empty?
    get_ipam_subnet_by_cidr(cidr)
  else
    group_id = get_group_id(group_name)
    get_ipam_subnet_by_group(cidr, group_id)
  end
end

#get_ipam_subnet_by_cidr(cidr) ⇒ Object



45
46
47
48
49
50
51
52
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 45

def get_ipam_subnet_by_cidr(cidr)
  params = URI.encode_www_form({ status: 'active', prefix: cidr })
  response = @api_resource.get("ipam/prefixes/?#{params}")
  json_body = JSON.parse(response.body)
  return nil if json_body['count'].zero?
  subnet = subnet_from_result(json_body['results'][0])
  return subnet if json_body['results']
end

#get_ipam_subnet_by_group(cidr, group_id) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 36

def get_ipam_subnet_by_group(cidr, group_id)
  params = URI.encode_www_form({ status: 'active', prefix: cidr, vrf_id: group_id })
  response = @api_resource.get("ipam/prefixes/?#{params}")
  json_body = JSON.parse(response.body)
  return nil if json_body['count'].zero?
  subnet = subnet_from_result(json_body['results'][0])
  return subnet if json_body['results']
end

#get_ipam_subnets(group_name) ⇒ Object



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 95

def get_ipam_subnets(group_name)
  if group_name.nil?
    params = URI.encode_www_form({ status: 'active' })
  else
    group_id = get_group_id(group_name)
    params = URI.encode_www_form({ status: 'active', vrf_id: group_id })
  end

  response = @api_resource.get("ipam/prefixes/?#{params}")
  json_body = JSON.parse(response.body)
  return nil if json_body['count'].zero?
  subnets = []

  json_body['results'].each do |subnet|
    subnets.push({
      subnet: subnet['prefix'].split('/').first,
      mask: subnet['prefix'].split('/').last,
      description: subnet['description'],
      id: subnet['id']
    })
  end

  return subnets if json_body['results']
end

#get_next_ip(mac, cidr, group_name) ⇒ Object



169
170
171
172
173
174
175
176
177
178
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 169

def get_next_ip(mac, cidr, group_name)
  subnet = get_ipam_subnet(cidr, group_name)
  raise ERRORS[:no_subnet] if subnet.nil?
  response = @api_resource.get("ipam/prefixes/#{subnet[:id]}/available-ips/?limit=1")
  json_body = JSON.parse(response.body)
  return nil if json_body.empty?
  ip = json_body[0]['address'].split('/').first
  next_ip = cache_next_ip(@ip_cache, ip, mac, cidr, subnet[:id], group_name)
  { data: next_ip }
end

#groups_supported?Boolean

Returns:

  • (Boolean)


180
181
182
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 180

def groups_supported?
  true
end

#ip_exists?(ip, subnet_id, group_name) ⇒ Boolean

Returns:

  • (Boolean)


120
121
122
123
124
125
126
127
128
129
# File 'lib/smart_proxy_ipam/netbox/netbox_client.rb', line 120

def ip_exists?(ip, subnet_id, group_name)
  group_id = get_group_id(group_name)
  url = "ipam/ip-addresses/?#{URI.encode_www_form({ address: ip })}"
  url += "&#{URI.encode_www_form({ prefix_id: subnet_id })}" unless subnet_id.nil?
  url += "&#{URI.encode_www_form({ vrf_id: group_id })}" unless group_id.nil?
  response = @api_resource.get(url)
  json_body = JSON.parse(response.body)
  return false if json_body['count'].zero?
  true
end