#!/usr/bin/env ruby
require 'optparse'
require 'json'
require 'rest-client'

def find_base name = "default"
  return name if File.exist?(name)

  file = File.absolute_path(File.dirname(__FILE__) + "/../test/facts/#{name}.json")
  raise "Unable to find file #{file}" unless File.exist?(file)

  file
end

base = find_base
version = "3.4.0"
interfaces = []
preserve_interfaces = false
use_facts_endpoint = false
primary = nil
bootif = nil
url = "http://admin:changeme@localhost:3000"
organization = nil
location = nil
OptionParser.new do |opts|
  opts.banner = "Usage: discover-host [options]"

  opts.on("-jFILE", "--json=FILE", "Base JSON filename") do |v|
    base = find_base(v)
  end

  opts.on("-vVERSION", "--version=VERSION", "Version of the discovery image (defaults to #{version})") do |v|
    version = v
  end

  opts.on("-iARRAY", "--interface=ARRAY", Array, "Comma separated array: name,network/prefix,mac,ip (can be used multiple times, default: eth0,192.168.122.0/24") do |v|
    interfaces << v
  end

  opts.on("-x", "--[no-]preserve-interfaces", "Preserve interfaces from JSON") do |v|
    preserve_interfaces = true
  end

  opts.on("-a", "--facts", "Use host facts endpoint") do |v|
    use_facts_endpoint = true
  end

  opts.on("-pNAME", "--primary=NAME", "Interface to use as primary (defaults to the first one)") do |v|
    primary = v
  end

  opts.on("-bNAME", "--boot=NAME", "Interface it was booted from (defaults to the first one)") do |v|
    bootif = v
  end

  opts.on("-uURL", "--url=URL", "URL to foreman (#{url} by default)") do |v|
    url = v
  end

  opts.on("-oORGANIZATION", "--organization=ORGANIZATION", "Organization override to discover in (defaults to subnet)") do |v|
    organization = v
  end

  opts.on("-lLOCATION", "--location=LOCATION", "Location override to discover in (defaults to subnet)") do |v|
    location = v
  end
end.parse!

interfaces << ["eth0", "192.168.122.0/24"] if interfaces.empty?
primary ||= interfaces.first.first
bootif ||= interfaces.first.first
json = JSON.parse(File.read(base))
json["foreman_organization"] = organization if organization
json["foreman_location"] = location if location
json["discovery_version"] = version
unless preserve_interfaces
  json["interfaces"] = interfaces.map{|i| i.first}.join(',')
  interfaces.each do |iface|
    name, subnet, mac, explicit_ip = iface
    mac ||= (["52"] + 5.times.map { '%02x' % rand(0..255) }).join(':')
    json["macaddress_#{name}"] = mac
    _, prefix = subnet.split('/')
    if subnet.include?('.')
      random_ip = IPAddr.new(subnet, Socket::AF_INET) | IPAddr.new(rand(2**(32 - prefix.to_i)), Socket::AF_INET)
      fact_name = "ipaddress"
    else
      random_ip = IPAddr.new(subnet, Socket::AF_INET6) | IPAddr.new(rand(2**(32 - prefix.to_i)), Socket::AF_INET6)
      fact_name = "ipaddress6"
    end
    json["#{fact_name}_#{name}"] = explicit_ip ? explicit_ip : random_ip
    if name == primary
      json["macaddress"] = json["macaddress_#{name}"]
      json[fact_name] = json["#{fact_name}_#{name}"]
    end
    json["discovery_bootif"] = mac if name == bootif
  end
end
puts JSON.pretty_generate(json)
if use_facts_endpoint
  endpoint = url + "/api/v2/hosts/facts"
  payload = {"facts" => json, "name" => json["hostname"] || json["networking"]["fqdn"]}
else
  endpoint = url + "/api/v2/discovered_hosts/facts"
  payload = {"facts" => json}
end
resource = RestClient::Resource.new(endpoint, verify_ssl: OpenSSL::SSL::VERIFY_NONE)
response = resource.post(payload.to_json, {content_type: :json, accept: :json})
puts response.code
puts response.body
