Skip to content

Commit

Permalink
(QA-2514) PE-client-tools helpers (#15)
Browse files Browse the repository at this point in the history
* (QA-2514) PE-client-tools helpers

* (maint) Add install helpers for pe-client-tools

This commit adds three helper methods to install pe-client-tools on Windows.

The first is a general  method that is designed to abstract
away the installation of pe-client-tools on supported operating systems.
Currently, it only accommodates development builds of the tools based on the
provided SHA and SUITE_VERSION environment variables available.

The second is a generic method to install an msi package on a target host.
Beaker's built in method of this name assumes that msi installed involves the
installation of puppet, so this method overrides that one without such an
assumption.

The this is a generic method to install a dmg package on a target host.
Beaker's built in `install_package` method for osx does not accommodate for an
installer `pkg` file that is named differently from the containing `dmg`. This
method forces the user to supply both names explicitly.

* (maint) Remove install helpers for pe-client-tools

This commit removes the dmg and msi helper methods instroduced earlier.

These two methods have bee moved into beaker.

* basic spec tests for ExecutableHelper & ConfigFileHelper
  • Loading branch information
zreichert authored and kevpl committed Aug 2, 2016
1 parent 949852c commit 32d70ef
Show file tree
Hide file tree
Showing 7 changed files with 476 additions and 0 deletions.
6 changes: 6 additions & 0 deletions lib/beaker-pe.rb
Expand Up @@ -2,12 +2,18 @@
require 'beaker-pe/version'
require 'beaker-pe/install/pe_utils'
require 'beaker-pe/options/pe_version_scraper'
require 'beaker-pe/pe-client-tools/config_file_helper'
require 'beaker-pe/pe-client-tools/install_helper'
require 'beaker-pe/pe-client-tools/executable_helper'

module Beaker
module DSL
module PE
include Beaker::DSL::InstallUtils::PEUtils
include Beaker::DSL::InstallUtils::PEClientTools
include Beaker::Options::PEVersionScraper
include Beaker::DSL::PEClientTools::ConfigFileHelper
include Beaker::DSL::PEClientTools::ExecutableHelper
end
end
end
Expand Down
93 changes: 93 additions & 0 deletions lib/beaker-pe/pe-client-tools/config_file_helper.rb
@@ -0,0 +1,93 @@
require "beaker/dsl/patterns"

module Beaker
module DSL
module PEClientTools
module ConfigFileHelper

# Helper method to write config files for pe-client-tools
# @param [Beaker::Host] host The beaker host that gets the config file
# @param [String] config_level 'user' or 'global'
# @param [String] tool 'access', 'code', 'db', 'query', 'orchestrator', 'job', 'app'
# @param [String] contents The contents of the config file
def write_client_tool_config_on(host, config_level, tool, contents)

# TODO take a hash and parse file or take literal string

file = "#{Private.config_path(host, config_level)}/#{Private.file_name(tool)}"
create_remote_file(host, file, contents)
end


class Private

require 'beaker/dsl/patterns'

extend Beaker::DSL
extend Beaker::DSL::Patterns

def self.file_name(tool)
if tool =~ /orchestrator|job|app/i
'puppet-orchestrator.conf'
elsif tool =~ /code/i
'puppet-code.conf'
elsif tool =~ /access/i
'puppet-access.conf'
elsif tool =~ /db|query/i
'puppetdb.conf'
else
raise ArgumentError.new("Unknown pe-client-tool type '#{tool}'")
end
end

def self.config_path(host, config_level)

puppetlabs_dir = 'puppetlabs'
puppetlabs_dir.prepend('.') if config_level == 'user'
client_tools_path_array = [puppetlabs_dir, 'client-tools']

case config_level

when /global/
@base_path = global_base_path(host)
when /user/
@base_path = home_dir(host)
else
raise ArgumentError.new("Unknown config level #{config_level}")
end

client_tools_dir = client_tools_path_array.unshift(@base_path).join(path_separator(host))
opts = {:cmdexe => true}

if host.platform =~ /win/
host.exec(Beaker::Command.new('MD', [client_tools_dir.gsub('\\', '\\\\\\')], opts), :accept_all_exit_codes => true)
else
host.exec(Beaker::Command.new("mkdir -p #{client_tools_dir}", [], opts), :accept_all_exit_codes => true)
end
client_tools_dir
end

def self.home_dir(host)

if (host.platform =~ /win/) then
@cmd = Beaker::Command.new('echo', ['%userprofile%'], :cmdexe => true)
else
@cmd = Beaker::Command.new('echo', ['$HOME'])
end
host.exec(@cmd).stdout.chomp
end

def self.global_base_path(host)

(host.platform =~ /win/) ?host.exec(Beaker::Command.new('echo', ['%PROGRAMDATA%'], :cmdexe => true)).stdout.chomp : '/etc//'
end

def self.path_separator(host)

(host.platform =~ /win/) ? '\\' : '/'
end
end
end
end
end
end
157 changes: 157 additions & 0 deletions lib/beaker-pe/pe-client-tools/executable_helper.rb
@@ -0,0 +1,157 @@
require "beaker/dsl/patterns"
require "beaker/dsl/helpers"
require "beaker/dsl/wrappers"

module Beaker
module DSL
module PEClientTools
module ExecutableHelper

# puppet-access helper win/lin/osx
# @param [BEAKER::Host] host The SUT that should run the puppet-access command
# @param [String] args The arguments to puppet-access
# @param [Hash] opts options hash to the Beaker Command
# @param [Block] &block optional block
def puppet_access_on(*args, &block)
Private.new.tool(:access, *args, &block)
end

# puppet-code helper win/lin/osx
# @param [BEAKER::Host] host The SUT that should run the puppet-code command
# @param [String] args The arguments to puppet-code
# @param [Hash] opts options hash to the Beaker Command
# @param [Block] &block optional block
def puppet_code_on(*args, &block)
Private.new.tool(:code, *args, &block)
end

# puppet-job helper win/lin/osx
# @param [BEAKER::Host] host The SUT that should run the puppet-job command
# @param [String] args The arguments to puppet-job
# @param [Hash] opts options hash to the Beaker Command
# @param [Block] &block optional block
def puppet_job_on(*args, &block)
Private.new.tool(:job, *args, &block)
end

# puppet-app helper win/lin/osx
# @param [BEAKER::Host] host The SUT that should run the puppet-app command
# @param [String] args The arguments to puppet-app
# @param [Hash] opts options hash to the Beaker Command
# @param [Block] &block optional block
def puppet_app_on(*args, &block)
Private.new.tool(:app, *args, &block)
end

# puppet-db helper win/lin/osx
# @param [BEAKER::Host] host The SUT that should run the puppet-db command
# @param [String] args The arguments to puppet-db
# @param [Hash] opts options hash to the Beaker Command
# @param [Block] &block optional block
def puppet_db_on(*args, &block)
Private.new.tool(:db, *args, &block)
end

# puppet-query helper win/lin/osx
# @param [BEAKER::Host] host The SUT that should run the puppet-query command
# @param [String] args The arguments to puppet-query
# @param [Hash] opts options hash to the Beaker Command
# @param [Block] &block optional block
def puppet_query_on(*args, &block)
Private.new.tool(:query, *args, &block)
end

# Logs a user in on a SUT with puppet-access/RBAC API (windows)
# @param [Beaker::Host] host The SUT to perform the login on
# @param [Scooter::HttpDispatchers::ConsoleDispatcher] credentialed_dispatcher A Scooter dispatcher that has credentials for the user
# @option attribute_hash [String] :name The environment variable
# @option attribute_hash [String] :default The default value for the environment variable
# @option attribute_hash [String] :message A message describing the use of this variable
# @option attribute_hash [Boolean] :required Used internally by CommandFlag, ignored for a standalone EnvVar
def login_with_puppet_access_on(host, credentialed_dispatcher, opts={})

lifetime = opts[:lifetime] || nil
unless host.platform =~ /win/

user = credentialed_dispatcher.credentials.login
password = credentialed_dispatcher.credentials.password
puppet_access_on(host, 'login', {:stdin => "#{user}\n#{password}\n"})
else

# this is a hack
# puppet-access needs to support alternative to interactive login
# create .puppetlabs dir
cmd = Beaker::Command.new('echo', ['%userprofile%'], :cmdexe => true)
user_home_dir = host.exec(cmd).stdout.chomp
win_token_path = "#{user_home_dir}\\.puppetlabs\\"
host.exec(Beaker::Command.new('MD', [win_token_path.gsub('\\', '\\\\\\')], :cmdexe => true), :accept_all_exit_codes => true)

token = credentialed_dispatcher.acquire_token_with_credentials(lifetime)
create_remote_file(host, "#{win_token_path}\\token", token)
end
end

class Private

include Beaker::DSL
include Beaker::DSL::Wrappers
include Beaker::DSL::Helpers::HostHelpers
include Beaker::DSL::Patterns

attr_accessor :logger

def tool(tool, *args, &block)

host = args.shift
@logger = host.logger
options = {}
options.merge!(args.pop) if args.last.is_a?(Hash)

if host.platform =~ /win/i

program_files = host.exec(Beaker::Command.new('echo', ['%PROGRAMFILES%'], :cmdexe => true)).stdout.chomp
client_tools_dir = "#{program_files}\\#{['Puppet Labs', 'Client', 'tools', 'bin'].join('\\')}\\"
tool_executable = "\"#{client_tools_dir}puppet-#{tool.to_s}.exe\""

#TODO does this need to be more detailed to pass exit codes????
# TODO make batch file direct output to separate file
batch_contents =<<-EOS
call #{tool_executable} #{args.join(' ')}
EOS

@command = build_win_batch_command( host, batch_contents, {:cmdexe => true})
else

tool_executable = '/opt/puppetlabs/client-tools/bin/' << "puppet-#{tool.to_s}"
@command = Beaker::Command.new(tool_executable, args, {:cmdexe => true})
end

result = host.exec(@command, options)

# Also, let additional checking be performed by the caller.
if block_given?
case block.arity
#block with arity of 0, just hand back yourself
when 0
yield self
#block with arity of 1 or greater, hand back the result object
else
yield result
end
end
result
end

def build_win_batch_command( host, batch_contents, command_options)
timestamp = Time.new.strftime('%Y-%m-%d_%H.%M.%S')
# Create Temp file
# make file fully qualified
batch_file = "#{host.system_temp_path}\\#{timestamp}.bat"
create_remote_file(host, batch_file, batch_contents)
Beaker::Command.new("\"#{batch_file}\"", [], command_options)
end
end
end
end
end
end
74 changes: 74 additions & 0 deletions lib/beaker-pe/pe-client-tools/install_helper.rb
@@ -0,0 +1,74 @@
module Beaker
module DSL
module InstallUtils
module PEClientTools

def install_pe_client_tools_on(hosts, opts = {})
# FIXME: accomodate production released location(s)
#{{{
product = 'pe-client-tools'
required_keys = [:puppet_collection, :pe_client_tools_sha, :pe_client_tools_version]

unless required_keys.all? { |opt| opts.keys.include?(opt) }
raise ArgumentError, "The keys #{required_keys.to_s} are required in the opts hash"
end
urls = { :dev_builds_url => "http://builds.delivery.puppetlabs.net",
}

opts = urls.merge(opts)

block_on hosts do |host|
package_name = nil
variant, version, arch, codename = host['platform'].to_array
case host['platform']
when /el-|fedora|sles|centos|cisco_/
release_path = "#{opts[:dev_builds_url]}/#{product}/#{ opts[:pe_client_tools_sha] }/artifacts/#{variant}/#{version}/#{opts[:puppet_collection]}/#{arch}"
package_name = product.dup
package_name << "-#{opts[:pe_client_tools_version]}-1.#{variant}#{version}.#{arch}.rpm" if opts[:pe_client_tools_version]
when /debian|ubuntu|cumulus|huaweios/
release_path = "#{opts[:dev_builds_url]}/#{product}/#{ opts[:pe_client_tools_sha] }/artifacts/deb/#{codename}/#{opts[:puppet_collection]}"
package_name = product.dup
package_name << "_#{opts[:pe_client_tools_version]}-1#{host['platform'].codename}_#{arch}.deb" if opts[:pe_client_tools_version]
when /windows/
release_path = "#{opts[:dev_builds_url]}/#{product}/#{ opts[:pe_client_tools_sha] }/artifacts/#{variant}/#{opts[:puppet_collection]}/x#{arch}"
package_name = product.dup
package_name << "-#{opts[:pe_client_tools_version]}.1-x#{arch}_VANAGON.msi" if opts[:pe_client_tools_version]
when /osx/
release_path = "#{opts[:dev_builds_url]}/#{product}/#{ opts[:pe_client_tools_sha] }/artifacts/apple/#{version}/#{opts[:puppet_collection]}/#{arch}"
package_base = product.dup
package_base << "-#{opts[:pe_client_tools_version]}" if opts[:pe_client_tools_version]
package_name = package_base.dup
package_name << '-1' if opts[:pe_client_tools_version]
installer = package_name + '-installer.pkg'
package_name << ".#{variant}#{version}.dmg" if opts[:pe_client_tools_version]
else
raise "install_puppet_agent_on() called for unsupported " +
"platform '#{host['platform']}' on '#{host.name}'"
end

if package_name
case host['platform']
when /windows/
generic_install_msi_on(host, File.join(release_path, package_name), {}, {:debug => true})
else
copy_dir_local = File.join('tmp', 'repo_configs')
fetch_http_file(release_path, package_name, copy_dir_local)
scp_to host, File.join(copy_dir_local, package_name), host.external_copy_base

if host['platform'] =~ /debian|ubuntu|cumulus|huaweios/
on host, "dpkg -i #{package_name}"
elsif host['platform'] =~ /osx/
host.generic_install_dmg(package_name, package_base, installer)
else
host.install_package( package_name )
end
end
end
end
#}}}
end

end
end
end
end
13 changes: 13 additions & 0 deletions spec/beaker-pe/pe-client-tools/config_file_helper_spec.rb
@@ -0,0 +1,13 @@
require 'spec_helper'
require 'beaker'

class MixedWithConfigFileHelper
include Beaker::DSL::PEClientTools::ConfigFileHelper
end

describe MixedWithConfigFileHelper do

it 'has a method to write a config file' do
expect(subject.respond_to?('write_client_tool_config_on')).not_to be(false)
end
end

0 comments on commit 32d70ef

Please sign in to comment.