class Chef::Knife::Core::WinBootstrapContext

Instances of BootstrapContext are the context objects (i.e., self) for bootstrap templates. For backwards compatability, they must set the following instance variables:

Constants

PathHelper

Attributes

client_pem[RW]

Public Class Methods

new(config, run_list, chef_config, secret=nil) click to toggle source
Calls superclass method
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 39
def initialize(config, run_list, chef_config, secret=nil)
  @config       = config
  @run_list     = run_list
  @chef_config  = chef_config
  @secret       = secret
  # Compatibility with Chef 12 and Chef 11 versions
  begin
    # Pass along the secret parameter for Chef 12
    super(config, run_list, chef_config, secret)
  rescue ArgumentError
    # The Chef 11 base class only has parameters for initialize
    super(config, run_list, chef_config)
  end
end

Public Instance Methods

bootstrap_context() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 232
def bootstrap_context
  @bootstrap_context ||= Knife::Core::WinBootstrapContext.new(@config, @config[:run_list], Chef::Config)
end
bootstrap_directory() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 319
def bootstrap_directory
  bootstrap_directory = "C:\\chef"
end
chef_version_in_url() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 176
def chef_version_in_url
  installer_version_string = nil
  if @config[:bootstrap_version]
    installer_version_string = "&v=#{@config[:bootstrap_version]}"
  elsif @config[:prerelease]
    installer_version_string = "&prerelease=true"
  else
    chef_version_string = if knife_config[:bootstrap_version]
      knife_config[:bootstrap_version]
    else
      Chef::VERSION.split(".").first
    end

    installer_version_string = "&v=#{chef_version_string}"

    # If bootstrapping a pre-release version add the prerelease query string
    if chef_version_string.split(".").length > 3
      installer_version_string << "&prerelease=true"
    end
  end

  installer_version_string
end
config_content() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 74
        def config_content
          client_rb = <<-CONFIG
