summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLamont Granquist <lamont@scriptkiddie.org>2020-01-31 13:54:10 -0800
committerLamont Granquist <lamont@scriptkiddie.org>2020-01-31 13:54:10 -0800
commit9ce4eb455526074cc88f398a8397e5d2a62443fa (patch)
tree2e4b38b643411065340068b2b6b8d34f69f46719
parent3023717497cb5540190c1977d578599437325330 (diff)
downloadchef-9ce4eb455526074cc88f398a8397e5d2a62443fa.tar.gz
Add chef-sugar virtualization helpers
Signed-off-by: Lamont Granquist <lamont@scriptkiddie.org>
-rw-r--r--chef-utils/README.md12
-rw-r--r--chef-utils/lib/chef-utils.rb4
-rw-r--r--chef-utils/lib/chef-utils/dsl/virtualization.rb159
-rw-r--r--chef-utils/spec/spec_helper.rb8
-rw-r--r--chef-utils/spec/unit/dsl/virtualization_spec.rb68
-rw-r--r--lib/chef/node/attribute.rb4
-rw-r--r--lib/chef/node/common_api.rb4
7 files changed, 253 insertions, 6 deletions
diff --git a/chef-utils/README.md b/chef-utils/README.md
index 8116f84c5e..ce62afa64a 100644
--- a/chef-utils/README.md
+++ b/chef-utils/README.md
@@ -133,6 +133,18 @@ 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
+* `lxc?` - if the node is an lxc guest
+* `parallels?`- if the node is a parallels guest
+* `vbox?` - if the node is a virtualbox guest
+* `vmware?` - if the node is a vmware guest
+* `openvz?` - if the node is an openvz guest
+* `virtual?` - if any of the above are true (guest of any detected virtualization system)
+* `physical?` - strictly the logical opposite of `virtual?`
+* `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 d52c866de5..39c74d3f68 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
@@ -38,6 +39,7 @@ module ChefUtils
include ChefUtils::DSL::Platform
include ChefUtils::DSL::PlatformFamily
include ChefUtils::DSL::TrainHelpers
+ include ChefUtils::DSL::Virtualization
include ChefUtils::DSL::Which
include ChefUtils::DSL::Windows
# ChefUtils::DSL::Service is deliberately excluded
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..eb324bd946
--- /dev/null
+++ b/chef-utils/lib/chef-utils/dsl/virtualization.rb
@@ -0,0 +1,159 @@
+#
+# 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 running under KVM.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def kvm?(node = __getnode)
+ node.dig("virtualization", "system") == "kvm"
+ 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"
+ 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"
+ end
+
+ # Determine if the current node is running under VirtualBox.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def vbox?(node = __getnode)
+ node.dig("virtualization", "system") == "vbox"
+ end
+
+ alias_method :virtualbox?, :vbox?
+
+ #
+ # Determine if the current node is running under VMware.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def vmware?(node = __getnode)
+ node.dig("virtualization", "system") == "vmware"
+ end
+
+ # Determine if the current node is running under openvz.
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def openvz?(node = __getnode)
+ node.dig("virtualization", "system") == "openvz"
+ end
+
+ # Determine if the current node is running under any virutalization environment
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def virtual?(node = __getnode)
+ openvz?(node) || vmware?(node) || virtualbox?(node) || parallels?(node) || lxc?(node) || kvm?(node)
+ end
+
+ # Determine if the current node is NOT running under any virutalization environment
+ #
+ # @param [Chef::Node] node
+ #
+ # @return [Boolean]
+ #
+ def physical?(node = __getnode)
+ !virtual?(node)
+ end
+
+ # Determine if the current node is running in vagrant mode.
+ #
+ # 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..52b3eb65d1
--- /dev/null
+++ b/chef-utils/spec/unit/dsl/virtualization_spec.rb
@@ -0,0 +1,68 @@
+#
+# 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(:virtual?, :kvm?, node: { "virtualization" => { "system" => "kvm" } })
+ end
+ context "on lxc" do
+ virtualization_reports_true_for(:virtual?, :lxc?, node: { "virtualization" => { "system" => "lxc" } })
+ end
+ context "on parallels" do
+ virtualization_reports_true_for(:virtual?, :parallels?, node: { "virtualization" => { "system" => "parallels" } })
+ end
+ context "on virtualbox" do
+ virtualization_reports_true_for(:virtual?, :virtualbox?, :vbox?, node: { "virtualization" => { "system" => "vbox" } })
+ end
+ context "on vmware" do
+ virtualization_reports_true_for(:virtual?, :vmware?, node: { "virtualization" => { "system" => "vmware" } })
+ end
+ context "on openvz" do
+ virtualization_reports_true_for(:virtual?, :openvz?, node: { "virtualization" => { "system" => "openvz" } })
+ end
+ context "on anything else" 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)