puppet-resource_api 0.3.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +23 -22
- data/Rakefile +1 -1
- data/lib/puppet/resource_api.rb +30 -21
- data/lib/puppet/resource_api/glue.rb +1 -1
- data/lib/puppet/resource_api/simple_provider.rb +3 -2
- data/lib/puppet/resource_api/version.rb +1 -1
- data/puppet-resource_api.gemspec +0 -3
- metadata +3 -21
- data/ext/mkrf_conf.rb +0 -20
- data/lib/puppet/resource_api/command.rb +0 -122
- data/lib/puppet/resource_api/errors.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4cd6bb413d555b36210db422b423ae959a154710
|
4
|
+
data.tar.gz: ac01f703016d047a1998749f944248968cdd113c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f02fe222bd17db29fa11724d2ac95262698fa15af2d7147de070d8650fac3d627a2fe4601072db467e538d31d8b502eba47060e7fd2feb64cee3a62c9421f6e1
|
7
|
+
data.tar.gz: 9ab8db6f0a1b140b5264506b25d6fa85910955cfc49d3475b85faf2ab0c50ef86ba216bedc77105c03c7fc981d45f0b6dd55640ed1419ee035a66f873b2b788f
|
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,23 @@
|
|
3
3
|
All significant changes to this repo will be summarized in this file.
|
4
4
|
|
5
5
|
|
6
|
+
## [v0.9.0](https://github.com/puppetlabs/puppet-resource_api/tree/v0.9.0) (2018-02-22)
|
7
|
+
[Full Changelog](https://github.com/puppetlabs/puppet-resource_api/compare/v0.3.0...v0.9.0)
|
8
|
+
|
9
|
+
**Implemented enhancements:**
|
10
|
+
|
11
|
+
- \(PDK-536\) Proper datatype parsing and checking [\#23](https://github.com/puppetlabs/puppet-resource_api/pull/23) ([DavidS](https://github.com/DavidS))
|
12
|
+
|
13
|
+
**Fixed bugs:**
|
14
|
+
|
15
|
+
- SimpleProvider: fix `is`-lookup and docs [\#24](https://github.com/puppetlabs/puppet-resource_api/pull/24) ([DavidS](https://github.com/DavidS))
|
16
|
+
- \(main\) Fixup to\_manifest output [\#20](https://github.com/puppetlabs/puppet-resource_api/pull/20) ([shermdog](https://github.com/shermdog))
|
17
|
+
|
18
|
+
**Merged pull requests:**
|
19
|
+
|
20
|
+
- Add a note on device support to the README [\#26](https://github.com/puppetlabs/puppet-resource_api/pull/26) ([DavidS](https://github.com/DavidS))
|
21
|
+
- Remove Command API [\#25](https://github.com/puppetlabs/puppet-resource_api/pull/25) ([DavidS](https://github.com/DavidS))
|
22
|
+
|
6
23
|
## [v0.3.0](https://github.com/puppetlabs/puppet-resource_api/tree/v0.3.0) (2018-02-21)
|
7
24
|
[Full Changelog](https://github.com/puppetlabs/puppet-resource_api/compare/v0.2.2...v0.3.0)
|
8
25
|
|
@@ -16,6 +33,10 @@ All significant changes to this repo will be summarized in this file.
|
|
16
33
|
|
17
34
|
- \(PDK-569\) `puppet resource` now displays type name correctly [\#18](https://github.com/puppetlabs/puppet-resource_api/pull/18) ([tphoney](https://github.com/tphoney))
|
18
35
|
|
36
|
+
**Merged pull requests:**
|
37
|
+
|
38
|
+
- Release prep v0.3.0 [\#22](https://github.com/puppetlabs/puppet-resource_api/pull/22) ([DavidS](https://github.com/DavidS))
|
39
|
+
|
19
40
|
## [v0.2.2](https://github.com/puppetlabs/puppet-resource_api/tree/v0.2.2) (2018-01-25)
|
20
41
|
[Full Changelog](https://github.com/puppetlabs/puppet-resource_api/compare/v0.2.1...v0.2.2)
|
21
42
|
|
data/README.md
CHANGED
@@ -114,43 +114,38 @@ The provider is the most important part of your new resource, as it reads and en
|
|
114
114
|
|
115
115
|
```ruby
|
116
116
|
require 'puppet/resource_api'
|
117
|
-
require 'puppet/resource_api/command'
|
118
117
|
require 'puppet/resource_api/simple_provider'
|
119
118
|
|
120
119
|
# Implementation for the foo type using the Resource API.
|
121
120
|
class Puppet::Provider::Foo::Foo < Puppet::ResourceApi::SimpleProvider
|
122
|
-
def
|
123
|
-
|
124
|
-
end
|
125
|
-
|
126
|
-
def get(context)
|
127
|
-
# nonsensical resource emulation for this example
|
128
|
-
@echo_cmd.run(context).stdout.split('').each do |c|
|
121
|
+
def get(_context)
|
122
|
+
[
|
129
123
|
{
|
130
|
-
name:
|
124
|
+
name: 'foo',
|
131
125
|
ensure: :present,
|
132
|
-
}
|
133
|
-
|
126
|
+
},
|
127
|
+
{
|
128
|
+
name: 'bar',
|
129
|
+
ensure: :present,
|
130
|
+
},
|
131
|
+
]
|
134
132
|
end
|
135
133
|
|
136
134
|
def create(context, name, should)
|
137
|
-
#
|
138
|
-
@echo_cmd.run(context, "create: #{name}, #{should.inspect}")
|
135
|
+
context.notice("Creating '#{name}' with #{should.inspect}")
|
139
136
|
end
|
140
137
|
|
141
138
|
def update(context, name, should)
|
142
|
-
#
|
143
|
-
@echo_cmd.run(context, "update: #{name}, #{should.inspect}")
|
139
|
+
context.notice("Updating '#{name}' with #{should.inspect}")
|
144
140
|
end
|
145
141
|
|
146
142
|
def delete(context, name)
|
147
|
-
#
|
148
|
-
@echo_cmd.run(context, "delete: #{name}")
|
143
|
+
context.notice("Deleting '#{name}'")
|
149
144
|
end
|
150
145
|
end
|
151
146
|
```
|
152
147
|
|
153
|
-
The optional `initialize` method can be used to set up state that is available throughout the execution of the catalog. This is most often used for
|
148
|
+
The optional `initialize` method can be used to set up state that is available throughout the execution of the catalog. This is most often used for establishing a connection, when talking to a service (e.g. when managing a database).
|
154
149
|
|
155
150
|
The `get(context)` method returns a list of hashes describing the resources that are currently on the target system. The basic example would always return an empty list. Here is an example of resources that could be returned from this:
|
156
151
|
|
@@ -171,7 +166,15 @@ The `create`/`update`/`delete` methods get called by the `SimpleProvider` base-c
|
|
171
166
|
|
172
167
|
### Unit testing
|
173
168
|
|
174
|
-
The generated unit tests in `spec/unit/puppet/provider/foo_spec.rb` get automatically evaluated with `pdk test unit`.
|
169
|
+
The generated unit tests in `spec/unit/puppet/provider/foo_spec.rb` get automatically evaluated with `pdk test unit`.
|
170
|
+
|
171
|
+
### `puppet device` support
|
172
|
+
|
173
|
+
To support remote resources using `puppet device`, a few more steps are needed. First a `Puppet::Util::NetworkDevice::<device type>::Device` class needs to exist, which provides facts and connection management . That device class can inherit from `Puppet::Util::NetworkDevice::Simple::Device` to receive a simple default configuration parser using hocon.
|
174
|
+
|
175
|
+
The provider needs to specify the `remote_resource` feature to enable the second part of the machinery.
|
176
|
+
|
177
|
+
After this, `puppet device` will be able to use the new provider, and supply it (through the device class) with the URL specified in the [`device.conf`](https://puppet.com/docs/puppet/5.3/config_file_device.html).
|
175
178
|
|
176
179
|
### Further Reading
|
177
180
|
|
@@ -179,7 +182,7 @@ The [Resource API](https://github.com/DavidS/puppet-specifications/blob/resource
|
|
179
182
|
|
180
183
|
This [Introduction to Testing Puppet Modules](https://www.netways.de/index.php?id=3445#c44135) talk describes rspec usage in more detail.
|
181
184
|
|
182
|
-
The [RSpec docs](https://relishapp.com/rspec) provide an overview of the capabilities of rspec.
|
185
|
+
The [RSpec docs](https://relishapp.com/rspec) provide an overview of the capabilities of rspec.
|
183
186
|
|
184
187
|
Read [betterspecs](http://www.betterspecs.org/) for general guidelines on what is considered good specs.
|
185
188
|
|
@@ -197,11 +200,9 @@ Currently working:
|
|
197
200
|
* `puppet agent`
|
198
201
|
* `puppet device` (if applicable)
|
199
202
|
|
200
|
-
|
201
203
|
There are still a few notable gaps between the implementation and the specification:
|
202
204
|
* Only a single runtime environment (the Puppet commands) is currently implemented.
|
203
205
|
* `auto*` definitions.
|
204
|
-
* The Commands API is mostly implemented, but deployment is blocked on upstream work (PDK-580). Use regular Ruby `system()` calls as a workaround, with their underlying encoding and safety issues.
|
205
206
|
|
206
207
|
## Development
|
207
208
|
|
data/Rakefile
CHANGED
@@ -14,7 +14,7 @@ require 'rspec/core/rake_task'
|
|
14
14
|
|
15
15
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
16
16
|
if RUBY_PLATFORM == "java"
|
17
|
-
t.exclude_pattern = 'spec/{acceptance/**/*.rb,integration/**/*.rb,puppet/resource_api
|
17
|
+
t.exclude_pattern = 'spec/{acceptance/**/*.rb,integration/**/*.rb,puppet/resource_api/*_context_spec.rb,puppet/util/network_device/simple/device_spec.rb}'
|
18
18
|
t.rspec_opts = '--tag ~agent_test'
|
19
19
|
end
|
20
20
|
end
|
data/lib/puppet/resource_api.rb
CHANGED
@@ -1,7 +1,4 @@
|
|
1
1
|
require 'pathname'
|
2
|
-
# do not load command support on the puppetserver
|
3
|
-
require 'puppet/resource_api/command' unless RUBY_PLATFORM == 'java'
|
4
|
-
require 'puppet/resource_api/errors'
|
5
2
|
require 'puppet/resource_api/glue'
|
6
3
|
require 'puppet/resource_api/puppet_context' unless RUBY_PLATFORM == 'java'
|
7
4
|
require 'puppet/resource_api/version'
|
@@ -89,7 +86,7 @@ module Puppet::ResourceApi
|
|
89
86
|
# if type.instance?(v)
|
90
87
|
# return true
|
91
88
|
# else
|
92
|
-
# inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(
|
89
|
+
# inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(v)
|
93
90
|
# error_msg = Puppet::Pops::Types::TypeMismatchDescriber.new.describe_mismatch("#{DEFINITION[:name]}.#{name}", type, inferred_type)
|
94
91
|
# raise Puppet::ResourceError, error_msg
|
95
92
|
# end
|
@@ -99,12 +96,33 @@ module Puppet::ResourceApi
|
|
99
96
|
defaultto options[:default]
|
100
97
|
end
|
101
98
|
|
102
|
-
|
103
|
-
|
99
|
+
type = Puppet::Pops::Types::TypeParser.singleton.parse(options[:type])
|
100
|
+
validate do |value|
|
101
|
+
return true if type.instance?(value)
|
102
|
+
|
103
|
+
if value.is_a? String
|
104
|
+
# when running under `puppet resource`, we need to try to coerce from strings to the real type
|
105
|
+
case value
|
106
|
+
when %r{^-?\d+$}, Puppet::Pops::Patterns::NUMERIC
|
107
|
+
value = Puppet::Pops::Utils.to_n(value)
|
108
|
+
when %r{\Atrue|false\Z}
|
109
|
+
value = value == 'true'
|
110
|
+
end
|
111
|
+
return true if type.instance?(value)
|
112
|
+
|
113
|
+
inferred_type = Puppet::Pops::Types::TypeCalculator.infer_set(value)
|
114
|
+
error_msg = Puppet::Pops::Types::TypeMismatchDescriber.new.describe_mismatch("#{definition[:name]}.#{name}", type, inferred_type)
|
115
|
+
raise Puppet::ResourceError, error_msg
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# provide better handling of the standard types
|
120
|
+
case type
|
121
|
+
when Puppet::Pops::Types::PStringType
|
104
122
|
# require any string value
|
105
123
|
Puppet::ResourceApi.def_newvalues(self, param_or_property, %r{})
|
106
124
|
# rubocop:disable Lint/BooleanSymbol
|
107
|
-
when
|
125
|
+
when Puppet::Pops::Types::PBooleanType
|
108
126
|
Puppet::ResourceApi.def_newvalues(self, param_or_property, 'true', 'false')
|
109
127
|
aliasvalue true, 'true'
|
110
128
|
aliasvalue false, 'false'
|
@@ -122,30 +140,21 @@ module Puppet::ResourceApi
|
|
122
140
|
end
|
123
141
|
end
|
124
142
|
# rubocop:enable Lint/BooleanSymbol
|
125
|
-
when
|
143
|
+
when Puppet::Pops::Types::PIntegerType
|
126
144
|
Puppet::ResourceApi.def_newvalues(self, param_or_property, %r{^-?\d+$})
|
127
145
|
munge do |v|
|
128
146
|
Puppet::Pops::Utils.to_n(v)
|
129
147
|
end
|
130
|
-
when
|
148
|
+
when Puppet::Pops::Types::PFloatType, Puppet::Pops::Types::PNumericType
|
131
149
|
Puppet::ResourceApi.def_newvalues(self, param_or_property, Puppet::Pops::Patterns::NUMERIC)
|
132
150
|
munge do |v|
|
133
151
|
Puppet::Pops::Utils.to_n(v)
|
134
152
|
end
|
153
|
+
end
|
154
|
+
|
155
|
+
case options[:type]
|
135
156
|
when 'Enum[present, absent]'
|
136
157
|
Puppet::ResourceApi.def_newvalues(self, param_or_property, :absent, :present)
|
137
|
-
when 'Variant[Pattern[/\A(0x)?[0-9a-fA-F]{8}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{16}\Z/], Pattern[/\A(0x)?[0-9a-fA-F]{40}\Z/]]'
|
138
|
-
# the namevar needs to be a Parameter, which only has newvalue*s*
|
139
|
-
Puppet::ResourceApi.def_newvalues(self, param_or_property, %r{\A(0x)?[0-9a-fA-F]{8}\Z}, %r{\A(0x)?[0-9a-fA-F]{16}\Z}, %r{\A(0x)?[0-9a-fA-F]{40}\Z})
|
140
|
-
when 'Optional[String]'
|
141
|
-
Puppet::ResourceApi.def_newvalues(self, param_or_property, %r{}, :undef)
|
142
|
-
when 'Variant[Stdlib::Absolutepath, Pattern[/\A(https?|ftp):\/\//]]'
|
143
|
-
# TODO: this is wrong, but matches original implementation
|
144
|
-
Puppet::ResourceApi.def_newvalues(self, param_or_property, /^\//, /\A(https?|ftp):\/\//) # rubocop:disable Style/RegexpLiteral
|
145
|
-
when 'Pattern[/\A((hkp|http|https):\/\/)?([a-z\d])([a-z\d-]{0,61}\.)+[a-z\d]+(:\d{2,5})?$/]'
|
146
|
-
Puppet::ResourceApi.def_newvalues(self, param_or_property, /\A((hkp|http|https):\/\/)?([a-z\d])([a-z\d-]{0,61}\.)+[a-z\d]+(:\d{2,5})?$/) # rubocop:disable Style/RegexpLiteral
|
147
|
-
else
|
148
|
-
raise Puppet::DevError, "Datatype #{options[:type]} is not yet supported in this prototype"
|
149
158
|
end
|
150
159
|
end
|
151
160
|
end
|
@@ -41,7 +41,7 @@ module Puppet::ResourceApi
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def to_manifest
|
44
|
-
(["#{@typename} { #{values[:name].inspect}: "] + values.keys.reject { |k| k == :name }.map { |k| " #{k} => #{values[k]
|
44
|
+
(["#{@typename} { #{values[:name].inspect}: "] + values.keys.reject { |k| k == :name }.map { |k| " #{k} => #{Puppet::Parameter.format_value_for_display(values[k])}," } + ['}']).join("\n")
|
45
45
|
end
|
46
46
|
|
47
47
|
# Convert our resource to yaml for Hiera purposes.
|
@@ -2,11 +2,12 @@ module Puppet::ResourceApi
|
|
2
2
|
# This class provides a default implementation for set(), when your resource does not benefit from batching.
|
3
3
|
# Instead of processing changes yourself, the `create`, `update`, and `delete` functions, are called for you,
|
4
4
|
# with proper logging already set up.
|
5
|
-
# Note that your type needs to use `ensure` in the conventional way to signal presence
|
5
|
+
# Note that your type needs to use `name` as its namevar, and `ensure` in the conventional way to signal presence
|
6
|
+
# and absence of resources.
|
6
7
|
class SimpleProvider
|
7
8
|
def set(context, changes)
|
8
9
|
changes.each do |name, change|
|
9
|
-
is = change.key?(:is) ? change[:is] : (get(context) || []).find { |
|
10
|
+
is = change.key?(:is) ? change[:is] : (get(context) || []).find { |r| r[:name] == name }
|
10
11
|
should = change[:should]
|
11
12
|
|
12
13
|
is = { name: name, ensure: 'absent' } if is.nil?
|
data/puppet-resource_api.gemspec
CHANGED
@@ -18,8 +18,5 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
|
-
spec.add_runtime_dependency 'childprocess', '~> 0.7'
|
22
21
|
spec.add_runtime_dependency 'hocon', '>= 1.0'
|
23
|
-
|
24
|
-
spec.extensions = 'ext/mkrf_conf.rb'
|
25
22
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppet-resource_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Schmitt
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-02-
|
11
|
+
date: 2018-02-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: childprocess
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - "~>"
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0.7'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - "~>"
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0.7'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: hocon
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -42,8 +28,7 @@ description:
|
|
42
28
|
email:
|
43
29
|
- david.schmitt@puppet.com
|
44
30
|
executables: []
|
45
|
-
extensions:
|
46
|
-
- ext/mkrf_conf.rb
|
31
|
+
extensions: []
|
47
32
|
extra_rdoc_files: []
|
48
33
|
files:
|
49
34
|
- ".dependency_decisions.yml"
|
@@ -63,11 +48,8 @@ files:
|
|
63
48
|
- bin/console
|
64
49
|
- bin/setup
|
65
50
|
- codecov.yml
|
66
|
-
- ext/mkrf_conf.rb
|
67
51
|
- lib/puppet/resource_api.rb
|
68
52
|
- lib/puppet/resource_api/base_context.rb
|
69
|
-
- lib/puppet/resource_api/command.rb
|
70
|
-
- lib/puppet/resource_api/errors.rb
|
71
53
|
- lib/puppet/resource_api/glue.rb
|
72
54
|
- lib/puppet/resource_api/io_context.rb
|
73
55
|
- lib/puppet/resource_api/puppet_context.rb
|
data/ext/mkrf_conf.rb
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# Based on the example from https://en.wikibooks.org/wiki/Ruby_Programming/RubyGems#How_to_install_different_versions_of_gems_depending_on_which_version_of_ruby_the_installee_is_using
|
2
|
-
require 'rubygems'
|
3
|
-
require 'rubygems/command.rb'
|
4
|
-
require 'rubygems/dependency_installer.rb'
|
5
|
-
begin
|
6
|
-
Gem::Command.build_args = ARGV
|
7
|
-
rescue NoMethodError # rubocop:disable Lint/HandleExceptions
|
8
|
-
end
|
9
|
-
inst = Gem::DependencyInstaller.new
|
10
|
-
begin
|
11
|
-
if RbConfig::CONFIG['host_os'] =~ %r{mswin|msys|mingw32}i
|
12
|
-
inst.install 'childprocess', '~> 0.7'
|
13
|
-
end
|
14
|
-
rescue StandardError
|
15
|
-
exit(1)
|
16
|
-
end
|
17
|
-
|
18
|
-
f = File.open(File.join(File.dirname(__FILE__), 'Rakefile'), 'w') # create dummy rakefile to indicate success
|
19
|
-
f.write("task :default\n")
|
20
|
-
f.close
|
@@ -1,122 +0,0 @@
|
|
1
|
-
require 'childprocess'
|
2
|
-
|
3
|
-
module Puppet::ResourceApi
|
4
|
-
# A useful interface to safely run system commands
|
5
|
-
#
|
6
|
-
# See https://github.com/DavidS/puppet-specifications/blob/reasourceapi/language/resource-api/README.md#commands for a complete specification
|
7
|
-
class Command
|
8
|
-
# Small utility class to hold the `run()` results together
|
9
|
-
class Result
|
10
|
-
attr_accessor :stdout, :stderr, :exit_code
|
11
|
-
def initialize
|
12
|
-
@stdout = ''
|
13
|
-
@stderr = ''
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
attr_accessor :cwd, :environment
|
18
|
-
|
19
|
-
attr_reader :command
|
20
|
-
|
21
|
-
def initialize(command)
|
22
|
-
@command = command
|
23
|
-
@cwd = '/'
|
24
|
-
@environment = {}
|
25
|
-
end
|
26
|
-
|
27
|
-
def run(context, *args,
|
28
|
-
stdin_source: :none, stdin_value: nil, stdin_io: nil, stdin_encoding: nil,
|
29
|
-
stdout_destination: :log, stdout_loglevel: :debug, stdout_encoding: nil,
|
30
|
-
stderr_destination: :log, stderr_loglevel: :warning, stderr_encoding: nil,
|
31
|
-
noop: false)
|
32
|
-
raise ArgumentError, "context is a '#{context.class}', expected a 'Puppet::ResourceApi::BaseContext'" unless context.is_a? Puppet::ResourceApi::BaseContext
|
33
|
-
return if noop
|
34
|
-
process = self.class.prepare_process(context, command, *args, environment: environment, cwd: cwd)
|
35
|
-
|
36
|
-
process.duplex = true
|
37
|
-
|
38
|
-
stdout_r, stdout_w = IO.pipe
|
39
|
-
process.io.stdout = stdout_w
|
40
|
-
process.io.stdout.set_encoding(process.io.stdout.external_encoding, stdout_encoding) if stdout_encoding
|
41
|
-
|
42
|
-
stderr_r, stderr_w = IO.pipe
|
43
|
-
process.io.stderr = stderr_w
|
44
|
-
process.io.stderr.set_encoding(process.io.stderr.external_encoding, stderr_encoding) if stderr_encoding
|
45
|
-
|
46
|
-
process.io.stdin.set_encoding(process.io.stdin.external_encoding, stdin_encoding) if stdin_encoding
|
47
|
-
|
48
|
-
process.start
|
49
|
-
stdout_w.close
|
50
|
-
stderr_w.close
|
51
|
-
|
52
|
-
case stdin_source
|
53
|
-
when :none # rubocop:disable Lint/EmptyWhen
|
54
|
-
# nothing to do here
|
55
|
-
when :io
|
56
|
-
while (v = stdin_io.read) && !v.empty? # `empty?` signals EOF, can't use the `length` variant due to encoding issues
|
57
|
-
process.io.stdin.write v
|
58
|
-
end
|
59
|
-
when :value
|
60
|
-
process.io.stdin.write stdin_value
|
61
|
-
end
|
62
|
-
process.io.stdin.close
|
63
|
-
|
64
|
-
result = Result.new
|
65
|
-
|
66
|
-
# TODO: https://tickets.puppetlabs.com/browse/PDK-542 - capture/buffer full lines
|
67
|
-
while process.alive? || !stdout_r.eof? || !stderr_r.eof?
|
68
|
-
rs, _ws, _errs = IO.select([stdout_r, stderr_r])
|
69
|
-
rs.each do |pipe|
|
70
|
-
loglevel = if pipe == stdout_r
|
71
|
-
stdout_loglevel
|
72
|
-
else
|
73
|
-
stderr_loglevel
|
74
|
-
end
|
75
|
-
|
76
|
-
destination = if pipe == stdout_r
|
77
|
-
stdout_destination
|
78
|
-
else
|
79
|
-
stderr_destination
|
80
|
-
end
|
81
|
-
|
82
|
-
begin
|
83
|
-
chunk = pipe.read_nonblock(1024)
|
84
|
-
case destination
|
85
|
-
when :log
|
86
|
-
chunk.split("\n").each { |l| context.send(loglevel, l.strip) }
|
87
|
-
when :store
|
88
|
-
if pipe == stdout_r
|
89
|
-
result.stdout += chunk
|
90
|
-
else
|
91
|
-
result.stderr += chunk
|
92
|
-
end
|
93
|
-
end
|
94
|
-
rescue Errno::EBADF # rubocop:disable Lint/HandleExceptions
|
95
|
-
# This can be thrown on Windows after the process has gone away
|
96
|
-
# ignore, retry WaitReadable through outer loop
|
97
|
-
rescue IO::WaitReadable, EOFError # rubocop:disable Lint/HandleExceptions
|
98
|
-
# ignore, retry WaitReadable through outer loop
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
result.exit_code = process.wait
|
104
|
-
|
105
|
-
raise Puppet::ResourceApi::CommandExecutionError, 'Command %{command} failed with exit code %{exit_code}' % { command: command, exit_code: result.exit_code } unless result.exit_code.zero?
|
106
|
-
|
107
|
-
result
|
108
|
-
rescue ChildProcess::LaunchError => e
|
109
|
-
raise Puppet::ResourceApi::CommandNotFoundError, 'Error when executing %{command}: %{error}' % { command: command, error: e.to_s }
|
110
|
-
end
|
111
|
-
|
112
|
-
def self.prepare_process(_context, command, *args, environment:, cwd:)
|
113
|
-
process = ChildProcess.build(command, *args)
|
114
|
-
environment.each do |k, v|
|
115
|
-
process.environment[k] = v
|
116
|
-
end
|
117
|
-
process.cwd = cwd
|
118
|
-
|
119
|
-
process
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
@@ -1,10 +0,0 @@
|
|
1
|
-
|
2
|
-
module Puppet::ResourceApi
|
3
|
-
# This error is thrown when a Command cannot find the specified command
|
4
|
-
class CommandNotFoundError < StandardError
|
5
|
-
end
|
6
|
-
|
7
|
-
# This error is thrown when a Command returned a non-zero exit code
|
8
|
-
class CommandExecutionError < StandardError
|
9
|
-
end
|
10
|
-
end
|