diff options
author | Tim Smith <tsmith@chef.io> | 2017-07-14 12:17:00 -0700 |
---|---|---|
committer | Tim Smith <tsmith@chef.io> | 2017-08-11 16:22:57 -0700 |
commit | d03746a52331e60016d6a0454ae33c68a45e4f29 (patch) | |
tree | 63e0d8092b5aa9dbad947c1c5e491f6549089a40 /lib | |
parent | 74ae9b00ba4698a4097759506b3f844ee7f94e2d (diff) | |
download | ohai-d03746a52331e60016d6a0454ae33c68a45e4f29.tar.gz |
Add Azure metadata endpoint support
The Azure metadata endpoint has gone GA. This pulls instance information straight from the source.
Signed-off-by: Tim Smith <tsmith@chef.io>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/ohai/mixin/azure_metadata.rb | 53 | ||||
-rw-r--r-- | lib/ohai/plugins/azure.rb | 75 |
2 files changed, 120 insertions, 8 deletions
diff --git a/lib/ohai/mixin/azure_metadata.rb b/lib/ohai/mixin/azure_metadata.rb new file mode 100644 index 00000000..e44c0241 --- /dev/null +++ b/lib/ohai/mixin/azure_metadata.rb @@ -0,0 +1,53 @@ +# +# Author:: Tim Smith (<tsmith@chef.io>) +# Copyright:: Copyright 2017 Chef Software, Inc. +# License:: Apache License, Version 2.0 +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +require "net/http" + +module Ohai + module Mixin + module AzureMetadata + + AZURE_METADATA_ADDR = "169.254.169.254" unless defined?(AZURE_METADATA_ADDR) + AZURE_METADATA_URL = "/metadata/instance?api-version=2017-04-02" unless defined?(AZURE_METADATA_URL) + + # fetch the meta content with a timeout and the required header + def http_get(uri) + conn = Net::HTTP.start(AZURE_METADATA_ADDR) + conn.read_timeout = 6 + conn.get(uri, initheader = { "Metadata" => "true" }) + end + + def fetch_metadata + Ohai::Log.debug("Mixin AzureMetadata: Fetching metadata from host #{AZURE_METADATA_ADDR} at #{AZURE_METADATA_URL}") + response = http_get(AZURE_METADATA_URL) + if response.code == "200" + begin + data = StringIO.new(response.body) + parser = FFI_Yajl::Parser.new + parser.parse(data) + rescue FFI_Yajl::ParseError + Ohai::Log.debug("Mixin AzureMetadata: Metadata response is NOT valid JSON") + {} + end + else + Ohai::Log.debug("Mixin AzureMetadata: Received resonse code #{response.code} requesting metadata") + {} + end + end + end + end +end diff --git a/lib/ohai/plugins/azure.rb b/lib/ohai/plugins/azure.rb index 7eae3955..671b4428 100644 --- a/lib/ohai/plugins/azure.rb +++ b/lib/ohai/plugins/azure.rb @@ -1,4 +1,4 @@ -# Copyright:: Copyright (c) 2013-2016 Chef Software, Inc. +# Copyright:: Copyright 2013-2017 Chef Software, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,24 +14,32 @@ # limitations under the License. # +require "ohai/mixin/azure_metadata" +require "ohai/mixin/http_helper" + Ohai.plugin(:Azure) do + include Ohai::Mixin::AzureMetadata + include Ohai::Mixin::HttpHelper + provides "azure" collect_data do - # The azure hints are populated by the knife plugin for Azure. - # The project is located at https://github.com/chef/knife-azure + # Before we had the metadata endpoint we relied exclusively on + # the knife-azure plugin populating data to the hint file. # Please see the lib/chef/knife/azure_server_create.rb file in that # project for details azure_metadata_from_hints = hint?("azure") if azure_metadata_from_hints - Ohai::Log.debug("Plugin Azure: azure_metadata_from_hints is present.") + Ohai::Log.debug("Plugin Azure: Azure hint is present. Parsing any hint data.") azure Mash.new azure_metadata_from_hints.each { |k, v| azure[k] = v } + azure["metadata"] = parse_metadata elsif has_waagent? || has_dhcp_option_245? - Ohai::Log.debug("Plugin Azure: No hints present, but system appears to be on azure.") + Ohai::Log.debug("Plugin Azure: No hints present, but system appears to be on Azure.") azure Mash.new + azure["metadata"] = parse_metadata else - Ohai::Log.debug("Plugin Azure: No hints present for azure and doesn't appear to be azure.") + Ohai::Log.debug("Plugin Azure: No hints present and doesn't appear to be on Azure.") false end end @@ -40,7 +48,7 @@ Ohai.plugin(:Azure) do # http://blog.mszcool.com/index.php/2015/04/detecting-if-a-virtual-machine-runs-in-microsoft-azure-linux-windows-to-protect-your-software-when-distributed-via-the-azure-marketplace/ def has_waagent? if File.exist?("/usr/sbin/waagent") || Dir.exist?('C:\WindowsAzure') - Ohai::Log.debug("Plugin Azure: Found waagent used by MS Azure.") + Ohai::Log.debug("Plugin Azure: Found waagent used by Azure.") true end end @@ -50,7 +58,7 @@ Ohai.plugin(:Azure) do if File.exist?("/var/lib/dhcp/dhclient.eth0.leases") File.open("/var/lib/dhcp/dhclient.eth0.leases").each do |line| if line =~ /unknown-245/ - Ohai::Log.debug("Plugin Azure: Found unknown-245 DHCP option used by MS Azure.") + Ohai::Log.debug("Plugin Azure: Found unknown-245 DHCP option used by Azure.") has_245 = true break end @@ -59,4 +67,55 @@ Ohai.plugin(:Azure) do has_245 end + # create the basic structure we'll store our data in + def initialize_metadata_mash + metadata = Mash.new + metadata["compute"] = Mash.new + metadata["network"] = Mash.new + metadata["network"]["interfaces"] = Mash.new + %w{public_ipv4 local_ipv4 public_ipv6 local_ipv6}.each do |type| + metadata["network"][type] = [] + end + metadata + end + + def fetch_ip_data(data, type, field) + ips = [] + + data[type]["ipAddress"].each do |val| + ips << val[field] unless val[field].empty? + end + ips + end + + def parse_metadata + return nil unless can_socket_connect?(Ohai::Mixin::AzureMetadata::AZURE_METADATA_ADDR, 80) + + endpoint_data = fetch_metadata + metadata = initialize_metadata_mash + + # blindly add everything in compute to our data structure + endpoint_data["compute"].each do |k, v| + metadata["compute"][k] = v + end + + # parse out per interface interface IP data + endpoint_data["network"]["interface"].each do |int| + metadata["network"]["interfaces"][int["macAddress"]] = Mash.new + metadata["network"]["interfaces"][int["macAddress"]]["mac"] = int["macAddress"] + metadata["network"]["interfaces"][int["macAddress"]]["public_ipv6"] = fetch_ip_data(int, "ipv6", "publicIpAddress") + metadata["network"]["interfaces"][int["macAddress"]]["public_ipv4"] = fetch_ip_data(int, "ipv4", "publicIpAddress") + metadata["network"]["interfaces"][int["macAddress"]]["local_ipv6"] = fetch_ip_data(int, "ipv6", "privateIpAddress") + metadata["network"]["interfaces"][int["macAddress"]]["local_ipv4"] = fetch_ip_data(int, "ipv4", "privateIpAddress") + end + + # aggregate the total IP data + %w{public_ipv4 local_ipv4 public_ipv6 local_ipv6}.each do |type| + metadata["network"]["interfaces"].each_value do |val| + metadata["network"][type].concat val[type] unless val[type].empty? + end + end + + metadata + end end |