chef_server_url  "#{@chef_config[:chef_server_url]}"
validation_client_name "#{@chef_config[:validation_client_name]}"
file_cache_path   "c:/chef/cache"
file_backup_path  "c:/chef/backup"
cache_options     ({:path => "c:/chef/cache/checksums", :skip_expires => true})
          CONFIG
          if @config[:chef_node_name]
            client_rb << %Q{node_name "#{@config[:chef_node_name]}"\n}
          else
            client_rb << "# Using default node name (fqdn)\n"
          end

          if @chef_config[:config_log_level]
            client_rb << %Q{log_level :#{@chef_config[:config_log_level]}\n}
          else
            client_rb << "log_level        :info\n"
          end

          client_rb << "log_location       #{get_log_location}"

          # We configure :verify_api_cert only when it's overridden on the CLI
          # or when specified in the knife config.
          if !@config[:node_verify_api_cert].nil? || knife_config.has_key?(:verify_api_cert)
            value = @config[:node_verify_api_cert].nil? ? knife_config[:verify_api_cert] : @config[:node_verify_api_cert]
            client_rb << %Q{verify_api_cert #{value}\n}
          end

          # We configure :ssl_verify_mode only when it's overridden on the CLI
          # or when specified in the knife config.
          if @config[:node_ssl_verify_mode] || knife_config.has_key?(:ssl_verify_mode)
            value = case @config[:node_ssl_verify_mode]
            when "peer"
              :verify_peer
            when "none"
              :verify_none
            when nil
              knife_config[:ssl_verify_mode]
            else
              nil
            end

            if value
              client_rb << %Q{ssl_verify_mode :#{value}\n}
            end
          end

          if @config[:ssl_verify_mode]
            client_rb << %Q{ssl_verify_mode :#{knife_config[:ssl_verify_mode]}\n}
          end

          if knife_config[:bootstrap_proxy]
            client_rb << "\n"
            client_rb << %Q{http_proxy        "#{knife_config[:bootstrap_proxy]}"\n}
            client_rb << %Q{https_proxy       "#{knife_config[:bootstrap_proxy]}"\n}
            client_rb << %Q{no_proxy          "#{knife_config[:bootstrap_no_proxy]}"\n} if knife_config[:bootstrap_no_proxy]
          end

          if knife_config[:bootstrap_no_proxy]
            client_rb << %Q{no_proxy       "#{knife_config[:bootstrap_no_proxy]}"\n}
          end

          if @config[:secret]
            client_rb << %Q{encrypted_data_bag_secret "c:/chef/encrypted_data_bag_secret"\n}
          end

          unless trusted_certs_script.empty?
            client_rb << %Q{trusted_certs_dir "c:/chef/trusted_certs"\n}
          end

          if Chef::Config[:fips]
            client_rb << <<-CONFIG
fips true
chef_version = ::Chef::VERSION.split(".")
unless chef_version[0].to_i > 12 || (chef_version[0].to_i == 12 && chef_version[1].to_i >= 8)
  raise "FIPS Mode requested but not supported by this client"
end
CONFIG
          end

          escape_and_echo(client_rb)
        end
data_to_byte_chunks(data, max_chuck_size) click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 281
      def data_to_byte_chunks(data, max_chuck_size)
        chunk = ''
        chunk_buffer = ''
        data_to_byte_chunks = []
        data.split('').each { |char|
          chunk_buffer << char.ord.to_s << ','
          if (chunk_buffer.length) >= max_chuck_size
            data_to_byte_chunks.push(chunk_buffer.chomp(','))
chunk_buffer = ''
          end
        }
        data_to_byte_chunks.push(chunk_buffer.chomp(','))
        data_to_byte_chunks
      end
escape_and_echo(file_contents) click to toggle source

escape WIN BATCH special chars and prefixes each line with an echo

# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 334
def escape_and_echo(file_contents)
  file_contents.gsub(/^(.*)$/, 'echo.\1').gsub(/([(<|>)^])/, '^\1').gsub(/(!)/, '^^\1').gsub(/(%)/,'%\1')
end
first_boot() click to toggle source
Calls superclass method
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 327
def first_boot
  escape_and_echo(super.to_json)
end
get_log_location() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 158
def get_log_location
  if @chef_config[:config_log_location].equal?(:win_evt)
    %Q{:#{@chef_config[:config_log_location]}\n}
  elsif @chef_config[:config_log_location].equal?(:syslog)
    raise "syslog is not supported for log_location on Windows OS\n"
  elsif (@chef_config[:config_log_location].equal?(STDOUT))
    "STDOUT\n"
  elsif (@chef_config[:config_log_location].equal?(STDERR))
    "STDERR\n"
  elsif @chef_config[:config_log_location].nil? || @chef_config[:config_log_location].empty?
    "STDOUT\n"
  elsif @chef_config[:config_log_location]
    %Q{"#{@chef_config[:config_log_location]}"\n}
  else
    "STDOUT\n"
  end
end
local_download_path() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 323
def local_download_path
  local_download_path = "%TEMP%\\chef-client-latest.msi"
end
secret() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 62
def secret
  if @config[:secret].nil?
    nil
  else
    escape_and_echo(@config[:secret])
  end
end
trusted_certs_script() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 70
def trusted_certs_script
  @trusted_certs_script ||= trusted_certs_content
end
validation_key() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 54
def validation_key
  if File.exist?(File.expand_path(@chef_config[:validation_key]))
    IO.read(File.expand_path(@chef_config[:validation_key]))
  else
    false
  end
end
win_cmd_tail(target_filename) click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 226
def win_cmd_tail(target_filename)
  cmd_tail_file = Gem.find_files(File.join('chef', 'knife', 'winops_bootstrap', 'tail.cmd')).first
  cmd_tail_content = IO.read(cmd_tail_file)
  win_parse_file_content(cmd_tail_content, target_filename)
end
win_cmd_wait_for_file(filename_in_envvar) click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 212
        def win_cmd_wait_for_file(filename_in_envvar)
          win_cmd_wait_for_file = <<-filename_in_envvar
:waitfor#{filename_in_envvar}
@if NOT EXIST "%#{filename_in_envvar}%" (
    @powershell.exe -command Start-Sleep 1
        @echo %#{filename_in_envvar}% does not exist yet.
    @goto waitfor#{filename_in_envvar}
) else (
    @echo Logfile %#{filename_in_envvar}% found.
)
filename_in_envvar
          win_cmd_wait_for_file
        end
win_folder_cp(folder_src,folder_dest, folder_src_original = nil) click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 248
def win_folder_cp(folder_src,folder_dest, folder_src_original = nil)
  win_folder_cp = ''
  Dir.foreach(folder_src) do |item|
    next if item == '.' or item == '..'
    folder_src_original = folder_src_original ? folder_src_original : folder_src
    if File.file?(File.join(folder_src,item))
      filename_target = File.join(folder_src,item).gsub(folder_src_original, folder_dest).gsub("/","\\")
      win_folder_cp << win_parse_file_content(IO.read(File.join(folder_src,item)).force_encoding('binary'), filename_target)
    else
      folder = File.join(folder_src,item).gsub(folder_src_original, folder_dest).gsub("/","\\")
      win_folder_cp << "mkdir #{folder}\n"
      win_folder_cp << win_folder_cp(File.join(folder_src,item), folder_dest, folder_src_original)
    end
  end
  win_folder_cp
end
win_parse_file_content(content, target_filename) click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 265
def win_parse_file_content(content, target_filename)
              byte_chunks = data_to_byte_chunks(content, 2000)
              win_parse_file_content = ''
              win_parse_file_content << "del \"#{target_filename}\" /Q 2> nul\n"
              byte_chunks.each { |file_chunk|
                       if file_chunk.length > 0
                      win_parse_file_content << write_file_chunk(file_chunk, target_filename)
                    end
              }
              win_parse_file_content
            end
win_ps_bootstrap(target_filename) click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 236
def win_ps_bootstrap(target_filename)
  ps_bootstrap_file = Gem.find_files(File.join('chef', 'knife', 'winops_bootstrap', 'bootstrap.ps1')).first
  ps_bootstrap_content = IO.read(ps_bootstrap_file)
  win_parse_file_content(ps_bootstrap_content, target_filename)
end
win_ps_exitcheck() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 297
        def win_ps_exitcheck
          <<-ps_exitcheck
@powershell.exe -command Start-Sleep 1
@echo off
REM Wait for the file to exist
:wff
if NOT EXIST "%CHEF_PS_EXITCODE%" (
  goto wff
)
if EXIST %CHEF_PS_EXITCODE% (
  setlocal disabledelayedexpansion
  for /f "tokens=1* delims=]" %%A in ('type "%CHEF_PS_EXITCODE%"^|find /v /n ""') do (
    set psexitcode=%%B
    setlocal enabledelayedexpansion
  )
) else (
  echo %CHEF_PS_EXITCODE% not found. This should never happen
  exit 328
)
ps_exitcheck
        end
win_ps_write_filechunk() click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 200
        def win_ps_write_filechunk
          win_ps_write_filechunk = <<-PS_WRITEFILECHUNK
$data=$args[0]
$filename=$args[1]
$bytes = @()
if (Test-Path $filename) { $bytes = [System.IO.File]::ReadAllBytes($filename) }
$bytes += $args[0]
[io.file]::WriteAllBytes($filename,$bytes)
PS_WRITEFILECHUNK
                  escape_and_echo(win_ps_write_filechunk)
                end
win_schedtask_xml(target_filename) click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 242
def win_schedtask_xml(target_filename)
  sched_xml_file = Gem.find_files(File.join('chef', 'knife', 'winops_bootstrap', 'Chef_bootstrap.erb')).first
  sched_xml_file_content = IO.read(sched_xml_file).chomp
  win_parse_file_content(Erubis::Eruby.new(sched_xml_file_content).evaluate(bootstrap_context), target_filename)
end
write_file_chunk(byte_chunk, target_filename) click to toggle source
# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 277
def write_file_chunk(byte_chunk, target_filename)
  "@powershell.exe -command #{bootstrap_directory}\\writefile.ps1 #{byte_chunk} #{target_filename}\n"
end

Private Instance Methods

trusted_certs_content() click to toggle source

Returns a string for copying the trusted certificates on the workstation to the system being bootstrapped This string should contain both the commands necessary to both create the files, as well as their content

# File lib/chef/knife/winops_core/windows_bootstrap_context.rb, line 342
def trusted_certs_content
  content = ""
  if @chef_config[:trusted_certs_dir]
    Dir.glob(File.join(PathHelper.escape_glob_dir(@chef_config[:trusted_certs_dir]), "*.{crt,pem}")).each do |cert|
      content << "> #{bootstrap_directory}/trusted_certs/#{File.basename(cert)} (\n" +
                 escape_and_echo(IO.read(File.expand_path(cert))) + "\n)\n"
    end
  end
  content
end