Class: ChefApply::TargetHost
- Inherits:
-
Object
- Object
- ChefApply::TargetHost
- Defined in:
- lib/chef_apply/target_host.rb
Defined Under Namespace
Classes: ChefNotInstalled, ConnectionFailure, RemoteExecutionFailed, UnsupportedTargetOS
Constant Summary collapse
- SSH_CONFIG_OVERRIDE_KEYS =
These values may exist in .ssh/config but will be ignored by train in favor of its defaults unless we specify them explicitly. See #apply_ssh_config
[:user, :port, :proxy].freeze
- MANIFEST_PATHS =
{ # TODO - use a proper method to query the win installation path - # currently we're assuming the default, but this can be customized # at install time. # A working approach is below - but it runs very slowly in testing # on a virtualbox windows vm: # (over winrm) Get-WmiObject Win32_Product | Where {$_.Name -match 'Chef Client'} windows: "c:\\opscode\\chef\\version-manifest.json", linux: "/opt/chef/version-manifest.json", }.freeze
- MKTMP_WIN_CMD =
"$parent = [System.IO.Path]::GetTempPath();" + "[string] $name = [System.Guid]::NewGuid();" + "$tmp = New-Item -ItemType Directory -Path " + "(Join-Path $parent $name);" + "$tmp.FullName"
- MKTMP_LINUX_CMD =
"d=$(mktemp -d -p${TMPDIR:-/tmp} chef_XXXXXX); echo $d".freeze
Instance Attribute Summary collapse
-
#backend ⇒ Object
readonly
Returns the value of attribute backend.
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#reporter ⇒ Object
readonly
Returns the value of attribute reporter.
-
#transport_type ⇒ Object
readonly
Returns the value of attribute transport_type.
Class Method Summary collapse
Instance Method Summary collapse
- #apply_ssh_config(config, opts_in) ⇒ Object
- #architecture ⇒ Object
- #base_os ⇒ Object
-
#chown(path, owner = nil) ⇒ Object
Simplified chown - just sets user , defaults to connection user.
- #connect! ⇒ Object
- #connection_config(host_url, opts_in, logger) ⇒ Object
- #get_chef_version_manifest ⇒ Object
- #hostname ⇒ Object
-
#initialize(host_url, opts = {}, logger = nil) ⇒ TargetHost
constructor
A new instance of TargetHost.
-
#installed_chef_version ⇒ Object
Returns the installed chef version as a Gem::Version, or raised ChefNotInstalled if chef client version manifest can’t be found.
-
#mkdir(path) ⇒ Object
create a dir.
-
#mktemp ⇒ Object
Create temporary dir and return the path.
- #platform ⇒ Object
- #run_command(command) ⇒ Object
- #run_command!(command) ⇒ Object
- #upload_file(local_path, remote_path) ⇒ Object
-
#user ⇒ Object
Returns the user being used to connect.
- #version ⇒ Object
Constructor Details
#initialize(host_url, opts = {}, logger = nil) ⇒ TargetHost
Returns a new instance of TargetHost.
36 37 38 39 40 41 |
# File 'lib/chef_apply/target_host.rb', line 36 def initialize(host_url, opts = {}, logger = nil) @config = connection_config(host_url, opts, logger) @transport_type = Train.validate_backend(@config) apply_ssh_config(@config, opts) if @transport_type == "ssh" @train_connection = Train.create(@transport_type, config) end |
Instance Attribute Details
#backend ⇒ Object (readonly)
Returns the value of attribute backend.
23 24 25 |
# File 'lib/chef_apply/target_host.rb', line 23 def backend @backend end |
#config ⇒ Object (readonly)
Returns the value of attribute config.
23 24 25 |
# File 'lib/chef_apply/target_host.rb', line 23 def config @config end |
#reporter ⇒ Object (readonly)
Returns the value of attribute reporter.
23 24 25 |
# File 'lib/chef_apply/target_host.rb', line 23 def reporter @reporter end |
#transport_type ⇒ Object (readonly)
Returns the value of attribute transport_type.
23 24 25 |
# File 'lib/chef_apply/target_host.rb', line 23 def transport_type @transport_type end |
Class Method Details
.instance_for_url(target, opts = {}) ⇒ Object
29 30 31 32 33 34 |
# File 'lib/chef_apply/target_host.rb', line 29 def self.instance_for_url(target, opts = {}) opts = { target: @url } target_host = new(target, opts) target_host.connect! target_host end |
Instance Method Details
#apply_ssh_config(config, opts_in) ⇒ Object
67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/chef_apply/target_host.rb', line 67 def apply_ssh_config(config, opts_in) # If we don't provide certain options, they will be defaulted # within train - in the case of ssh, this will prevent the .ssh/config # values from being picked up. # Here we'll modify the returned @config to specify # values that we get out of .ssh/config if present and if they haven't # been explicitly given. host_cfg = ssh_config_for_host(config[:host]) SSH_CONFIG_OVERRIDE_KEYS.each do |key| if host_cfg.key?(key) && opts_in[key].nil? config[key] = host_cfg[key] end end end |
#architecture ⇒ Object
106 107 108 |
# File 'lib/chef_apply/target_host.rb', line 106 def architecture platform.arch end |
#base_os ⇒ Object
114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/chef_apply/target_host.rb', line 114 def base_os if platform.family == "windows" :windows elsif platform.linux? :linux else # TODO - this seems like it shouldn't happen here, when # all the caller is doing is asking about the OS raise ChefApply::TargetHost::UnsupportedTargetOS.new(platform.name) end end |
#chown(path, owner = nil) ⇒ Object
Simplified chown - just sets user , defaults to connection user. Does not touch group. Only has effect on non-windows targets
198 199 200 201 202 |
# File 'lib/chef_apply/target_host.rb', line 198 def chown(path, owner = nil) return if base_os == :windows owner ||= user run_command!("chown #{owner} '#{path}'") end |
#connect! ⇒ Object
82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/chef_apply/target_host.rb', line 82 def connect! return unless @backend.nil? @backend = train_connection.connection @backend.wait_until_ready rescue Train::UserError => e raise ConnectionFailure.new(e, config) rescue Train::Error => e # These are typically wrapper errors for other problems, # so we'll prefer to use e.cause over e if available. raise ConnectionFailure.new(e.cause || e, config) end |
#connection_config(host_url, opts_in, logger) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/chef_apply/target_host.rb', line 43 def connection_config(host_url, opts_in, logger) connection_opts = { target: host_url, sudo: opts_in[:sudo] === false ? false : true, www_form_encoded_password: true, key_files: opts_in[:identity_file], non_interactive: true, # Prevent long delays due to retries on auth failure. # This does reduce the number of attempts we'll make for transient conditions as well, but # train does not currently exposes these as separate controls. Ideally I'd like to see a 'retry_on_auth_failure' option. connection_retries: 2, connection_retry_sleep: 0.15, logger: ChefApply::Log } if opts_in.key? :ssl connection_opts[:ssl] = opts_in[:ssl] connection_opts[:self_signed] = (opts_in[:ssl_verify] === false ? true : false) end [:sudo_password, :sudo, :sudo_command, :password, :user].each do |key| connection_opts[key] = opts_in[key] if opts_in.key? key end Train.target_config(connection_opts) end |
#get_chef_version_manifest ⇒ Object
172 173 174 175 176 177 |
# File 'lib/chef_apply/target_host.rb', line 172 def get_chef_version_manifest path = MANIFEST_PATHS[base_os()] manifest = backend.file(path) return :not_found unless manifest.file? JSON.parse(manifest.content) end |
#hostname ⇒ Object
102 103 104 |
# File 'lib/chef_apply/target_host.rb', line 102 def hostname config[:host] end |
#installed_chef_version ⇒ Object
Returns the installed chef version as a Gem::Version, or raised ChefNotInstalled if chef client version manifest can’t be found.
149 150 151 152 153 154 155 156 157 158 159 |
# File 'lib/chef_apply/target_host.rb', line 149 def installed_chef_version return @installed_chef_version if @installed_chef_version # Note: In the case of a very old version of chef (that has no manifest - pre 12.0?) # this will report as not installed. manifest = get_chef_version_manifest() raise ChefNotInstalled.new if manifest == :not_found # We'll split the version here because unstable builds (where we currently # install from) are in the form "Major.Minor.Build+HASH" which is not a valid # version string. @installed_chef_version = Gem::Version.new(manifest["build_version"].split("+")[0]) end |
#mkdir(path) ⇒ Object
create a dir. set owner to the connecting user if host isn’t windows so that scp – which uses the connecting user – can upload into it.
181 182 183 184 185 186 187 188 189 190 191 192 |
# File 'lib/chef_apply/target_host.rb', line 181 def mkdir(path) if base_os == :windows run_command!("New-Item -ItemType Directory -Force -Path #{path}") else # This will also set ownership to the connecting user instead of default of # root when sudo'd, so that the dir can be used to upload files using scp - # which is done as the connecting user. run_command!("mkdir -p #{path}") chown(path, user) end nil end |
#mktemp ⇒ Object
Create temporary dir and return the path. This will also set ownership to the connecting user instead of default of root when sudo’d, so that the dir can be used to upload files using scp - which is done as the connecting user.
216 217 218 219 220 221 222 223 224 225 226 227 |
# File 'lib/chef_apply/target_host.rb', line 216 def mktemp if base_os == :windows res = run_command!(MKTMP_WIN_CMD) res.stdout.chomp.strip else # # TODO should we keep chmod 777? res = run_command!("bash -c '#{MKTMP_LINUX_CMD}'") path = res.stdout.chomp.strip chown(path) path end end |
#platform ⇒ Object
126 127 128 |
# File 'lib/chef_apply/target_host.rb', line 126 def platform backend.platform end |
#run_command(command) ⇒ Object
138 139 140 |
# File 'lib/chef_apply/target_host.rb', line 138 def run_command(command) backend.run_command command end |
#run_command!(command) ⇒ Object
130 131 132 133 134 135 136 |
# File 'lib/chef_apply/target_host.rb', line 130 def run_command!(command) result = run_command(command) if result.exit_status != 0 raise RemoteExecutionFailed.new(@config[:host], command, result) end result end |
#upload_file(local_path, remote_path) ⇒ Object
142 143 144 |
# File 'lib/chef_apply/target_host.rb', line 142 def upload_file(local_path, remote_path) backend.upload(local_path, remote_path) end |
#user ⇒ Object
Returns the user being used to connect. Defaults to train’s default user if not specified defaulted in .ssh/config (for ssh connections), as set up in ‘#apply_ssh_config’.
96 97 98 99 100 |
# File 'lib/chef_apply/target_host.rb', line 96 def user return config[:user] unless config[:user].nil? require "train/transports/ssh" Train::Transports::SSH.[:user][:default] end |
#version ⇒ Object
110 111 112 |
# File 'lib/chef_apply/target_host.rb', line 110 def version platform.release end |