Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalize command execution environment #1395

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
3 changes: 1 addition & 2 deletions e2e/drone.sh
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,7 @@ timeout 600 ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=30 -i "${ssh_
echo "Waiting for node to come online.."
(retry 30 node_online "${worker_hostname}") || exit $?
echo "Node is online:"
kubectl get nodes "${worker_hostname}" -o wide
HTTP_PROXY=http://10.133.37.157:8888 HTTPS_PROXY=http://10.133.37.157:8888 http_proxy=http://10.133.37.157:8888 https_proxy=http://10.133.37.157:8888 NO_PROXY=localhost,0,1,2,3,4,5,6,7,8,9 kubectl get nodes "${worker_hostname}" -o wide

echo "Testing a worker reset.."
timeout 700 pharos reset -y -c e2e/digitalocean/cluster.yml --tf-json e2e/digitalocean/tf.json --role worker --first

3 changes: 2 additions & 1 deletion e2e/travis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ bundle exec bin/pharos
bundle exec bin/pharos -v
bundle exec bin/pharos version
bundle exec bin/pharos up -y -c cluster.yml
bundle exec bin/pharos ssh --role master -c cluster.yml -- kubectl get nodes
bundle exec bin/pharos ssh --role master -c cluster.yml -- env
bundle exec bin/pharos ssh --role master -c cluster.yml -- NO_PROXY=localhost,0,1,2,3,4,5,6,7,8,9 kubectl get nodes
bundle exec bin/pharos kubeconfig -c cluster.yml > kubeconfig.e2e

# Verify that workloads start running
Expand Down
3 changes: 0 additions & 3 deletions lib/pharos/phases/configure_host.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ def call
unless @host.environment.nil? || @host.environment.empty?
logger.info "Updating environment file ..."
host_configurer.update_env_file
logger.info "Reconnecting ..."
@host.transport.disconnect
@host.transport.connect
end

logger.info "Configuring script helpers ..."
Expand Down
6 changes: 6 additions & 0 deletions lib/pharos/phases/gather_facts.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ class GatherFacts < Pharos::Phase
FULL_HOSTNAME_CLOUD_PROVIDERS = %w(aws vsphere).freeze

def call
logger.debug "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
logger.debug transport.exec!('sudo env')
logger.debug "-----------------------------------"
logger.debug transport.exec!('echo $(sudo env)')
logger.debug ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"

logger.info { "Checking sudo access ..." }
check_sudo
logger.info { "Gathering host facts ..." }
Expand Down
5 changes: 3 additions & 2 deletions lib/pharos/transport.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ module Pharos
module Transport
def self.for(host, **options)
if host.local?
Local.new('localhost', **options)
Local.new(host, **options)
else
opts = {}
opts[:keys] = [host.ssh_key_path] if host.ssh_key_path
Expand All @@ -19,7 +19,8 @@ def self.for(host, **options)
opts[:keepalive_interval] = 30
opts[:keepalive_maxcount] = 5
opts[:timeout] = 5
SSH.new(host.address, user: host.user, **opts.merge(options))
opts[:user] = host.user
SSH.new(host, **opts.merge(options))
end
end
end
Expand Down
23 changes: 3 additions & 20 deletions lib/pharos/transport/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,11 @@
module Pharos
module Transport
class Base
EXPORT_ENVS = {
http_proxy: '$http_proxy',
https_proxy: '$https_proxy',
no_proxy: '$no_proxy',
HTTP_PROXY: '$HTTP_PROXY',
HTTPS_PROXY: '$HTTPS_PROXY',
NO_PROXY: '$NO_PROXY',
FTP_PROXY: '$FTP_PROXY',
PATH: '$PATH'
}.freeze

include MonitorMixin

attr_reader :host

# @param host [String]
# @param host [Pharos::Configuration::Host]
# @param opts [Hash]
def initialize(host, **opts)
super()
Expand Down Expand Up @@ -68,18 +57,12 @@ def exec!(cmd, **options)
end

# @param name [String] name of script
# @param env [Hash] environment variables hash
# @param path [String] real path to file, defaults to script
# @raise [Pharos::ExecError]
# @return [String] stdout
def exec_script!(name, env: {}, path: nil, **options)
def exec_script!(name, path: nil, **options)
script = ::File.read(path || name)
cmd = %w(sudo env -i -)

cmd.concat(EXPORT_ENVS.merge(env).map { |key, value| "#{key}=\"#{value}\"" })
cmd.concat(%w(bash --norc --noprofile -x -s))
logger.debug { "exec: #{cmd}" }
exec!(cmd, stdin: script, source: name, **options)
exec!(nil, stdin: script, source: name, **options)
end

# @param cmd [String] command to execute
Expand Down
38 changes: 34 additions & 4 deletions lib/pharos/transport/command/local.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,33 @@ module Pharos
module Transport
module Command
class Local
attr_reader :cmd, :result
attr_reader :cmd, :result, :env

# @param client [Pharos::Transport::Local] client instance
# @param cmd [String,Array<String>] command to execute
# @param env [Hash] environment variables hash
# @param stdin [String,IO] attach string or stream to command STDIN
# @param source [String]
def initialize(client, cmd, stdin: nil, source: nil)
def initialize(client, cmd, stdin: nil, source: nil, env: {})
@client = client
@cmd = "env bash --noprofile --norc -x -c #{(cmd.is_a?(Array) ? cmd.join(' ') : cmd).shellescape}"
@stdin = stdin.respond_to?(:read) ? stdin.read : stdin
@source = source
@stdin = stdin.respond_to?(:read) ? stdin.read : stdin
@env = export_envs.merge(@client.host.environment&.transform_keys(&:to_s) || {}).merge(env.transform_keys(&:to_s))

cmd = cmd.join(' ') if cmd.is_a?(Array)

cmd_parts = ['env', '-i', *envs_array, 'bash', '--norc', '--noprofile', '-x']

if cmd.nil?
cmd_parts.insert(0, 'sudo')
else
cmd_parts.concat(['-c', "sudo() { $(which sudo) -E \"$@\"; }; export -f sudo; #{cmd}".shellescape])
end

cmd_parts << '-s' unless stdin.nil?

@cmd = cmd_parts.join(' ')

@result = Pharos::Transport::Command::Result.new(hostname)
freeze
end
Expand Down Expand Up @@ -68,6 +84,20 @@ def run
end
result
end

private

# @return [Hash]
def export_envs
%w(PATH HOME KUBECONFIG USER).map do |key|
[key, "\"$#{key}\""]
end.to_h
end

# @return [Array<String>]
def envs_array
env.map { |k, v| "#{k}=\"#{v}\"" }
end
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/pharos/transport/ssh.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def class_mutex
Net::SSH::Authentication::ED25519::OpenSSHPrivateKeyLoader::DecryptError
].freeze

# @param host [String]
# @param host [Pharos::Configuration::Host]
# @param opts [Hash]
def initialize(host, **opts)
super(host, opts)
Expand All @@ -41,7 +41,7 @@ def connect(**options)
logger.debug { "connect: #{@user}@#{@host} (#{@opts})" }
non_interactive = true
begin
@session = session_factory.start(@host, @user, @opts.merge(options).merge(non_interactive: non_interactive))
@session = session_factory.start(@host.address, @user, @opts.merge(options).merge(non_interactive: non_interactive))
logger.debug "Connected"
class_mutex.unlock if class_mutex.locked? && class_mutex.owned?
rescue *RETRY_CONNECTION_ERRORS => exc
Expand Down