class Proxy::DHCP::BlueCat::BlueCatAPI
This Class handles all commuincation to the bluecat address manager
Attributes
contains the bluecat api token
id of your Bluecat configuration
Name of your Bluecat configuration
fqdn or ip of your bluecat address manager
id of the parent_block
that holds the subnets that you want to use
credentials of your api user
connection mode to the address manager. http or https
id of the server that holds your dhcp
credentials of your api user
validate ssl connection. true or false
name of your dns view
Public Class Methods
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 48 def initialize(scheme, verify, host, parent_block, view_name, config_name, config_id, server_id, username, password) @scheme = scheme @verify = verify @host = host @parent_block = parent_block @view_name = view_name @config_name = config_name @config_id = config_id @server_id = server_id @username = username @password = password end
Public Instance Methods
public wrapper function to add the dhcp reservation and dns records
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 221 def add_host(options) # add the ip and hostname and mac as static rest_post("addDeviceInstance", "configName=#{@config_name} \ &ipAddressMode=PASS_VALUE \ &ipEntity=#{options["ip"]} \ &viewName=#{@view_name} \ &zoneName=#{options["hostname"].split(".", 2).last} \ &deviceName=#{options["hostname"]} \ &recordName=#{options["hostname"]} \ &macAddressMode=PASS_VALUE \ &macEntity=#{options["mac"]} \ &options=AllowDuplicateHosts=true%7C") address_id = get_addressid_by_ip(options["ip"]) # update the state of the ip from static to dhcp reserved rest_put("changeStateIP4Address", "addressId=#{address_id} \ &targetState=MAKE_DHCP_RESERVED \ &macAddress=#{options["mac"]}") unless options["nextServer"].nil? || options["filename"].nil? rest_post("addDHCPClientDeploymentOption", "entityId=#{address_id}&name=tftp-server-name&value=#{options["nextServer"]}") rest_post("addDHCPClientDeploymentOption", "entityId=#{address_id}&name=boot-file-name&value=#{options["filename"]}") end # deploy the config rest_post("deployServerConfig", "serverId=#{@server_id}&properties=services=DHCP") # lets wait a little bit for the complete dhcp deploy sleep 3 rest_post("deployServerConfig", "serverId=#{@server_id}&properties=services=DNS") nil end
public fetches a subnet by its network address
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 310 def find_mysubnet(subnet_address) net = IPAddress.parse(get_network_by_ip(subnet_address)) ::Proxy::DHCP::Subnet.new(net.address, net.netmask) end
helper function to get the object id of a ip by an ip address
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 176 def get_addressid_by_ip(ip) json = rest_get("getIP4Address", "containerId=#{@config_id}&address=#{ip}") result = JSON.parse(json) return nil if result.empty? result["id"].to_s end
helper function to get the whole subnet informarions by an ip address
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 196 def get_network_by_ip(ip) logger.debug("BAM get_network_by_ip #{ip}") querystring = "containerId=#{@config_id}&type=IP4Network&address=#{ip}" json = rest_get("getIPRangedByIP", querystring) result = JSON.parse(json) properties = parse_properties(result["properties"]) properties["CIDR"].to_s end
helper function to get the object id of a subnet by an ip address
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 185 def get_networkid_by_ip(ip) logger.debug("BAM get_networkid_by_ip #{ip}") querystring = "containerId=#{@config_id}&type=IP4Network&address=#{ip}" json = rest_get("getIPRangedByIP", querystring) result = JSON.parse(json) return nil if result.empty? result["id"].to_s end
public fetches all dhcp reservations by a mac
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 394 def host_by_mac_and_subnet(subnet_of_host, mac) logger.debug("subnet_of_host #{subnet_of_host}") net = get_network_by_ip(subnet_of_host) logger.debug("net #{net}") subnet = IPAddress.parse(net) logger.debug("subnet #{subnet} ") json = rest_get("getMACAddress", "configurationId=#{@config_id}&macAddress=#{mac}") result = JSON.parse(json) macid = result["id"].to_s return if macid == "0" json2 = rest_get("getLinkedEntities", "entityId=#{macid}&type=IP4Address&start=0&count=9999") result2 = JSON.parse(json2) return nil if result2.empty? logger.debug("das #{result2}") result2.each do |record| properties = parse_properties(record["properties"]) ip = IPAddress(properties["address"]) logger.debug("hier #{subnet.to_string} #{ip.to_string}") next unless subnet.include?(ip) logger.debug("hier #{record}") host = hosts_by_ip(properties["address"]) return nil if host.nil? logger.debug("da #{host}") return host[0] end nil end
public fetches all dhcp reservations in a subnet
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 317 def hosts(network_address) netid = get_networkid_by_ip(network_address) net = IPAddress.parse(get_network_by_ip(network_address)) subnet = ::Proxy::DHCP::Subnet.new(net.address, net.netmask) json = rest_get("getNetworkLinkedProperties", "networkId=#{netid}") results = JSON.parse(json) hosts = results.map do |result| properties = parse_properties(result["properties"]) ## Static Addresses and Gateway are not needed here ## But lets keep the logic to identify them # if properties.length() >= 4 # if properties["state"] == "Gateway" or properties["state"] == "Static" # address = properties[0].split("=").last() # macAddress = "00:00:00:00:00:00" # hosttag = properties[3].split("=").last().split(":") # name = hosttag[1] + "." + hosttag[3] # opts = {:hostname => name} # ::Proxy::DHCP::Reservation.new(name, address, macAddress, subnet, opts) # end # end next unless properties.length >= 5 next unless properties["state"] == "DHCP Reserved" hosttag = properties["host"].split(":") name = "#{hosttag[1]}.#{hosttag[3]}" opts = { hostname: name } ::Proxy::DHCP::Reservation.new(name, properties["address"], properties["macAddress"].tr("-", ":"), subnet, opts) end hosts.compact end
public fetches a host by its ip
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 353 def hosts_by_ip(ip) hosts = [] net = IPAddress.parse(get_network_by_ip(ip)) subnet = ::Proxy::DHCP::Subnet.new(net.address, net.netmask) ipid = get_addressid_by_ip(ip) return nil if ipid.to_s == "0" json = rest_get("getLinkedEntities", "entityId=#{ipid}&type=HostRecord&start=0&count=2") results = JSON.parse(json) if results.empty? || (results == "Link request is not supported") # no host record on ip, fetch mac only json2 = rest_get("getIP4Address", "containerId=#{@config_id}&address=#{ip}") result2 = JSON.parse(json2) properties2 = parse_properties(result2["properties"]) unless properties2["macAddress"].nil? mac_address = properties2["macAddress"].tr("-", ":") hosts.push(Proxy::DHCP::Reservation.new("", ip, mac_address, subnet, {})) end else # host record on ip, return more infos results.each do |result| properties = parse_properties(result["properties"]) opts = { hostname: properties["absoluteName"] } next unless properties["reverseRecord"].to_s == "true".to_s json2 = rest_get("getEntityById", "id=#{ipid}") result2 = JSON.parse(json2) properties2 = parse_properties(result2["properties"]) unless properties2["macAddress"].nil? mac_address = properties2["macAddress"].tr("-", ":") hosts.push(Proxy::DHCP::Reservation.new(properties["absoluteName"], ip, mac_address, subnet, opts)) end end end hosts.compact end
public fetches the next free address in a subnet +end_ip not implemented+
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 276 def next_ip(netadress, start_ip, _end_ip) networkid = get_networkid_by_ip(netadress) start_ip = IPAddress.parse(netadress).first if start_ip.to_s.empty? properties = "offset=#{start_ip}%7CexcludeDHCPRange=false" result = rest_get("getNextIP4Address", "parentId=#{networkid}&properties=#{properties}") return if result.empty? result.tr('"', "") end
helper function to parse the properties scheme of bluecat into a hash
properies: a string that contains properties for the object in attribute=value format, with each separated by a | (pipe) character. For example, a host record object may have a properties field such as ttl=123|comments=my comment|.
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 210 def parse_properties(properties) properties = properties.split("|") h = {} properties.each do |property| h[property.split("=").first.to_s] = property.split("=").last.to_s end h end
public wrapper function to remove a ip record and depending dns records
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 260 def remove_host(ip) ipid = get_addressid_by_ip(ip) json = rest_get("getLinkedEntities", "entityId=#{ipid}&type=HostRecord&start=0&count=2") results = JSON.parse(json) results.map do |result| rest_delete("delete", "objectId=#{result["id"]}") end rest_delete("delete", "objectId=#{ipid}") rest_post("deployServerConfig", "serverId=#{@server_id}&properties=services=DHCP,DNS") end
wrapper function to for rest delete requests
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 155 def rest_delete(endpoint, querystring) logger.debug("BAM DELETE #{endpoint}?#{querystring}") response = HTTParty.delete(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) # Session propably expired, refresh it and do the request again if response.code == 401 rest_login response = HTTParty.delete(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) end return response.body if response.code == 200 logger.error("BAM DELETE Failed. HTTP#{response.code} #{response.body}") end
wrapper function to for rest get requests
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 91 def rest_get(endpoint, querystring) rest_login if self.class.token.nil? logger.debug("BAM GET #{endpoint}?#{querystring}") response = HTTParty.get(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) # Session propably expired, refresh it and do the request again if response.code == 401 rest_login response = HTTParty.get(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) end return response.body if response.code == 200 logger.error("BAM GET Failed. HTTP#{response.code} #{response.body}") end
login to bam, parse the session token
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 62 def rest_login logger.debug("BAM Login #{@scheme} #{@host} ") response = HTTParty.get(format("%s://%s/Services/REST/v1/login?username=%s&password=%s", @scheme, @host, @username, @password), headers: { "Content-Type" => "text/plain" }, verify => @verify) logger.error("BAM Login Failed. HTTP#{response.code} #{response.body}") if response.code != 200 body = response.body.to_s token = body.match(/BAMAuthToken:\s+(\S+)/).captures logger.debug("BAM Login Body #{response.body}") logger.debug("BAM Login Token #{token[0]}") self.class.token = token[0].to_s end
logout from bam
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 81 def rest_logout logger.debug("BAM Logout ") response = HTTParty.get(format("%s://%s/Services/REST/v1/logout", @scheme, @host), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) logger.error("BAM Logout Failed. HTTP#{response.code} #{response.body}") if response.code != 200 end
wrapper function to for rest post requests
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 115 def rest_post(endpoint, querystring) logger.debug("BAM POST #{endpoint}?#{querystring}") response = HTTParty.post(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) # Session propably expired, refresh it and do the request again if response.code == 401 rest_login response = HTTParty.post(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) end return response.body if response.code == 200 logger.error("BAM POST Failed. HTTP#{response.code} #{response.body}") end
wrapper function to for rest put requests
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 135 def rest_put(endpoint, querystring) logger.debug("BAM PUT #{endpoint}?#{querystring}") response = HTTParty.put(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) # Session propably expired, refresh it and do the request again if response.code == 401 rest_login response = HTTParty.put(format("%s://%s/Services/REST/v1/%s?%s", @scheme, @host, endpoint, querystring), headers: { "Authorization" => "BAMAuthToken: #{self.class.token}", "Content-Type" => "application/json" }, verify: @verify) end return response.body if response.code == 200 logger.error("BAM PUT Failed. HTTP#{response.code} #{response.body}") end
public fetches all subnets under the parent_block
# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 290 def subnets json = rest_get("getEntities", "parentId=#{@parent_block}&type=IP4Network&start=0&count=10000") results = JSON.parse(json) subnets = results.map do |result| properties = parse_properties(result["properties"]) net = IPAddress.parse(properties["CIDR"]) opts = { routers: [properties["gateway"]] } if properties["gateway"].nil? logger.error("subnet issue: #{properties["CIDR"]} skipped, due missing gateway in bluecat") next end ::Proxy::DHCP::Subnet.new(net.address, net.netmask, opts) end subnets.compact end