class Proxy::DHCP::BlueCat::BlueCatAPI

This Class handles all commuincation to the bluecat address manager

Attributes

token[RW]

contains the bluecat api token

config_id[R]

id of your Bluecat configuration

config_name[R]

Name of your Bluecat configuration

host[R]

fqdn or ip of your bluecat address manager

parent_block[R]

id of the parent_block that holds the subnets that you want to use

password[R]

credentials of your api user

scheme[R]

connection mode to the address manager. http or https

server_id[R]

id of the server that holds your dhcp

username[R]

credentials of your api user

verify[R]

validate ssl connection. true or false

view_name[R]

name of your dns view

Public Class Methods

new(scheme, verify, host, parent_block, view_name, config_name, config_id, server_id, username, password) click to toggle source
# 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

add_host(options) click to toggle source

public wrapper function to add the dhcp reservation and dns records

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 204
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? or options['filename'].nil?
    rest_post('addDHCPClientDeploymentOption', 'entityId=' + address_id.to_s + '&name=tftp-server-name' + "&value=" + options['nextServer'].to_s)
    rest_post('addDHCPClientDeploymentOption', 'entityId=' + address_id.to_s + '&name=boot-file-name' + "&value=" + options['filename'].to_s)
  end

  # deploy the config
  rest_post('deployServerConfig', 'serverId=' + @server_id.to_s + '&properties=services=DHCP')
  # lets wait a little bit for the complete dhcp deploy
  sleep 3
  rest_post('deployServerConfig', 'serverId=' + @server_id.to_s + '&properties=services=DNS')
  nil
end
find_mysubnet(subnet_address) click to toggle source

public fetches a subnet by its network address

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 288
def find_mysubnet(subnet_address)
  net = IPAddress.parse(get_network_by_ip(subnet_address))
  subnet = ::Proxy::DHCP::Subnet.new(net.address, net.netmask)
  subnet
end
get_addressid_by_ip(ip) click to toggle source

helper function to get the object id of a ip by an ip address

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 162
def get_addressid_by_ip(ip)
  json = rest_get('getIP4Address', 'containerId=' + @config_id.to_s + '&address=' + ip)
  result = JSON.parse(json)
  return nil if result.empty?
  result['id'].to_s
end
get_network_by_ip(ip) click to toggle source

helper function to get the whole subnet informarions by an ip address

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 180
def get_network_by_ip(ip)
  logger.debug('BAM get_network_by_ip ' + ip)
  querystring = 'containerId=' + @config_id.to_s + '&type=IP4Network' + '&address=' + ip.to_s
  json = rest_get('getIPRangedByIP', querystring)
  result = JSON.parse(json)
  properties = parse_properties(result['properties'])
  properties['CIDR'].to_s
end
get_networkid_by_ip(ip) click to toggle source

helper function to get the object id of a subnet by an ip address

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 170
def get_networkid_by_ip(ip)
  logger.debug('BAM get_networkid_by_ip ' + ip)
  querystring = 'containerId=' + @config_id.to_s + '&type=IP4Network' + '&address=' + ip.to_s
  json = rest_get('getIPRangedByIP', querystring)
  result = JSON.parse(json)
  return nil if result.empty?
  result['id'].to_s
end
host_by_mac(mac) click to toggle source

public fetches all dhcp reservations by a mac

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 370
def host_by_mac(mac)
  json = rest_get('getMACAddress', 'configurationId=' + @config_id.to_s + '&macAddress=' + mac.to_s)
  result = JSON.parse(json)
  macid = result['id'].to_s
  return if macid == '0'
  json2 = rest_get('getLinkedEntities', 'entityId=' + macid + '&type=IP4Address&start=0&count=1')
  result2 = JSON.parse(json2)
  return if result2.empty?
  properties = parse_properties(result2[0]['properties'])
  host = hosts_by_ip(properties['address'])
  return if host.nil?
  host[0]
end
hosts(network_address) click to toggle source

public fetches all dhcp reservations in a subnet

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 296
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.to_s)
  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
hosts_by_ip(ip) click to toggle source

public fetches a host by its ip

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 331
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.to_s + '&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
next_ip(netadress, start_ip, end_ip) click to toggle source

public fetches the next free address in a subnet +end_ip not implemented+

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 255
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.to_s + '%7CexcludeDHCPRange=false'
  result = rest_get('getNextIP4Address', 'parentId=' + networkid.to_s + '&properties=' + properties)
  return if result.empty?
  result.tr('"', '')
end
parse_properties(properties) click to toggle source

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 193
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
remove_host(ip) click to toggle source

public wrapper function to remove a ip record and depending dns records

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 239
def remove_host(ip)
  ipid = get_addressid_by_ip(ip)
  json = rest_get('getLinkedEntities', 'entityId=' + ipid.to_s + '&type=HostRecord&start=0&count=2')
  results = JSON.parse(json)

  hosts = results.map do |result|
    rest_delete('delete', 'objectId=' + result['id'].to_s)
  end
  rest_delete('delete', 'objectId=' + ipid.to_s)

  rest_post('deployServerConfig', 'serverId=' + @server_id.to_s + '&properties=services=DHCP,DNS')
end
rest_delete(endpoint, querystring) click to toggle source

wrapper function to for rest delete requests

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 144
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.to_s + ' ' + response.body.to_s)
end
rest_get(endpoint, querystring) click to toggle source

wrapper function to for rest get requests

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 88
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.to_s + ' ' + response.body.to_s)
end
rest_login() click to toggle source

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)
  if response.code != 200
    logger.error('BAM Login Failed. HTTP' + response.code.to_s + ' ' + response.body.to_s)
  end
  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].to_s)
  self.class.token = token[0].to_s
end
rest_logout() click to toggle source

logout from bam

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 79
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.to_s + ' ' + response.body.to_s) if response.code != 200
end
rest_post(endpoint, querystring) click to toggle source

wrapper function to for rest post requests

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 109
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.to_s + ' ' + response.body.to_s)
end
rest_put(endpoint, querystring) click to toggle source

wrapper function to for rest put requests

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 127
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.to_s + ' ' + response.body.to_s)
end
subnets() click to toggle source

public fetches all subnets under the parent_block

# File lib/smart_proxy_dhcp_bluecat/bluecat_api.rb, line 268
def subnets
  json = rest_get('getEntities', 'parentId=' + @parent_block.to_s + '&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