agentless-catalog-executor 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.dependency_decisions.yml +118 -0
- data/.gitignore +15 -0
- data/.rspec +3 -0
- data/.rubocop.yml +97 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +44 -0
- data/Dockerfile +42 -0
- data/Gemfile +22 -0
- data/LICENSE +201 -0
- data/README.md +23 -0
- data/Rakefile +52 -0
- data/acceptance/.gitignore +10 -0
- data/acceptance/Gemfile +28 -0
- data/acceptance/Rakefile +16 -0
- data/acceptance/config/gem/options.rb +6 -0
- data/acceptance/config/git/options.rb +7 -0
- data/acceptance/config/package/options.rb +6 -0
- data/acceptance/lib/acceptance/ace_command_helper.rb +49 -0
- data/acceptance/lib/acceptance/ace_setup_helper.rb +45 -0
- data/acceptance/setup/common/pre-suite/.gitkeep +0 -0
- data/acceptance/setup/gem/pre-suite/.gitkeep +0 -0
- data/acceptance/setup/git/pre-suite/.gitkeep +0 -0
- data/acceptance/setup/package/pre-suite/.gitkeep +0 -0
- data/acceptance/tests/.gitkeep +0 -0
- data/agentless-catalog-executor.gemspec +38 -0
- data/config/docker.conf +9 -0
- data/config/local.conf +9 -0
- data/config/transport_tasks_config.rb +49 -0
- data/developer-docs/api.md +139 -0
- data/developer-docs/docker.md +170 -0
- data/docker-compose.yml +12 -0
- data/lib/ace/config.rb +73 -0
- data/lib/ace/configurer.rb +17 -0
- data/lib/ace/error.rb +31 -0
- data/lib/ace/fork_util.rb +39 -0
- data/lib/ace/plugin_cache.rb +79 -0
- data/lib/ace/puppet_util.rb +57 -0
- data/lib/ace/schemas/ace-execute_catalog.json +48 -0
- data/lib/ace/schemas/ace-run_task.json +30 -0
- data/lib/ace/schemas/task.json +74 -0
- data/lib/ace/transport_app.rb +252 -0
- data/lib/ace/version.rb +5 -0
- data/lib/puppet/indirector/catalog/certless.rb +83 -0
- metadata +254 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
# Docker Docs
|
2
|
+
|
3
|
+
## Setup
|
4
|
+
|
5
|
+
[Docker-compose installation](https://docs.docker.com/compose/install/) would need to be followed and setup in order to use the ACE containers for development.
|
6
|
+
|
7
|
+
|
8
|
+
The ACE compose file is dependent on a Docker network created when launching the Puppetserver and PuppetDB containers within the `spec/` directory, the network will default to `spec_default`, since the containers are built from the `spec/` directory they will be assigned the `<folder>_default` network.
|
9
|
+
|
10
|
+
As the ACE container is build outside of the `spec/` directory it would not be able to create the `spec_default` network. This can be created manually through:
|
11
|
+
|
12
|
+
```
|
13
|
+
docker network create spec_default
|
14
|
+
```
|
15
|
+
|
16
|
+
Once this is done the ACE container can be launched by executing the following within the root folder:
|
17
|
+
|
18
|
+
```
|
19
|
+
docker-compose up -d --build
|
20
|
+
```
|
21
|
+
|
22
|
+
This will take some time as it needs to perform the initial build of fetching the images and running through the build.
|
23
|
+
|
24
|
+
Navigate to the `spec/` folder and build the Puppetserver and PuppetDB containers using the same command. The Puppetserver will take some time to start and typically using the following command to verify that it is ready:
|
25
|
+
|
26
|
+
```
|
27
|
+
docker logs --follow spec_puppetserver_1
|
28
|
+
```
|
29
|
+
|
30
|
+
Once the Puppetserver is ready, the following message is reported:
|
31
|
+
|
32
|
+
```
|
33
|
+
2019-03-18 15:42:19,964 INFO [p.s.m.master-service] Puppet Server has successfully started and is now ready to handle requests
|
34
|
+
2019-03-18 15:42:19,965 INFO [p.s.l.legacy-routes-service] The legacy routing service has successfully started and is now ready to handle requests
|
35
|
+
```
|
36
|
+
|
37
|
+
On Linux, ensure that you have access to all volumes:
|
38
|
+
|
39
|
+
```
|
40
|
+
sudo chmod a+rx -R volumes/
|
41
|
+
```
|
42
|
+
|
43
|
+
At this point it is required to generate certs for the `aceserver`, this can be achieved though:
|
44
|
+
|
45
|
+
`docker exec spec_puppet_1 puppetserver ca generate --certname aceserver --subject-alt-names localhost,aceserver,ace_aceserver_1,spec_puppetserver_1,ace_server,puppet_server,spec_aceserver_1,puppetdb,spec_puppetdb_1,0.0.0.0,puppet`
|
46
|
+
|
47
|
+
On Linux, ensure that you have access to the newly created files:
|
48
|
+
|
49
|
+
```
|
50
|
+
sudo chmod a+rx -R volumes/
|
51
|
+
```
|
52
|
+
|
53
|
+
Reasoning for this is that it makes it easier to ensure that the cert names are consistent across environments.
|
54
|
+
|
55
|
+
## Verifying the services
|
56
|
+
|
57
|
+
[Postman](https://www.getpostman.com/) is advisable to verify that the endpoints are configured. In order to set up Postman, navigate to Settings > Certificates and add client certificates for hosts `0.0.0.0:8140` and `0.0.0.0:44633` where the CRT file points to `spec/volumes/puppet/ssl/certs/aceserver.pem` and Key file points to `spec/volumes/puppet/ssl/private_keys/aceserver.pem`
|
58
|
+
|
59
|
+
*Note*: These cert and key files will only be created when the PuppetServer container has finished initalising.
|
60
|
+
|
61
|
+
### PuppetServer /tasks/:module/:task
|
62
|
+
|
63
|
+
```
|
64
|
+
https://0.0.0.0:8140/puppet/v3/tasks/:module/:task?environment=production
|
65
|
+
```
|
66
|
+
|
67
|
+
Is the endpoint to get the task metadata from a PuppetServer, i.e.
|
68
|
+
|
69
|
+
```
|
70
|
+
GET https://0.0.0.0:8140/puppet/v3/tasks/panos/apikey?environment=production
|
71
|
+
|
72
|
+
RESPONSE
|
73
|
+
{
|
74
|
+
"metadata": {
|
75
|
+
"description": "Retrieve a PAN-OS apikey",
|
76
|
+
"files": [
|
77
|
+
...
|
78
|
+
],
|
79
|
+
"parameters": {},
|
80
|
+
"puppet_task_version": 1,
|
81
|
+
"remote": true,
|
82
|
+
"supports_noop": false
|
83
|
+
},
|
84
|
+
"name": "panos::apikey",
|
85
|
+
"files": [
|
86
|
+
...
|
87
|
+
]
|
88
|
+
}
|
89
|
+
```
|
90
|
+
|
91
|
+
This can be used to construct the request body that will be used to execute the [ACE `/run_task`](#ace-runtask) endpoint.
|
92
|
+
|
93
|
+
### ACE /run_task
|
94
|
+
|
95
|
+
```
|
96
|
+
POST https://0.0.0.0:44633/run_task
|
97
|
+
BODY {
|
98
|
+
"target": {
|
99
|
+
"remote-transport": "panos",
|
100
|
+
"name":"pavm",
|
101
|
+
"hostname": "vvtzckq3vzx995w.delivery.puppetlabs.net",
|
102
|
+
"user": "admin",
|
103
|
+
"password": "admin",
|
104
|
+
"ssl": false
|
105
|
+
},
|
106
|
+
"task": {
|
107
|
+
"metadata": {
|
108
|
+
"description": "Retrieve a PAN-OS apikey",
|
109
|
+
"files": [
|
110
|
+
...
|
111
|
+
],
|
112
|
+
"parameters": {},
|
113
|
+
"puppet_task_version": 1,
|
114
|
+
"remote": true,
|
115
|
+
"supports_noop": false
|
116
|
+
},
|
117
|
+
"name": "panos::apikey",
|
118
|
+
"files": [
|
119
|
+
...
|
120
|
+
]
|
121
|
+
}}
|
122
|
+
|
123
|
+
RESPONSE
|
124
|
+
{
|
125
|
+
"node": "vvtzckq3vzx995w.delivery.puppetlabs.net",
|
126
|
+
"status": "success",
|
127
|
+
"result": {
|
128
|
+
"apikey": "LUFRPT14MW5xOEo1R09KVlBZNnpnemh0VHRBOWl6TGM9bXcwM3JHUGVhRlNiY0dCR0srNERUQT09"
|
129
|
+
}
|
130
|
+
}
|
131
|
+
```
|
132
|
+
|
133
|
+
Running the containers through Docker does have the benefit that the containers will be a better representation of how the ACE service will work in PE, however for developing and verifying changes it can be considered slow as changes may require the ACE container to be rebuilt which can take some time, an alternative approach for local development is [running the service locally](#running-ace-locally), this way the Puppetserver and PuppetDB containers are only required to be running.
|
134
|
+
|
135
|
+
## Running ACE locally
|
136
|
+
|
137
|
+
The ACE service can also be ran directly through Puma rather than building the container, this has the benefits of being able to specifying local changes of Bolt within the Gemfile rather than having to make the changes in the container, or committing the changes and rebuilding the containers which can take some time.
|
138
|
+
|
139
|
+
When running locally through Puma there is a caveat on the tasks that are being executed and a possible conflict with the version of Ruby on the local installation, where solutions are highlighted in the [incorrect Puppet Ruby version](#incorrect-puppet-ruby-version).
|
140
|
+
|
141
|
+
Launching the service locally can be achieved by running the following:
|
142
|
+
|
143
|
+
```
|
144
|
+
ACE_CONF=config/local.conf bundle exec puma -C config/transport_tasks_config.rb
|
145
|
+
```
|
146
|
+
|
147
|
+
### Incorrect Puppet Ruby version
|
148
|
+
|
149
|
+
The tasks typically used in networking modules have a shebang referencing the Puppet Ruby, there are two approaches to getting around this.
|
150
|
+
|
151
|
+
When constructing requests to be sent to ACE, in the target hash the interpreter can be specified, i.e.
|
152
|
+
|
153
|
+
```
|
154
|
+
{
|
155
|
+
"target":{
|
156
|
+
"remote-transport":"panos",
|
157
|
+
"name":"pavm",
|
158
|
+
"interpreters":{
|
159
|
+
".rb":"/Users/thomas.franklin/.rbenv/versions/2.5.1/bin/ruby"
|
160
|
+
}
|
161
|
+
},
|
162
|
+
"task": {hash from puppetserver /tasks endpoint}
|
163
|
+
}
|
164
|
+
```
|
165
|
+
|
166
|
+
Although this would need to be included in every request - a 'permanent' solution would be to symlink the Puppet Ruby to the development version of Ruby, i.e.
|
167
|
+
|
168
|
+
```
|
169
|
+
sudo ln -svf $(bundle exec which ruby) /opt/puppetlabs/puppet/bin/ruby
|
170
|
+
```
|
data/docker-compose.yml
ADDED
data/lib/ace/config.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hocon'
|
4
|
+
require 'bolt_server/base_config'
|
5
|
+
|
6
|
+
module ACE
|
7
|
+
class Config < BoltServer::BaseConfig
|
8
|
+
attr_reader :data
|
9
|
+
def config_keys
|
10
|
+
super + %w[concurrency cache-dir puppet-server-conn-timeout puppet-server-uri ssl-ca-crls]
|
11
|
+
end
|
12
|
+
|
13
|
+
def env_keys
|
14
|
+
super + %w[concurrency puppet-server-conn-timeout puppet-server-uri ssl-ca-crls]
|
15
|
+
end
|
16
|
+
|
17
|
+
def ssl_keys
|
18
|
+
super + %w[ssl-ca-crls]
|
19
|
+
end
|
20
|
+
|
21
|
+
def int_keys
|
22
|
+
%w[concurrency puppet-server-conn-timeout]
|
23
|
+
end
|
24
|
+
|
25
|
+
def defaults
|
26
|
+
super.merge(
|
27
|
+
'port' => 44633,
|
28
|
+
'concurrency' => 10,
|
29
|
+
'cache-dir' => "/opt/puppetlabs/server/data/ace-server/cache",
|
30
|
+
'puppet-server-conn-timeout' => 120,
|
31
|
+
'file-server-conn-timeout' => 120
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
def required_keys
|
36
|
+
super + %w[puppet-server-uri cache-dir]
|
37
|
+
end
|
38
|
+
|
39
|
+
def service_name
|
40
|
+
'ace-server'
|
41
|
+
end
|
42
|
+
|
43
|
+
def load_env_config
|
44
|
+
env_keys.each do |key|
|
45
|
+
transformed_key = "ACE_#{key.tr('-', '_').upcase}"
|
46
|
+
next unless ENV.key?(transformed_key)
|
47
|
+
@data[key] = if int_keys.include?(key)
|
48
|
+
ENV[transformed_key].to_i
|
49
|
+
else
|
50
|
+
ENV[transformed_key]
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def validate
|
56
|
+
super
|
57
|
+
|
58
|
+
unless natural?(@data['concurrency'])
|
59
|
+
raise Bolt::ValidationError, "Configured 'concurrency' must be a positive integer"
|
60
|
+
end
|
61
|
+
|
62
|
+
unless natural?(@data['puppet-server-conn-timeout'])
|
63
|
+
raise Bolt::ValidationError, "Configured 'puppet-server-conn-timeout' must be a positive integer"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def make_compatible
|
68
|
+
# This function sets values used by Bolt that behave the same in ACE, but have a different meaning
|
69
|
+
@data['file-server-uri'] = @data['puppet-server-uri']
|
70
|
+
@data['file-server-conn-timeout'] = @data['puppet-server-conn-timeout']
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'puppet/configurer'
|
4
|
+
|
5
|
+
module ACE
|
6
|
+
class Configurer < Puppet::Configurer
|
7
|
+
# override the configurer to return the facts
|
8
|
+
# related to the transport and the trusted
|
9
|
+
# facts which is passed to the configurer.run
|
10
|
+
def get_facts(options)
|
11
|
+
transport_facts = Puppet::Node::Facts.indirection.find(Puppet[:certname],
|
12
|
+
environment: Puppet[:environment]).values
|
13
|
+
trusted_facts = options[:trusted_facts]
|
14
|
+
{ transport_facts: transport_facts, trusted_facts: trusted_facts }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/ace/error.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ACE
|
4
|
+
class Error < RuntimeError
|
5
|
+
attr_reader :kind, :details, :issue_code, :error_code
|
6
|
+
|
7
|
+
def initialize(msg, kind, details = nil, issue_code = nil)
|
8
|
+
super(msg)
|
9
|
+
@kind = kind
|
10
|
+
@issue_code = issue_code
|
11
|
+
@details = details || {}
|
12
|
+
@error_code ||= 1
|
13
|
+
end
|
14
|
+
|
15
|
+
def msg
|
16
|
+
message
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_h
|
20
|
+
h = { 'kind' => kind,
|
21
|
+
'msg' => message,
|
22
|
+
'details' => details }
|
23
|
+
h['issue_code'] = issue_code if issue_code
|
24
|
+
h
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_json(opts = nil)
|
28
|
+
to_h.to_json(opts)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# English module required for $CHILD_STATUS rather than $?
|
4
|
+
require 'English'
|
5
|
+
|
6
|
+
module ACE
|
7
|
+
class ForkUtil
|
8
|
+
# Forks and calls a function
|
9
|
+
# It is expected that the function returns a JSON response
|
10
|
+
# Throws an exception if JSON.generate fails to generate
|
11
|
+
def self.isolate
|
12
|
+
reader, writer = IO.pipe
|
13
|
+
pid = fork {
|
14
|
+
success = true
|
15
|
+
begin
|
16
|
+
response = yield
|
17
|
+
writer.puts JSON.generate(response)
|
18
|
+
rescue StandardError => e
|
19
|
+
writer.puts(e)
|
20
|
+
success = false
|
21
|
+
ensure
|
22
|
+
Process.exit! success
|
23
|
+
end
|
24
|
+
}
|
25
|
+
unless pid
|
26
|
+
log "Could not fork"
|
27
|
+
exit 1
|
28
|
+
end
|
29
|
+
writer.close
|
30
|
+
output = reader.read
|
31
|
+
Process.wait(pid)
|
32
|
+
if $CHILD_STATUS != 0
|
33
|
+
raise output
|
34
|
+
else
|
35
|
+
JSON.parse(output)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'fileutils'
|
4
|
+
require 'ace/puppet_util'
|
5
|
+
require 'puppet/configurer'
|
6
|
+
require 'concurrent'
|
7
|
+
require 'ace/fork_util'
|
8
|
+
|
9
|
+
module ACE
|
10
|
+
class PluginCache
|
11
|
+
attr_reader :cache_dir_mutex, :cache_dir
|
12
|
+
def initialize(environments_cache_dir)
|
13
|
+
@cache_dir = environments_cache_dir
|
14
|
+
@cache_dir_mutex = Concurrent::ReadWriteLock.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup
|
18
|
+
FileUtils.mkdir_p(cache_dir)
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def with_synced_libdir(environment, certname, &block)
|
23
|
+
ForkUtil.isolate do
|
24
|
+
ACE::PuppetUtil.isolated_puppet_settings(certname, environment)
|
25
|
+
with_synced_libdir_core(environment, &block)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def with_synced_libdir_core(environment)
|
30
|
+
pool = Puppet::Network::HTTP::Pool.new(Puppet[:http_keepalive_timeout])
|
31
|
+
Puppet.push_context({
|
32
|
+
http_pool: pool
|
33
|
+
}, "Isolated HTTP Pool")
|
34
|
+
libdir = sync_core(environment)
|
35
|
+
Puppet.settings[:libdir] = libdir
|
36
|
+
$LOAD_PATH << libdir
|
37
|
+
yield
|
38
|
+
ensure
|
39
|
+
FileUtils.remove_dir(libdir)
|
40
|
+
pool.close
|
41
|
+
end
|
42
|
+
|
43
|
+
# the Puppet[:libdir] will point to a tmp location
|
44
|
+
# where the contents from the pluginsync dest is copied
|
45
|
+
# too.
|
46
|
+
def libdir(plugin_dest)
|
47
|
+
tmpdir = Dir.mktmpdir(['plugins', plugin_dest])
|
48
|
+
cache_dir_mutex.with_write_lock do
|
49
|
+
FileUtils.cp_r(File.join(plugin_dest, '.'), tmpdir)
|
50
|
+
FileUtils.touch(tmpdir)
|
51
|
+
end
|
52
|
+
tmpdir
|
53
|
+
end
|
54
|
+
|
55
|
+
def environment_dir(environment)
|
56
|
+
environment_dir = File.join(cache_dir, environment)
|
57
|
+
cache_dir_mutex.with_write_lock do
|
58
|
+
FileUtils.mkdir_p(environment_dir)
|
59
|
+
FileUtils.touch(environment_dir)
|
60
|
+
end
|
61
|
+
environment_dir
|
62
|
+
end
|
63
|
+
|
64
|
+
# @returns the tmp libdir directory which will be where
|
65
|
+
# Puppet[:libdir] is referenced too
|
66
|
+
def sync_core(environment)
|
67
|
+
env = Puppet::Node::Environment.remote(environment)
|
68
|
+
environments_dir = environment_dir(environment)
|
69
|
+
Puppet[:vardir] = File.join(environments_dir)
|
70
|
+
Puppet[:confdir] = File.join(environments_dir, 'conf')
|
71
|
+
Puppet[:rundir] = File.join(environments_dir, 'run')
|
72
|
+
Puppet[:logdir] = File.join(environments_dir, 'log')
|
73
|
+
Puppet[:codedir] = File.join(environments_dir, 'code')
|
74
|
+
Puppet[:plugindest] = File.join(environments_dir, 'plugins')
|
75
|
+
Puppet::Configurer::PluginHandler.new.download_plugins(env)
|
76
|
+
libdir(File.join(environments_dir, 'plugins'))
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
module ACE
|
6
|
+
class PuppetUtil
|
7
|
+
def self.init_global_settings(ca_cert_path, ca_crls_path, private_key_path, client_cert_path, cachedir, uri)
|
8
|
+
Puppet::Util::Log.destinations.clear
|
9
|
+
Puppet::Util::Log.newdestination(:console)
|
10
|
+
Puppet.settings[:log_level] = 'notice'
|
11
|
+
Puppet.settings[:trace] = true
|
12
|
+
Puppet.settings[:catalog_terminus] = :certless
|
13
|
+
Puppet.settings[:node_terminus] = :memory
|
14
|
+
Puppet.settings[:catalog_cache_terminus] = :json
|
15
|
+
Puppet.settings[:facts_terminus] = :network_device
|
16
|
+
# the following settings are just to make base_context
|
17
|
+
# happy, these will not be the final values,
|
18
|
+
# as per request settings will be set later on
|
19
|
+
# to satisfy multi-environments
|
20
|
+
Puppet.settings[:vardir] = cachedir
|
21
|
+
Puppet.settings[:confdir] = File.join(cachedir, 'conf')
|
22
|
+
Puppet.settings[:rundir] = File.join(cachedir, 'run')
|
23
|
+
Puppet.settings[:logdir] = File.join(cachedir, 'log')
|
24
|
+
Puppet.settings[:codedir] = File.join(cachedir, 'code')
|
25
|
+
Puppet.settings[:plugindest] = File.join(cachedir, 'plugins')
|
26
|
+
Puppet.push_context(Puppet.base_context(Puppet.settings), "Puppet Initialization")
|
27
|
+
# ssl_context will be a persistent context
|
28
|
+
cert_provider = Puppet::X509::CertProvider.new(
|
29
|
+
capath: ca_cert_path,
|
30
|
+
crlpath: ca_crls_path
|
31
|
+
)
|
32
|
+
ssl_context = Puppet::SSL::SSLProvider.new.create_context(
|
33
|
+
cacerts: cert_provider.load_cacerts(required: true),
|
34
|
+
crls: cert_provider.load_crls(required: true),
|
35
|
+
private_key: OpenSSL::PKey::RSA.new(File.read(private_key_path, encoding: 'utf-8')),
|
36
|
+
client_cert: OpenSSL::X509::Certificate.new(File.read(client_cert_path, encoding: 'utf-8'))
|
37
|
+
)
|
38
|
+
Puppet.push_context({
|
39
|
+
ssl_context: ssl_context,
|
40
|
+
server: uri.host,
|
41
|
+
serverport: uri.port
|
42
|
+
}, "PuppetServer connection information to be used")
|
43
|
+
Puppet.settings.use :main, :agent, :ssl
|
44
|
+
Puppet::Transaction::Report.indirection.terminus_class = :rest
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.isolated_puppet_settings(certname, environment)
|
48
|
+
Puppet.settings[:certname] = certname
|
49
|
+
Puppet.settings[:environment] = environment
|
50
|
+
env = Puppet::Node::Environment.remote(environment)
|
51
|
+
Puppet.push_context({
|
52
|
+
configured_environment: environment,
|
53
|
+
loaders: Puppet::Pops::Loaders.new(env)
|
54
|
+
}, "Isolated settings to be used")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|