1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
#
# Author:: Adam Jacob (<adam@chef.io>)
# Copyright:: Copyright 2008-2018, 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/log"
require "chef/provider"
require "forwardable"
class Chef
class Provider
class Execute < Chef::Provider
extend Forwardable
provides :execute
def_delegators :new_resource, :command, :returns, :environment, :user, :domain, :password, :group, :cwd, :umask, :creates, :elevated, :internal
def load_current_resource
current_resource = Chef::Resource::Execute.new(new_resource.name)
current_resource
end
def define_resource_requirements
if creates && creates_relative? && !cwd
# FIXME? move this onto the resource?
raise Chef::Exceptions::Execute, "Please either specify a full path for the creates attribute, or specify a cwd property to the #{new_resource} resource"
end
end
def timeout
# original implementation did not specify a timeout, but ShellOut
# *always* times out. So, set a very long default timeout
new_resource.timeout || 3600
end
def action_run
if creates && sentinel_file.exist?
logger.debug("#{new_resource} sentinel file #{sentinel_file} exists - nothing to do")
return false
end
converge_by("execute #{description}") do
begin
shell_out!(command, opts)
rescue Mixlib::ShellOut::ShellCommandFailed
if sensitive?
ex = Mixlib::ShellOut::ShellCommandFailed.new("Command execution failed. STDOUT/STDERR suppressed for sensitive resource")
# Forcibly hide the exception cause chain here so we don't log the unredacted version
def ex.cause
nil
end
raise ex
else
raise
end
end
logger.info("#{new_resource} ran successfully")
end
end
private
def sensitive?
!!new_resource.sensitive
end
def live_stream?
Chef::Config[:stream_execute_output] || !!new_resource.live_stream
end
def stream_to_stdout?
STDOUT.tty? && !Chef::Config[:daemon]
end
def opts
opts = {}
opts[:timeout] = timeout
opts[:returns] = returns if returns
opts[:environment] = environment if environment
opts[:user] = user if user
opts[:domain] = domain if domain
opts[:password] = password if password
opts[:group] = group if group
opts[:cwd] = cwd if cwd
opts[:umask] = umask if umask
opts[:internal] = internal
opts[:log_level] = :info
opts[:log_tag] = new_resource.to_s
if (logger.info? || live_stream?) && !sensitive?
if run_context.events.formatter?
opts[:live_stream] = Chef::EventDispatch::EventsOutputStream.new(run_context.events, :name => :execute)
elsif stream_to_stdout?
opts[:live_stream] = STDOUT
end
end
opts[:elevated] = elevated if elevated
opts
end
def description
sensitive? ? "sensitive resource" : command
end
def creates_relative?
Pathname(creates).relative?
end
def sentinel_file
Pathname.new(Chef::Util::PathHelper.cleanpath(
( cwd && creates_relative? ) ? ::File.join(cwd, creates) : creates
))
end
end
end
end
|