summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@chef.io>2020-02-03 18:06:21 -0800
committerGitHub <noreply@github.com>2020-02-03 18:06:21 -0800
commit32cd08b01f9ecc79dde32d9f80e9c19704e57f3f (patch)
tree7e7685195ea3a9f5e32d51657cf1f433c6af0d8d
parente93af6a4cf5787a34a5c765ebd2e4029ca9a3633 (diff)
parente4dd7951d90abb7fd50c34930c02cb65d25d9568 (diff)
downloadchef-32cd08b01f9ecc79dde32d9f80e9c19704e57f3f.tar.gz
Merge pull request #9316 from chef/lcg/chef-sugar-virtualization-backport
Add chef-sugar virtualization helpers (Chef 15 backport)
-rw-r--r--chef-utils/README.md19
-rw-r--r--chef-utils/lib/chef-utils.rb4
-rw-r--r--chef-utils/lib/chef-utils/dsl/virtualization.rb231
-rw-r--r--chef-utils/spec/spec_helper.rb8
-rw-r--r--chef-utils/spec/unit/dsl/virtualization_spec.rb74
-rw-r--r--lib/chef/node/attribute.rb4
-rw-r--r--lib/chef/node/common_api.rb4
7 files changed, 338 insertions, 6 deletions
diff --git a/chef-utils/README.md b/chef-utils/README.md
index dbffe378a8..452f585e82 100644
--- a/chef-utils/README.md
+++ b/chef-utils/README.md
@@ -133,6 +133,25 @@ Architecture Helpers allow you to determine the processor architecture of your n
* `digital_ocean?` - if the node is running in digital ocean
* `softlayer?` - if the node is running in softlayer
+### Virtualization Helpers
+
+* `kvm?` - if the node is a kvm guest
+* `kvm_host?` - if the node is a kvm host
+* `lxc?` - if the node is an lxc guest
+* `lxc_host?` - if the node is an lxc host
+* `parallels?`- if the node is a parallels guest
+* `parallels_host?`- if the node is a parallels host
+* `vbox?` - if the node is a virtualbox guest
+* `vbox_host?` - if the node is a virtualbox host
+* `vmware?` - if the node is a vmware guest
+* `vmware_host?` - if the node is a vmware host
+* `openvz?` - if the node is an openvz guest
+* `openvz_host?` - if the node is an openvz host
+* `guest?` - if the node is detected as any kind of guest
+* `hypervisor?` - if the node is detected as being any kind of hypervisor
+* `physical?` - the node is not running as a guest (may be a hypervisor or may be plain metal)
+* `vagrant?` - attempts to identify the node as a vagrant guest (this check may be error prone)
+
### Train Helpers
**EXPERIMENTAL**: APIs may have breaking changes any time without warning
diff --git a/chef-utils/lib/chef-utils.rb b/chef-utils/lib/chef-utils.rb
index 596737892c..1fe6b7af59 100644
--- a/chef-utils/lib/chef-utils.rb
+++ b/chef-utils/lib/chef-utils.rb
@@ -24,11 +24,12 @@ require_relative "chef-utils/dsl/platform"
require_relative "chef-utils/dsl/platform_family"
require_relative "chef-utils/dsl/service"
require_relative "chef-utils/dsl/train_helpers"
+require_relative "chef-utils/dsl/virtualization"
require_relative "chef-utils/dsl/which"
require_relative "chef-utils/dsl/windows"
require_relative "chef-utils/mash"
-# This is the Chef Infra Client DSL, not everytihng needs to go in here
+# This is the Chef Infra Client DSL, not everything needs to go in here
module ChefUtils
include ChefUtils::DSL::Architecture
include ChefUtils::DSL::Cloud
@@ -36,6 +37,7 @@ module ChefUtils
include ChefUtils::DSL::OS
include ChefUtils::DSL::Platform
include ChefUtils::DSL::PlatformFamily
+ include ChefUtils::DSL::Virtualization
include ChefUtils::DSL::Windows
# FIXME: include ChefUtils::DSL::Which in Chef 16.0
# FIXME: include ChefUtils::DSL::PathSanity in Chef 16.0
diff --git a/chef-utils/lib/chef-utils/dsl/virtualization.rb b/chef-utils/lib/chef-utils/dsl/virtualization.rb
new file mode 100644
index 0000000000..df3a1ac3eb
--- /dev/null
+++ b/chef-utils/lib/chef-utils/dsl/virtualization.rb
@@ -0,0 +1,231 @@
+#
+# Copyright:: Copyright 2018-2020, 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_relative "../internal"
+
+module ChefUtils
+ module DSL
+ module Virtualization
+ include Internal
+
+ # Determine if the current node is a KVM guest.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def kvm?(node = __getnode)
+ node.dig("virtualization", "system") == "kvm" && node.dig("virtualization", "role") == "guest"
+ end
+
+ # Determine if the current node is a KVM host.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def kvm_host?(node = __getnode)
+ node.dig("virtualization", "system") == "kvm" && node.dig("virtualization", "role") == "host"
+ end
+
+ # Determine if the current node is running in a linux container.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def lxc?(node = __getnode)
+ node.dig("virtualization", "system") == "lxc" && node.dig("virtualization", "role") == "guest"
+ end
+
+ # Determine if the current node is a linux container host.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def lxc_host?(node = __getnode)
+ node.dig("virtualization", "system") == "lxc" && node.dig("virtualization", "role") == "host"
+ end
+
+ # Determine if the current node is running under Parallels Desktop.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ # true if the machine is currently running under Parallels Desktop, false
+ # otherwise
+ #
+ def parallels?(node = __getnode)
+ node.dig("virtualization", "system") == "parallels" && node.dig("virtualization", "role") == "guest"
+ end
+
+ # Determine if the current node is a Parallels Desktop host.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ # true if the machine is currently running under Parallels Desktop, false
+ # otherwise
+ #
+ def parallels_host?(node = __getnode)
+ node.dig("virtualization", "system") == "parallels" && node.dig("virtualization", "role") == "host"
+ end
+
+ # Determine if the current node is a VirtualBox guest.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def vbox?(node = __getnode)
+ node.dig("virtualization", "system") == "vbox" && node.dig("virtualization", "role") == "guest"
+ end
+
+ # Determine if the current node is a VirtualBox host.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def vbox_host?(node = __getnode)
+ node.dig("virtualization", "system") == "vbox" && node.dig("virtualization", "role") == "host"
+ end
+
+ alias_method :virtualbox?, :vbox?
+
+ # Determine if the current node is a VMWare guest.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def vmware?(node = __getnode)
+ node.dig("virtualization", "system") == "vmware" && node.dig("virtualization", "role") == "guest"
+ end
+
+ # Determine if the current node is VMware host.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def vmware_host?(node = __getnode)
+ node.dig("virtualization", "system") == "vmware" && node.dig("virtualization", "role") == "host"
+ end
+
+ # Determine if the current node is an openvz guest.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def openvz?(node = __getnode)
+ node.dig("virtualization", "system") == "openvz" && node.dig("virtualization", "role") == "guest"
+ end
+
+ # Determine if the current node is an openvz host.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def openvz_host?(node = __getnode)
+ node.dig("virtualization", "system") == "openvz" && node.dig("virtualization", "role") == "host"
+ end
+
+ # Determine if the current node is running under any virutalization environment
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def guest?(node = __getnode)
+ node.dig("virtualization", "role") == "guest"
+ end
+
+ alias_method :virtual?, :guest?
+
+ # Determine if the current node supports running guests under any virtualization environment
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def hypervisor?(node = __getnode)
+ node.dig("virtualization", "role") == "host"
+ end
+
+ # Determine if the current node is NOT running under any virtualization environment (plain metal or hypervisor on metal)
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def physical?(node = __getnode)
+ !virtual?(node)
+ end
+
+ # Determine if the current node is running as a vagrant guest.
+ #
+ # Note that this API is equivalent to just looking for the vagrant user or the
+ # vagrantup.com domain in the hostname, which is the best API we have.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ # true if the machine is currently running vagrant, false
+ # otherwise
+ #
+ def vagrant?(node = __getnode)
+ vagrant_key?(node) || vagrant_domain?(node) || vagrant_user?(node)
+ end
+
+ private
+
+ # Check if the +vagrant+ key exists on the +node+ object. This key is no
+ # longer populated by vagrant, but it is kept around for legacy purposes.
+ #
+ # @param (see vagrant?)
+ # @return (see vagrant?)
+ #
+ def vagrant_key?(node = __getnode)
+ node.key?("vagrant")
+ end
+
+ # Check if "vagrantup.com" is included in the node's domain.
+ #
+ # @param (see vagrant?)
+ # @return (see vagrant?)
+ #
+ def vagrant_domain?(node = __getnode)
+ node.key?("domain") && !node["domain"].nil? && node["domain"].include?("vagrantup.com")
+ end
+
+ # Check if the system contains a +vagrant+ user.
+ #
+ # @param (see vagrant?)
+ # @return (see vagrant?)
+ #
+ def vagrant_user?(node = __getnode)
+ !!(Etc.getpwnam("vagrant") rescue nil)
+ end
+
+ extend self
+ end
+ end
+end
diff --git a/chef-utils/spec/spec_helper.rb b/chef-utils/spec/spec_helper.rb
index 4d9b5518d1..a44377336e 100644
--- a/chef-utils/spec/spec_helper.rb
+++ b/chef-utils/spec/spec_helper.rb
@@ -10,17 +10,19 @@ HELPER_MODULES = [
ChefUtils::DSL::Platform,
ChefUtils::DSL::PlatformFamily,
ChefUtils::DSL::Service,
+ ChefUtils::DSL::Virtualization,
ChefUtils::DSL::Which,
ChefUtils::DSL::Windows,
].freeze
ARCH_HELPERS = (ChefUtils::DSL::Architecture.methods - Module.methods).freeze
+CLOUD_HELPERS = (ChefUtils::DSL::Cloud.methods - Module.methods).freeze
+INTROSPECTION_HELPERS = (ChefUtils::DSL::Introspection.methods - Module.methods).freeze
OS_HELPERS = (ChefUtils::DSL::OS.methods - Module.methods).freeze
-PLATFORM_HELPERS = (ChefUtils::DSL::Platform.methods - Module.methods).freeze
PLATFORM_FAMILY_HELPERS = (ChefUtils::DSL::PlatformFamily.methods - Module.methods).freeze
-INTROSPECTION_HELPERS = (ChefUtils::DSL::Introspection.methods - Module.methods).freeze
+PLATFORM_HELPERS = (ChefUtils::DSL::Platform.methods - Module.methods).freeze
+VIRTUALIZATION_HELPERS = (ChefUtils::DSL::Virtualization.methods - Module.methods).freeze
WINDOWS_HELPERS = (ChefUtils::DSL::Windows.methods - Module.methods).freeze
-CLOUD_HELPERS = (ChefUtils::DSL::Cloud.methods - Module.methods).freeze
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
diff --git a/chef-utils/spec/unit/dsl/virtualization_spec.rb b/chef-utils/spec/unit/dsl/virtualization_spec.rb
new file mode 100644
index 0000000000..84daa9e162
--- /dev/null
+++ b/chef-utils/spec/unit/dsl/virtualization_spec.rb
@@ -0,0 +1,74 @@
+#
+# Copyright:: Copyright 2018-2020, 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 "spec_helper"
+require "fauxhai"
+
+def virtualization_reports_true_for(*args, node:)
+ args.each do |method|
+ it "reports true for #{method}" do
+ expect(described_class.send(method, node)).to be true
+ end
+ end
+ (VIRTUALIZATION_HELPERS - args).each do |method|
+ it "reports false for #{method}" do
+ expect(described_class.send(method, node)).to be false
+ end
+ end
+end
+
+RSpec.describe ChefUtils::DSL::Virtualization do
+ ( HELPER_MODULES - [ described_class ] ).each do |klass|
+ it "does not have methods that collide with #{klass}" do
+ expect((klass.methods - Module.methods) & VIRTUALIZATION_HELPERS).to be_empty
+ end
+ end
+
+ VIRTUALIZATION_HELPERS.each do |helper|
+ it "has the #{helper} in the ChefUtils module" do
+ expect(ChefUtils).to respond_to(helper)
+ end
+ end
+
+ context "on kvm" do
+ virtualization_reports_true_for(:guest?, :virtual?, :kvm?, node: { "virtualization" => { "system" => "kvm", "role" => "guest" } })
+ virtualization_reports_true_for(:hypervisor?, :physical?, :kvm_host?, node: { "virtualization" => { "system" => "kvm", "role" => "host" } })
+ end
+ context "on lxc" do
+ virtualization_reports_true_for(:guest?, :virtual?, :lxc?, node: { "virtualization" => { "system" => "lxc", "role" => "guest" } })
+ virtualization_reports_true_for(:hypervisor?, :physical?, :lxc_host?, node: { "virtualization" => { "system" => "lxc", "role" => "host" } })
+ end
+ context "on parallels" do
+ virtualization_reports_true_for(:guest?, :virtual?, :parallels?, node: { "virtualization" => { "system" => "parallels", "role" => "guest" } })
+ virtualization_reports_true_for(:hypervisor?, :physical?, :parallels_host?, node: { "virtualization" => { "system" => "parallels", "role" => "host" } })
+ end
+ context "on virtualbox" do
+ virtualization_reports_true_for(:guest?, :virtual?, :virtualbox?, :vbox?, node: { "virtualization" => { "system" => "vbox", "role" => "guest" } })
+ virtualization_reports_true_for(:hypervisor?, :physical?, :vbox_host?, node: { "virtualization" => { "system" => "vbox", "role" => "host" } })
+ end
+ context "on vmware" do
+ virtualization_reports_true_for(:guest?, :virtual?, :vmware?, node: { "virtualization" => { "system" => "vmware", "role" => "guest" } })
+ virtualization_reports_true_for(:hypervisor?, :physical?, :vmware_host?, node: { "virtualization" => { "system" => "vmware", "role" => "host" } })
+ end
+ context "on openvz" do
+ virtualization_reports_true_for(:guest?, :virtual?, :openvz?, node: { "virtualization" => { "system" => "openvz", "role" => "guest" } })
+ virtualization_reports_true_for(:hypervisor?, :physical?, :openvz_host?, node: { "virtualization" => { "system" => "openvz", "role" => "host" } })
+ end
+ context "on metal which is not a virt host" do
+ virtualization_reports_true_for(:physical?, node: {} )
+ end
+end
diff --git a/lib/chef/node/attribute.rb b/lib/chef/node/attribute.rb
index d872e53d9b..4ccf04af6a 100644
--- a/lib/chef/node/attribute.rb
+++ b/lib/chef/node/attribute.rb
@@ -1,7 +1,7 @@
#--
# Author:: Adam Jacob (<adam@chef.io>)
# Author:: AJ Christensen (<aj@chef.io>)
-# Copyright:: Copyright 2008-2019, Chef Software Inc.
+# Copyright:: Copyright 2008-2020, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -453,6 +453,8 @@ class Chef
merged_attributes.read(*path)
end
+ alias :dig :read
+
def read!(*path)
merged_attributes.read!(*path)
end
diff --git a/lib/chef/node/common_api.rb b/lib/chef/node/common_api.rb
index 388b2b5e23..829552d80c 100644
--- a/lib/chef/node/common_api.rb
+++ b/lib/chef/node/common_api.rb
@@ -1,5 +1,5 @@
#--
-# Copyright:: Copyright 2016, Chef Software, Inc.
+# Copyright:: Copyright 2016-2020, Chef Software Inc.
# License:: Apache License, Version 2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -98,6 +98,8 @@ class Chef
nil
end
+ alias :dig :read
+
# non-autovivifying reader that throws an exception if the attribute does not exist
def read!(*path)
raise Chef::Exceptions::NoSuchAttribute.new(path.join ".") unless exist?(*path)