File Manager
Viewing File: version.rb
#
# Author:: Seth Chisamore (<schisamo@chef.io>)
# Copyright:: Copyright 2011-2016, 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 "chef/win32/api"
require "chef/win32/api/system"
require "wmi-lite/wmi"
class Chef
module ReservedNames::Win32
class Version
class << self
include Chef::ReservedNames::Win32::API::System
end
include Chef::ReservedNames::Win32::API::Macros
include Chef::ReservedNames::Win32::API::System
# Ruby implementation of
# http://msdn.microsoft.com/en-us/library/ms724833(v=vs.85).aspx
# http://msdn.microsoft.com/en-us/library/ms724358(v=vs.85).aspx
def self.get_system_metrics(n_index)
GetSystemMetrics(n_index)
end
private_class_method :get_system_metrics
def self.method_name_from_marketing_name(marketing_name)
"#{marketing_name.gsub(/\s/, '_').tr('.', '_').downcase}?"
# "#{marketing_name.gsub(/\s/, '_').gsub(//, '_').downcase}?"
end
private_class_method :method_name_from_marketing_name
WIN_VERSIONS = {
"Windows 10" => { :major => 10, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
"Windows Server 2016" => { :major => 10, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
"Windows 8.1" => { :major => 6, :minor => 3, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
"Windows Server 2012 R2" => { :major => 6, :minor => 3, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
"Windows 8" => { :major => 6, :minor => 2, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
"Windows Server 2012" => { :major => 6, :minor => 2, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
"Windows 7" => { :major => 6, :minor => 1, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
"Windows Server 2008 R2" => { :major => 6, :minor => 1, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
"Windows Server 2008" => { :major => 6, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type != VER_NT_WORKSTATION } },
"Windows Vista" => { :major => 6, :minor => 0, :callable => lambda { |product_type, suite_mask| product_type == VER_NT_WORKSTATION } },
"Windows Server 2003 R2" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| get_system_metrics(SM_SERVERR2) != 0 } },
"Windows Home Server" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| (suite_mask & VER_SUITE_WH_SERVER) == VER_SUITE_WH_SERVER } },
"Windows Server 2003" => { :major => 5, :minor => 2, :callable => lambda { |product_type, suite_mask| get_system_metrics(SM_SERVERR2) == 0 } },
"Windows XP" => { :major => 5, :minor => 1 },
"Windows 2000" => { :major => 5, :minor => 0 },
}
def initialize
@major_version, @minor_version, @build_number = get_version
ver_info = get_version_ex
@product_type = ver_info[:w_product_type]
@suite_mask = ver_info[:w_suite_mask]
@sp_major_version = ver_info[:w_service_pack_major]
@sp_minor_version = ver_info[:w_service_pack_minor]
# Obtain sku information for the purpose of identifying
# datacenter, cluster, and core skus, the latter 2 only
# exist in releases after Windows Server 2003
if ! Chef::Platform.windows_server_2003?
@sku = get_product_info(@major_version, @minor_version, @sp_major_version, @sp_minor_version)
else
# The get_product_info API is not supported on Win2k3,
# use an alternative to identify datacenter skus
@sku = get_datacenter_product_info_windows_server_2003(ver_info)
end
end
marketing_names = Array.new
# General Windows checks
WIN_VERSIONS.each do |k, v|
method_name = method_name_from_marketing_name(k)
define_method(method_name) do
(@major_version == v[:major]) &&
(@minor_version == v[:minor]) &&
(v[:callable] ? v[:callable].call(@product_type, @suite_mask) : true)
end
marketing_names << [k, method_name]
end
define_method(:marketing_name) do
marketing_names.each do |mn|
break mn[0] if send(mn[1])
end
end
# Server Type checks
%w{ cluster core datacenter }.each do |m|
define_method("#{m}?") do
self.class.constants.any? do |c|
(self.class.const_get(c) == @sku) &&
(c.to_s =~ /#{m}/i )
end
end
end
private
def get_version
# Use WMI here because API's like GetVersion return faked
# version numbers on Windows Server 2012 R2 and Windows 8.1 --
# WMI always returns the truth. See article at
# http://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
wmi = WmiLite::Wmi.new
os_info = wmi.first_of("Win32_OperatingSystem")
os_version = os_info["version"]
# The operating system version is a string in the following form
# that can be split into components based on the '.' delimiter:
# MajorVersionNumber.MinorVersionNumber.BuildNumber
os_version.split(".").collect { |version_string| version_string.to_i }
end
def get_version_ex
lp_version_info = OSVERSIONINFOEX.new
lp_version_info[:dw_os_version_info_size] = OSVERSIONINFOEX.size
unless GetVersionExW(lp_version_info)
Chef::ReservedNames::Win32::Error.raise!
end
lp_version_info
end
def get_product_info(major, minor, sp_major, sp_minor)
out = FFI::MemoryPointer.new(:uint32)
GetProductInfo(major, minor, sp_major, sp_minor, out)
out.get_uint(0)
end
def get_datacenter_product_info_windows_server_2003(ver_info)
# The intent is not to get the actual sku, just identify
# Windows Server 2003 datacenter
sku = (ver_info[:w_suite_mask] & VER_SUITE_DATACENTER) ? PRODUCT_DATACENTER_SERVER : 0
end
end
end
end