summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Smith <tsmith@chef.io>2021-02-10 18:04:03 -0800
committerGitHub <noreply@github.com>2021-02-10 18:04:03 -0800
commit2e48aed6265f1830bcfdd640d8cfe2373fc99c58 (patch)
treed98b67eaf3571ef24bbf0e2d2cbcdbbd04aa90ea
parentba09f9b476b37c9c07e8d572c8fdba73450fbd06 (diff)
parent15b1c965cec56b69a0179f927230f329a3065b78 (diff)
downloadohai-2e48aed6265f1830bcfdd640d8cfe2373fc99c58.tar.gz
Merge pull request #1620 from chef/alibaba
Signed-off-by: Tim Smith <tsmith@chef.io>
-rw-r--r--lib/ohai/mixin/alibaba_metadata.rb86
-rw-r--r--lib/ohai/plugins/alibaba.rb72
-rw-r--r--lib/ohai/plugins/cloud.rb19
-rw-r--r--spec/unit/plugins/alibaba_spec.rb89
-rw-r--r--spec/unit/plugins/cloud_spec.rb31
5 files changed, 296 insertions, 1 deletions
diff --git a/lib/ohai/mixin/alibaba_metadata.rb b/lib/ohai/mixin/alibaba_metadata.rb
new file mode 100644
index 00000000..983dfd91
--- /dev/null
+++ b/lib/ohai/mixin/alibaba_metadata.rb
@@ -0,0 +1,86 @@
+# frozen_string_literal: true
+#
+# Author:: Tim Smith (<tsmith@chef.io>)
+# Copyright:: Copyright (c) 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" unless defined?(Net::HTTP)
+
+module Ohai
+ module Mixin
+ #
+ # This code parses the Alibaba Instance Metadata API to provide details
+ # of the running instance.
+ #
+ # Note: As of 2021-02-07 there is only one API release so we're not implementing
+ # logic like the ec2 or azure mixins where we have to find the latest supported
+ # release
+ module AlibabaMetadata
+
+ ALI_METADATA_ADDR ||= "100.100.100.200"
+
+ def http_get(uri)
+ conn = Net::HTTP.start(ALI_METADATA_ADDR)
+ conn.read_timeout = 6
+ conn.keep_alive_timeout = 6
+ conn.get("/2016-01-01/#{uri}", { "User-Agent" => "chef-ohai/#{Ohai::VERSION}" })
+ end
+
+ def fetch_metadata(id = "")
+ response = http_get(id)
+ return nil unless response.code == "200"
+
+ if json?(response.body)
+ data = String(response.body)
+ parser = FFI_Yajl::Parser.new
+ parser.parse(data)
+ elsif response.body.include?("\n")
+ temp = {}
+ response.body.split("\n").each do |sub_attr|
+ temp[sanitize_key(sub_attr)] = fetch_metadata("#{id}/#{sub_attr}")
+ end
+ temp
+ else
+ response.body
+ end
+ end
+
+ # @param [String] data that might be JSON
+ #
+ # @return [Boolean] is the data JSON or not?
+ def json?(data)
+ data = String(data)
+ parser = FFI_Yajl::Parser.new
+ begin
+ parser.parse(data)
+ true
+ rescue FFI_Yajl::ParseError
+ false
+ end
+ end
+
+ # @param data [String]
+ #
+ # @return [Boolean] is there a trailing /?
+ def has_trailing_slash?(data)
+ !!( data =~ %r{/$} )
+ end
+
+ def sanitize_key(key)
+ key.gsub(%r{\-|/}, "_")
+ end
+ end
+ end
+end
diff --git a/lib/ohai/plugins/alibaba.rb b/lib/ohai/plugins/alibaba.rb
new file mode 100644
index 00000000..ac3c8088
--- /dev/null
+++ b/lib/ohai/plugins/alibaba.rb
@@ -0,0 +1,72 @@
+# frozen_string_literal: true
+#
+# Author:: Tim Smith (<tsmith@chef.io>)
+# Copyright:: Copyright (c) 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.
+
+# How we detect Alibaba from easiest to hardest & least reliable
+# 1. Ohai alibaba hint exists. This always works
+# 2. DMI sys_vendor data mentions alibaba.
+
+Ohai.plugin(:Alibaba) do
+ require_relative "../mixin/alibaba_metadata"
+ require_relative "../mixin/http_helper"
+
+ include Ohai::Mixin::AlibabaMetadata
+ include Ohai::Mixin::HttpHelper
+
+ provides "alibaba"
+
+ # look for alibaba string in dmi sys_vendor data within the sys tree.
+ # this works even if the system lacks dmidecode use by the Dmi plugin
+ # @return [Boolean] do we have Alibaba DMI data?
+ def has_ali_dmi?
+ if /Alibaba/.match?(file_val_if_exists("/sys/class/dmi/id/sys_vendor"))
+ logger.trace("Plugin Alibaba: has_ali_dmi? == true")
+ true
+ else
+ logger.trace("Plugin Alibaba: has_ali_dmi? == false")
+ false
+ end
+ end
+
+ # return the contents of a file if the file exists
+ # @param path[String] abs path to the file
+ # @return [String] contents of the file if it exists
+ def file_val_if_exists(path)
+ if file_exist?(path)
+ file_read(path)
+ end
+ end
+
+ # a single check that combines all the various detection methods for Alibaba
+ # @return [Boolean] Does the system appear to be on Alibaba
+ def looks_like_alibaba?
+ return true if hint?("alibaba") || has_ali_dmi?
+ end
+
+ collect_data do
+ if looks_like_alibaba?
+ logger.trace("Plugin Alibaba: looks_like_alibaba? == true")
+ alibaba Mash.new
+ fetch_metadata.each do |k, v|
+ alibaba[k] = v
+ end
+ else
+ logger.trace("Plugin Alibaba: looks_like_alibaba? == false")
+ false
+ end
+ end
+end
diff --git a/lib/ohai/plugins/cloud.rb b/lib/ohai/plugins/cloud.rb
index 14e1e454..be7a8405 100644
--- a/lib/ohai/plugins/cloud.rb
+++ b/lib/ohai/plugins/cloud.rb
@@ -18,6 +18,7 @@
Ohai.plugin(:Cloud) do
provides "cloud"
+ depends "alibaba"
depends "ec2"
depends "gce"
depends "rackspace"
@@ -118,7 +119,22 @@ Ohai.plugin(:Cloud) do
end
end
- #---------------------------------------
+ #--------------------------------------
+ # Alibaba Cloud
+ #--------------------------------------
+
+ def on_alibaba?
+ alibaba != nil
+ end
+
+ def get_alibaba_values
+ @cloud_attr_obj.add_ipv4_addr(alibaba["meta_data"]["eipv4"], :public)
+ @cloud_attr_obj.add_ipv4_addr(alibaba["meta_data"]["private_ipv4"], :private)
+ @cloud_attr_obj.local_hostname = alibaba["meta_data"]["hostname"]
+ @cloud_attr_obj.provider = "alibaba"
+ end
+
+ #--------------------------------------
# Google Compute Engine (gce)
#--------------------------------------
@@ -334,6 +350,7 @@ Ohai.plugin(:Cloud) do
get_azure_values if on_azure?
get_digital_ocean_values if on_digital_ocean?
get_softlayer_values if on_softlayer?
+ get_alibaba_values if on_alibaba?
cloud @cloud_attr_obj.cloud_mash
end
diff --git a/spec/unit/plugins/alibaba_spec.rb b/spec/unit/plugins/alibaba_spec.rb
new file mode 100644
index 00000000..c77e9899
--- /dev/null
+++ b/spec/unit/plugins/alibaba_spec.rb
@@ -0,0 +1,89 @@
+#
+# Author:: Ranjib Dey (dey.ranjib@gmail.com)
+# Author:: Tim Smith (tsmith@chef.io)
+# 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 CONDIT"Net::HTTP Response"NS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require "spec_helper"
+require "open-uri"
+
+describe Ohai::System, "plugin alibaba" do
+ let(:plugin) { get_plugin("alibaba") }
+
+ before do
+ allow(plugin).to receive(:hint?).with("alibaba").and_return(false)
+ allow(plugin).to receive(:file_exist?).with("/sys/class/dmi/id/sys_vendor").and_return(false)
+ end
+
+ shared_examples_for "!alibaba" do
+ it "does NOT attempt to fetch the alibaba metadata" do
+ expect(plugin).not_to receive(:http_get)
+ plugin.run
+ end
+
+ it "does NOT set alibaba attributes" do
+ expect(plugin[:alibaba]).to be_nil
+ plugin.run
+ end
+ end
+
+ shared_examples_for "alibaba" do
+ before do
+ @http_get = double("Net::HTTP client")
+ allow(plugin).to receive(:http_get).with("").and_return(double("Net::HTTP Response", body: "meta-data\n", code: "200"))
+ allow(plugin).to receive(:http_get).with("/meta-data").and_return(double("Net::HTTP Response", body: "hostname\n", code: "200"))
+ allow(plugin).to receive(:http_get).with("/meta-data/hostname").and_return(double("Net::HTTP Response", body: "foo", code: "200"))
+ allow(IO).to receive(:select).and_return([[], [1], []])
+ t = double("connection")
+ allow(t).to receive(:connect_nonblock).and_raise(Errno::EINPROGRESS)
+ allow(Socket).to receive(:new).and_return(t)
+ allow(Socket).to receive(:pack_sockaddr_in).and_return(nil)
+ end
+
+ it "recursively fetches and properly parses json metadata" do
+ plugin.run
+
+ expect(plugin[:alibaba]).not_to be_nil
+ expect(plugin[:alibaba]["meta_data"]).to eq("hostname" => "foo")
+ end
+
+ end
+
+ describe "with hint file and with metadata connection" do
+ before do
+ allow(plugin).to receive(:hint?).with("alibaba").and_return({})
+ end
+
+ it_behaves_like "alibaba"
+ end
+
+ describe "with alibaba dmi sys_vendor data" do
+ before do
+ allow(plugin).to receive(:file_exist?).with("/sys/class/dmi/id/sys_vendor").and_return(true)
+ allow(plugin).to receive(:file_read).with("/sys/class/dmi/id/sys_vendor").and_return("Alibaba Cloud\n")
+ end
+
+ it_behaves_like "alibaba"
+ end
+
+ describe "without hint file and non-alibaba dmi sys_vendor data" do
+ before do
+ allow(plugin).to receive(:file_exist?).with("/sys/class/dmi/id/sys_vendor").and_return(true)
+ allow(plugin).to receive(:file_read).with("/sys/class/dmi/id/sys_vendor").and_return("TimCloud\n")
+ end
+
+ it_behaves_like "!alibaba"
+ end
+end
diff --git a/spec/unit/plugins/cloud_spec.rb b/spec/unit/plugins/cloud_spec.rb
index f71a7dd3..95d210e0 100644
--- a/spec/unit/plugins/cloud_spec.rb
+++ b/spec/unit/plugins/cloud_spec.rb
@@ -78,6 +78,7 @@ describe Ohai::System, "plugin cloud" do
describe "with no cloud mashes" do
it "doesn't populate the cloud data" do
+ @plugin[:alibaba] = nil
@plugin[:ec2] = nil
@plugin[:rackspace] = nil
@plugin[:eucalyptus] = nil
@@ -91,6 +92,36 @@ describe Ohai::System, "plugin cloud" do
end
end
+ describe "with Alibaba mash" do
+ before do
+ @plugin[:alibaba] = Mash.new
+ @plugin[:alibaba]["meta_data"] = Mash.new
+ end
+
+ it "populates hostname" do
+ @plugin[:alibaba]["meta_data"]["hostname"] = "foo"
+ @plugin.run
+ expect(@plugin[:cloud][:local_hostname]).to eq("foo")
+ end
+
+ it "populates cloud public ip" do
+ @plugin[:alibaba]["meta_data"]["eipv4"] = "174.129.150.8"
+ @plugin.run
+ expect(@plugin[:cloud][:public_ipv4_addrs][0]).to eq("174.129.150.8")
+ end
+
+ it "populates cloud private ip" do
+ @plugin[:alibaba]["meta_data"]["private_ipv4"] = "10.252.42.149"
+ @plugin.run
+ expect(@plugin[:cloud][:local_ipv4_addrs][0]).to eq("10.252.42.149")
+ end
+
+ it "populates cloud provider" do
+ @plugin.run
+ expect(@plugin[:cloud][:provider]).to eq("alibaba")
+ end
+ end
+
describe "with EC2 mash" do
before do
@plugin[:ec2] = Mash.new