#!/usr/bin/env ruby begin require 'rubygems' rescue LoadError end require 'ohai/system' require 'json' require 'httpclient' require 'logger' require 'optparse' module NodeAgentConfig extend self attr_accessor :api def define yield self end end class NodeAgent def initialize(logger, config=nil) @logger = logger @api_default_address = "localhost" @api_default_port = "8000" if not config.nil? if not config.api.nil? @api_url = config.api end end if not @api_url begin cmdline = ::File.read("/proc/cmdline") api_ip = cmdline.match(/\burl=http:\/\/((\d{1,3}\.){3}\d{1,3})/)[1] @logger.info("Found admin node IP address in kernel cmdline: #{api_ip}") rescue @logger.error("Can't get API url from /proc/cmdline. Will use localhost.") api_ip = "127.0.0.1" end @api_url = "http://#{api_ip}:#{@api_default_port}/api" end @os = Ohai::System.new() @os.all_plugins end def put headers = {"Content-Type" => "application/json"} htclient = HTTPClient.new @logger.debug("Trying to put host info into #{@api_url}") res = htclient.put("#{@api_url}/nodes/", [_data].to_json, headers) if res.status < 200 or res.status >= 300 @logger.error("HTTP PUT failed: #{res.inspect}") end return res end def post headers = {"Content-Type" => "application/json"} htclient = HTTPClient.new @logger.debug("Trying to create host using #{@api_url}") res = htclient.post("#{@api_url}/nodes/", _data.to_json, headers) return res end def _interfaces interfaces = @os[:network][:interfaces].inject([]) do |result, elm| result << { :name => elm[0], :addresses => elm[1]["addresses"] } end interfaces << { "default_interface" => @os["network"]["default_interface"] } interfaces << { "default_gateway" => @os["network"]["default_gateway"] } interfaces end def _mac @os[:macaddress] end def _metadata { :block_device => @os["block_device"].to_hash, :interfaces => _interfaces, :cpu => @os["cpu"].to_hash, :memory => @os["memory"].to_hash, :serial => _serial } end def _is_virtual begin if @os["virtualization"]["role"] == "guest" return true end rescue end return false end def _manufacturer if _is_virtual return @os["virtualization"]["system"].upcase else begin return @os[:dmi][:system][:manufacturer] rescue return "Unknown" end end end def _product_name if _is_virtual return @os["virtualization"]["role"] else begin return @os[:dmi][:system][:product_name] rescue return "Unknown" end end end def _serial begin return @os[:dmi][:system][:serial_number] rescue return "Unknown" end end def _data res = { :fqdn => @os[:fqdn], :mac => @os[:macaddress], :ip => @os[:ipaddress], :manufacturer => _manufacturer, :platform_name => _product_name, :os_platform => @os[:platform], :meta => _metadata } res[:status] = @node_state if @node_state res end def update_state @node_state = nil if File.exist?("/opt/nailgun/system_type") fl = File.open("/opt/nailgun/system_type", "r") system_type = fl.readline.rstrip @node_state = "discover" if system_type == "bootstrap" else fl = File.open("/opt/nailgun/system_type", "w") fl.puts("target") @node_state = "ready" end end end logger = Logger.new(STDOUT) logger.level = Logger::DEBUG options = {} optparser = OptionParser.new do |opts| opts.banner = "Usage: #{__FILE__} [options]" opts.on( '-h', '--help', 'Display this screen' ) do puts opts exit end opts.on("-c", "--config CONFIG", "Config file") do |config_file| options[:config_file] = config_file end end optparser.parse! if options[:config_file].nil? options[:config_file] = "/etc/nailgun-agent/config.rb" end begin logger.info("Trying to load agent config #{options[:config_file]}") load options[:config_file] rescue LoadError logger.error("Error occured while loading agent config") end agent = NodeAgent.new(logger, NodeAgentConfig) begin agent.update_state res = agent.post if res.status == 409: agent.put end rescue Exception => e logger.error("Error in sending node info: #{e.message}") end