summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2017-07-14 12:17:00 -0700
committerTim Smith <tsmith@chef.io>2017-08-11 16:22:57 -0700
commitd03746a52331e60016d6a0454ae33c68a45e4f29 (patch)
tree63e0d8092b5aa9dbad947c1c5e491f6549089a40
parent74ae9b00ba4698a4097759506b3f844ee7f94e2d (diff)
downloadohai-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>
-rw-r--r--lib/ohai/mixin/azure_metadata.rb53
-rw-r--r--lib/ohai/plugins/azure.rb75
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