agentless-catalog-executor 0.10.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.rubocop.yml +5 -0
- data/.travis.yml +1 -0
- data/CHANGELOG.md +37 -2
- data/CODEOWNERS +2 -0
- data/Dockerfile +1 -1
- data/README.md +1 -1
- data/agentless-catalog-executor.gemspec +1 -1
- data/developer-docs/api.md +7 -0
- data/developer-docs/docker.md +3 -1
- data/lib/ace/file_mutex.rb +29 -0
- data/lib/ace/fork_util.rb +5 -2
- data/lib/ace/plugin_cache.rb +21 -15
- data/lib/ace/puppet_util.rb +35 -14
- data/lib/ace/schemas/ace-execute_catalog.json +26 -1
- data/lib/ace/schemas/ace-run_task.json +1 -2
- data/lib/ace/transport_app.rb +166 -39
- data/lib/ace/version.rb +1 -1
- data/lib/puppet/indirector/catalog/certless.rb +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 603248d8cb9b344650b57553ed3f415e94964b5c49fb1adcfa38b3e14adbfc8a
|
4
|
+
data.tar.gz: dedfb986987cb291c4a5277b269a25da626f875854ba44b5a7935aabc3851f67
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e408493f6327f58cc447a38e7de50cc39bee52d99dd98bbfa4ae66c24744e0c27a5d384bd2d04448c0004915367028f927d4c7587fdcfcfa03b326f0bb5d281d
|
7
|
+
data.tar.gz: cd98abcf1b810d881dddcf1c0207f8ec0a3c3cf62e7da76fa9cd87bd1416e379da5a9ffbb094a0d27dea4ba5ae3477b40006ab909a6391179e949a24e741c6de
|
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -3,6 +3,32 @@
|
|
3
3
|
All significant changes to this repo will be summarized in this file.
|
4
4
|
|
5
5
|
|
6
|
+
## [v1.0.0](https://github.com/puppetlabs/ace/tree/v1.0.0) (2019-10-08)
|
7
|
+
[Full Changelog](https://github.com/puppetlabs/ace/compare/v0.10.0...v1.0.0)
|
8
|
+
|
9
|
+
**Implemented enhancements:**
|
10
|
+
|
11
|
+
- \(FM-8503\) implement transport loading if there is no device.rb shim [\#55](https://github.com/puppetlabs/ace/pull/55) ([Lavinia-Dan](https://github.com/Lavinia-Dan))
|
12
|
+
- \(FM-8485\) - Addition of CODEOWNERS file [\#53](https://github.com/puppetlabs/ace/pull/53) ([david22swan](https://github.com/david22swan))
|
13
|
+
- \(FM-8446\) remove remote-transport requirement [\#50](https://github.com/puppetlabs/ace/pull/50) ([DavidS](https://github.com/DavidS))
|
14
|
+
- \(PE-27029\) introduce enforce\_environment to support strict mode [\#49](https://github.com/puppetlabs/ace/pull/49) ([DavidS](https://github.com/DavidS))
|
15
|
+
- \(PE-27024\) return detailed results from `/execute\_catalog` [\#48](https://github.com/puppetlabs/ace/pull/48) ([DavidS](https://github.com/DavidS))
|
16
|
+
|
17
|
+
**Fixed bugs:**
|
18
|
+
|
19
|
+
- \(FM-8566\) Add additional error handling for /run\_task [\#60](https://github.com/puppetlabs/ace/pull/60) ([da-ar](https://github.com/da-ar))
|
20
|
+
- \(FM-8497\) Ensure cross-process mutexing [\#59](https://github.com/puppetlabs/ace/pull/59) ([da-ar](https://github.com/da-ar))
|
21
|
+
- \(FM-8481\) Add missing headers for native extensions [\#51](https://github.com/puppetlabs/ace/pull/51) ([da-ar](https://github.com/da-ar))
|
22
|
+
- \\(PE-27024\\) return detailed results from `/execute\\_catalog` [\#48](https://github.com/puppetlabs/ace/pull/48) ([DavidS](https://github.com/DavidS))
|
23
|
+
|
24
|
+
**Merged pull requests:**
|
25
|
+
|
26
|
+
- \(maint\) rubocop fixes for RSpec/EmptyLineAfterExample [\#61](https://github.com/puppetlabs/ace/pull/61) ([da-ar](https://github.com/da-ar))
|
27
|
+
- \(FM-8496\) Add support for Puppet debug flags during /execute\_catalog [\#58](https://github.com/puppetlabs/ace/pull/58) ([david22swan](https://github.com/david22swan))
|
28
|
+
- \(maint\) Do not follow spec test found in `Volumes` [\#56](https://github.com/puppetlabs/ace/pull/56) ([da-ar](https://github.com/da-ar))
|
29
|
+
- \(maint\) various cleanups [\#52](https://github.com/puppetlabs/ace/pull/52) ([DavidS](https://github.com/DavidS))
|
30
|
+
- \(maint\) using the CA\_ALLOW\_SUBJECT\_ALT\_NAMES env variable for new doc… [\#47](https://github.com/puppetlabs/ace/pull/47) ([Thomas-Franklin](https://github.com/Thomas-Franklin))
|
31
|
+
|
6
32
|
## [v0.10.0](https://github.com/puppetlabs/ace/tree/v0.10.0) (2019-07-25)
|
7
33
|
[Full Changelog](https://github.com/puppetlabs/ace/compare/v0.9.1...v0.10.0)
|
8
34
|
|
@@ -31,6 +57,8 @@ All significant changes to this repo will be summarized in this file.
|
|
31
57
|
- \(FM-7927\) Docs review [\#35](https://github.com/puppetlabs/ace/pull/35) ([clairecadman](https://github.com/clairecadman))
|
32
58
|
|
33
59
|
## [v0.9.0](https://github.com/puppetlabs/ace/tree/v0.9.0) (2019-04-16)
|
60
|
+
[Full Changelog](https://github.com/puppetlabs/ace/compare/0.1.0...v0.9.0)
|
61
|
+
|
34
62
|
**Implemented enhancements:**
|
35
63
|
|
36
64
|
- \(FM-7922\) running the configuration to apply catalog to transport [\#30](https://github.com/puppetlabs/ace/pull/30) ([Thomas-Franklin](https://github.com/Thomas-Franklin))
|
@@ -39,8 +67,6 @@ All significant changes to this repo will be summarized in this file.
|
|
39
67
|
- \(FM-7883\) execute plugin sync from a puppetserver [\#20](https://github.com/puppetlabs/ace/pull/20) ([Thomas-Franklin](https://github.com/Thomas-Franklin))
|
40
68
|
- \(FM-7826\) first pass of execute catalog docs and mock API endpoint [\#16](https://github.com/puppetlabs/ace/pull/16) ([DavidS](https://github.com/DavidS))
|
41
69
|
- Utilities for environment isolation per request [\#12](https://github.com/puppetlabs/ace/pull/12) ([willmeek](https://github.com/willmeek))
|
42
|
-
- \(PE-25514\) Add docker support for ACE [\#3](https://github.com/puppetlabs/ace/pull/3) ([da-ar](https://github.com/da-ar))
|
43
|
-
- \(PE-25508\) Add JSON Schema and validation example [\#2](https://github.com/puppetlabs/ace/pull/2) ([da-ar](https://github.com/da-ar))
|
44
70
|
|
45
71
|
**Fixed bugs:**
|
46
72
|
|
@@ -64,6 +90,15 @@ All significant changes to this repo will be summarized in this file.
|
|
64
90
|
- Update README.md [\#10](https://github.com/puppetlabs/ace/pull/10) ([willmeek](https://github.com/willmeek))
|
65
91
|
- \(maint\) reworking of the configuration [\#5](https://github.com/puppetlabs/ace/pull/5) ([Thomas-Franklin](https://github.com/Thomas-Franklin))
|
66
92
|
- Update JSONSchema, and mock endpoint [\#4](https://github.com/puppetlabs/ace/pull/4) ([da-ar](https://github.com/da-ar))
|
93
|
+
|
94
|
+
## [0.1.0](https://github.com/puppetlabs/ace/tree/0.1.0) (2018-11-30)
|
95
|
+
**Implemented enhancements:**
|
96
|
+
|
97
|
+
- \(PE-25514\) Add docker support for ACE [\#3](https://github.com/puppetlabs/ace/pull/3) ([da-ar](https://github.com/da-ar))
|
98
|
+
- \(PE-25508\) Add JSON Schema and validation example [\#2](https://github.com/puppetlabs/ace/pull/2) ([da-ar](https://github.com/da-ar))
|
99
|
+
|
100
|
+
**Merged pull requests:**
|
101
|
+
|
67
102
|
- \(PE-25509\) first fake endpoint; rubocop [\#1](https://github.com/puppetlabs/ace/pull/1) ([DavidS](https://github.com/DavidS))
|
68
103
|
|
69
104
|
|
data/CODEOWNERS
ADDED
data/Dockerfile
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
FROM puppet/puppet-agent-alpine:6.4.2 as build
|
3
3
|
|
4
4
|
RUN \
|
5
|
-
apk --no-cache add build-base ruby-dev ruby-bundler ruby-json ruby-bigdecimal git openssl-dev && \
|
5
|
+
apk --no-cache add build-base ruby-dev ruby-bundler ruby-json ruby-bigdecimal git openssl-dev linux-headers && \
|
6
6
|
echo 'gem: --no-document' > /etc/gemrc && \
|
7
7
|
bundle config --global silence_root_warning 1
|
8
8
|
|
data/README.md
CHANGED
@@ -18,7 +18,7 @@ ACE is built-in to PE as pe-ace-server.
|
|
18
18
|
|
19
19
|
## Development
|
20
20
|
|
21
|
-
As ACE is dependent on Puppet Server, there is a docker-compose file in the `spec/` directory which we advise you run before
|
21
|
+
As ACE is dependent on Puppet Server, there is a docker-compose file in the `spec/` directory which we advise you run before the ACE service to ensure that the certs and keys are valid. For more information, see the [docker documentation](developer-docs/docker.md).
|
22
22
|
|
23
23
|
To release a new version, update the version number in `version.rb`, generate a new changelog with `bundle exec rake changelog`, commit the results and run `bundle exec rake release`, which creates a git tag for the version, pushes git commits and tags, and pushes the `.gem` file to [rubygems.org](https://rubygems.org). Released gems are eventually consumed by [ace-vanagon](https://github.com/puppetlabs/ace-vanagon) and promoted into PE.
|
24
24
|
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
-
spec.add_dependency "bolt", "~> 1.
|
23
|
+
spec.add_dependency "bolt", "~> 1.31"
|
24
24
|
|
25
25
|
# server-side dependencies cargo culted from https://github.com/puppetlabs/bolt/blob/4418da408643aa7eb5ed64f4c9704b941ea878dc/Gemfile#L10-L16
|
26
26
|
spec.add_dependency "hocon", ">= 1.2.5"
|
data/developer-docs/api.md
CHANGED
@@ -106,6 +106,13 @@ The `compiler` is a JSON object which contains parameters regarding the compilat
|
|
106
106
|
* `transaction_uuid`
|
107
107
|
* `job_id`
|
108
108
|
|
109
|
+
The compiler also contains several parameters that can be used in order to help to debug your request, these being:
|
110
|
+
|
111
|
+
* `noop`
|
112
|
+
* `debug`
|
113
|
+
* `trace`
|
114
|
+
* `evaltrace`
|
115
|
+
|
109
116
|
### Task Object
|
110
117
|
This is a copy of [bolt's task object](https://github.com/puppetlabs/bolt/blob/master/developer-docs/bolt-api-servers.md#task-object)
|
111
118
|
|
data/developer-docs/docker.md
CHANGED
@@ -31,7 +31,9 @@ sudo chmod a+rx -R volumes/
|
|
31
31
|
|
32
32
|
At this point it is required to generate certs for the `aceserver`, this can be achieved though:
|
33
33
|
|
34
|
-
|
34
|
+
```
|
35
|
+
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,spec_puppet_1,ace_aceserver_1
|
36
|
+
```
|
35
37
|
|
36
38
|
On Linux, ensure that you have access to the newly created files:
|
37
39
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'timeout'
|
4
|
+
|
5
|
+
module ACE
|
6
|
+
class FileMutex
|
7
|
+
def initialize(lock_file)
|
8
|
+
@lock_file = lock_file
|
9
|
+
end
|
10
|
+
|
11
|
+
def with_read_lock
|
12
|
+
fh = File.open(@lock_file, File::CREAT)
|
13
|
+
fh.flock(File::LOCK_SH)
|
14
|
+
yield
|
15
|
+
ensure
|
16
|
+
fh.flock(File::LOCK_UN)
|
17
|
+
fh.close
|
18
|
+
end
|
19
|
+
|
20
|
+
def with_write_lock
|
21
|
+
fh = File.open(@lock_file, File::CREAT)
|
22
|
+
fh.flock(File::LOCK_EX)
|
23
|
+
yield
|
24
|
+
ensure
|
25
|
+
fh.flock(File::LOCK_UN)
|
26
|
+
fh.close
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/ace/fork_util.rb
CHANGED
@@ -28,7 +28,7 @@ module ACE
|
|
28
28
|
}
|
29
29
|
}.to_json)
|
30
30
|
success = false
|
31
|
-
rescue
|
31
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
32
32
|
writer.puts({
|
33
33
|
msg: e.message,
|
34
34
|
kind: e.class,
|
@@ -39,6 +39,7 @@ module ACE
|
|
39
39
|
}.to_json)
|
40
40
|
success = false
|
41
41
|
ensure
|
42
|
+
writer.flush
|
42
43
|
Process.exit! success
|
43
44
|
end
|
44
45
|
# :nocov:
|
@@ -48,11 +49,13 @@ module ACE
|
|
48
49
|
exit 1
|
49
50
|
end
|
50
51
|
writer.close
|
51
|
-
output = reader.
|
52
|
+
output = reader.readlines('')[0]
|
52
53
|
Process.wait(pid)
|
53
54
|
if $CHILD_STATUS != 0
|
54
55
|
error = JSON.parse(output)
|
55
56
|
raise ACE::Error.new(error['msg'], error['kind'], error['details'])
|
57
|
+
elsif output.nil?
|
58
|
+
raise ACE::Error.new('spawned process returned no result', 'puppetlabs/ace/fork_util', 'no details')
|
56
59
|
else
|
57
60
|
JSON.parse(output)
|
58
61
|
end
|
data/lib/ace/plugin_cache.rb
CHANGED
@@ -14,14 +14,21 @@ module ACE
|
|
14
14
|
PURGE_INTERVAL = 24 * PURGE_TIMEOUT
|
15
15
|
PURGE_TTL = 7 * PURGE_INTERVAL
|
16
16
|
|
17
|
-
def initialize(environments_cache_dir
|
17
|
+
def initialize(environments_cache_dir,
|
18
|
+
purge_interval: PURGE_INTERVAL,
|
19
|
+
purge_timeout: PURGE_TIMEOUT,
|
20
|
+
purge_ttl: PURGE_TTL,
|
21
|
+
cache_dir_mutex: Concurrent::ReadWriteLock.new,
|
22
|
+
do_purge: true)
|
18
23
|
@cache_dir = environments_cache_dir
|
19
|
-
@cache_dir_mutex =
|
24
|
+
@cache_dir_mutex = cache_dir_mutex
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
if do_purge
|
27
|
+
@purge = Concurrent::TimerTask.new(execution_interval: purge_interval,
|
28
|
+
timeout_interval: purge_timeout,
|
29
|
+
run_now: true) { expire(purge_ttl) }
|
30
|
+
@purge.execute
|
31
|
+
end
|
25
32
|
end
|
26
33
|
|
27
34
|
def setup
|
@@ -29,9 +36,14 @@ module ACE
|
|
29
36
|
self
|
30
37
|
end
|
31
38
|
|
32
|
-
def with_synced_libdir(environment, certname, &block)
|
39
|
+
def with_synced_libdir(environment, enforce_environment, certname, &block)
|
33
40
|
ForkUtil.isolate do
|
34
|
-
ACE::PuppetUtil.isolated_puppet_settings(
|
41
|
+
ACE::PuppetUtil.isolated_puppet_settings(
|
42
|
+
certname,
|
43
|
+
environment,
|
44
|
+
enforce_environment,
|
45
|
+
environment_dir(environment)
|
46
|
+
)
|
35
47
|
with_synced_libdir_core(environment, &block)
|
36
48
|
end
|
37
49
|
end
|
@@ -65,7 +77,7 @@ module ACE
|
|
65
77
|
def environment_dir(environment)
|
66
78
|
environment_dir = File.join(cache_dir, environment)
|
67
79
|
cache_dir_mutex.with_write_lock do
|
68
|
-
FileUtils.mkdir_p(environment_dir)
|
80
|
+
FileUtils.mkdir_p(File.join(environment_dir, 'code', 'environments', environment))
|
69
81
|
FileUtils.touch(environment_dir)
|
70
82
|
end
|
71
83
|
environment_dir
|
@@ -76,12 +88,6 @@ module ACE
|
|
76
88
|
def sync_core(environment)
|
77
89
|
env = Puppet::Node::Environment.remote(environment)
|
78
90
|
environments_dir = environment_dir(environment)
|
79
|
-
Puppet[:vardir] = File.join(environments_dir)
|
80
|
-
Puppet[:confdir] = File.join(environments_dir, 'conf')
|
81
|
-
Puppet[:rundir] = File.join(environments_dir, 'run')
|
82
|
-
Puppet[:logdir] = File.join(environments_dir, 'log')
|
83
|
-
Puppet[:codedir] = File.join(environments_dir, 'code')
|
84
|
-
Puppet[:plugindest] = File.join(environments_dir, 'plugins')
|
85
91
|
Puppet::Configurer::PluginHandler.new.download_plugins(env)
|
86
92
|
libdir(File.join(environments_dir, 'plugins'))
|
87
93
|
end
|
data/lib/ace/puppet_util.rb
CHANGED
@@ -18,12 +18,12 @@ module ACE
|
|
18
18
|
# as per request settings will be set later on
|
19
19
|
# to satisfy multi-environments
|
20
20
|
Puppet.settings[:vardir] = cachedir
|
21
|
-
Puppet.settings[:confdir] = File.join(cachedir, '
|
22
|
-
Puppet.settings[:rundir] = File.join(cachedir, '
|
23
|
-
Puppet.settings[:logdir] = File.join(cachedir, '
|
24
|
-
Puppet.settings[:codedir] = File.join(cachedir, '
|
25
|
-
Puppet.settings[:plugindest] = File.join(cachedir, '
|
26
|
-
|
21
|
+
Puppet.settings[:confdir] = File.join(cachedir, 'conf_x')
|
22
|
+
Puppet.settings[:rundir] = File.join(cachedir, 'run_x')
|
23
|
+
Puppet.settings[:logdir] = File.join(cachedir, 'log_x')
|
24
|
+
Puppet.settings[:codedir] = File.join(cachedir, 'code_x')
|
25
|
+
Puppet.settings[:plugindest] = File.join(cachedir, 'plugin_x')
|
26
|
+
|
27
27
|
# ssl_context will be a persistent context
|
28
28
|
cert_provider = Puppet::X509::CertProvider.new(
|
29
29
|
capath: ca_cert_path,
|
@@ -35,18 +35,39 @@ module ACE
|
|
35
35
|
private_key: OpenSSL::PKey::RSA.new(File.read(private_key_path, encoding: 'utf-8')),
|
36
36
|
client_cert: OpenSSL::X509::Certificate.new(File.read(client_cert_path, encoding: 'utf-8'))
|
37
37
|
)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
Puppet::Transaction::Report.indirection.terminus_class = :rest
|
38
|
+
# Store SSL settings for reuse in isolated process
|
39
|
+
@ssl_settings = {
|
40
|
+
ssl_context: ssl_context,
|
41
|
+
server: uri.host,
|
42
|
+
serverport: uri.port
|
43
|
+
}
|
45
44
|
end
|
46
45
|
|
47
|
-
def self.isolated_puppet_settings(certname, environment)
|
46
|
+
def self.isolated_puppet_settings(certname, environment, enforce_environment, environment_dir)
|
48
47
|
Puppet.settings[:certname] = certname
|
49
48
|
Puppet.settings[:environment] = environment
|
49
|
+
Puppet.settings[:strict_environment_mode] = enforce_environment
|
50
|
+
|
51
|
+
Puppet.settings[:vardir] = File.join(environment_dir)
|
52
|
+
Puppet.settings[:confdir] = File.join(environment_dir, 'conf')
|
53
|
+
Puppet.settings[:rundir] = File.join(environment_dir, 'run')
|
54
|
+
Puppet.settings[:logdir] = File.join(environment_dir, 'log')
|
55
|
+
Puppet.settings[:codedir] = File.join(environment_dir, 'code')
|
56
|
+
Puppet.settings[:plugindest] = File.join(environment_dir, 'plugins')
|
57
|
+
|
58
|
+
# establish a base_context. This needs to be the first context on the stack, but must not be created
|
59
|
+
# before all settings have been set. For example, this will create a Puppet::Environments::Directories
|
60
|
+
# instance copying the :environmentpath setting and never updating this.
|
61
|
+
Puppet.push_context(Puppet.base_context(Puppet.settings), "Puppet Initialization")
|
62
|
+
Puppet.push_context(@ssl_settings, "PuppetServer connection information to be used")
|
63
|
+
|
64
|
+
# finalise settings initialisation
|
65
|
+
Puppet.settings.use :main, :agent, :ssl
|
66
|
+
|
67
|
+
# special override
|
68
|
+
Puppet::Transaction::Report.indirection.terminus_class = :rest
|
69
|
+
|
70
|
+
# configure the requested environment, and deploy new loaders
|
50
71
|
env = Puppet::Node::Environment.remote(environment)
|
51
72
|
Puppet.push_context({
|
52
73
|
configured_environment: environment,
|
@@ -28,6 +28,10 @@
|
|
28
28
|
"type": "string",
|
29
29
|
"description": "The name of the environment for which to compile the catalog."
|
30
30
|
},
|
31
|
+
"enforce_environment": {
|
32
|
+
"type": "boolean",
|
33
|
+
"description": "Whether to force agents to run in the same environment in which their assigned applications are defined. (This key is required to be false if `environment` is an empty string)."
|
34
|
+
},
|
31
35
|
"transaction_uuid": {
|
32
36
|
"type": "string",
|
33
37
|
"description": "The id for tracking the catalog compilation and report submission."
|
@@ -35,12 +39,33 @@
|
|
35
39
|
"job_id": {
|
36
40
|
"type": "string",
|
37
41
|
"description": "The id of the orchestrator job that triggered this run."
|
42
|
+
},
|
43
|
+
"noop": {
|
44
|
+
"type": "boolean",
|
45
|
+
"description": "The operation should not be applied",
|
46
|
+
"default": false
|
47
|
+
},
|
48
|
+
"debug": {
|
49
|
+
"type": "boolean",
|
50
|
+
"description": "Show up to debug level messages",
|
51
|
+
"default": false
|
52
|
+
},
|
53
|
+
"trace": {
|
54
|
+
"type": "boolean",
|
55
|
+
"description": "Allows for a backtrace to be returned in the event of an exception",
|
56
|
+
"default": false
|
57
|
+
},
|
58
|
+
"evaltrace": {
|
59
|
+
"type": "boolean",
|
60
|
+
"description": "Reports on each step of the Puppet process",
|
61
|
+
"default": false
|
38
62
|
}
|
39
63
|
},
|
40
64
|
"additionalProperties": true,
|
41
65
|
"required": [
|
42
66
|
"certname",
|
43
|
-
"environment"
|
67
|
+
"environment",
|
68
|
+
"enforce_environment"
|
44
69
|
]
|
45
70
|
}
|
46
71
|
},
|
data/lib/ace/transport_app.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'ace/file_mutex'
|
3
4
|
require 'ace/error'
|
4
5
|
require 'ace/fork_util'
|
5
6
|
require 'ace/puppet_util'
|
@@ -18,12 +19,17 @@ require 'puppet/util/network_device/base'
|
|
18
19
|
module ACE
|
19
20
|
class TransportApp < Sinatra::Base
|
20
21
|
def initialize(config = nil)
|
22
|
+
@logger = Logging.logger[self]
|
21
23
|
@config = config
|
22
24
|
@executor = Bolt::Executor.new(0)
|
23
25
|
tasks_cache_dir = File.join(@config['cache-dir'], 'tasks')
|
24
|
-
@
|
25
|
-
|
26
|
-
|
26
|
+
@mutex = ACE::FileMutex.new(Tempfile.new('ace.lock'))
|
27
|
+
@file_cache = BoltServer::FileCache.new(@config.data.merge('cache-dir' => tasks_cache_dir),
|
28
|
+
cache_dir_mutex: @mutex, do_purge: false).setup
|
29
|
+
environments_cache_dir = File.join(@config['cache-dir'], 'environment_cache')
|
30
|
+
@plugins_mutex = ACE::FileMutex.new(Tempfile.new('ace.plugins.lock'))
|
31
|
+
@plugins = ACE::PluginCache.new(environments_cache_dir,
|
32
|
+
cache_dir_mutex: @plugins_mutex, do_purge: false).setup
|
27
33
|
|
28
34
|
@schemas = {
|
29
35
|
"run_task" => JSON.parse(File.read(File.join(__dir__, 'schemas', 'ace-run_task.json'))),
|
@@ -40,6 +46,36 @@ module ACE
|
|
40
46
|
config['cache-dir'],
|
41
47
|
URI.parse(config['puppet-server-uri']))
|
42
48
|
|
49
|
+
ace_pid = Process.pid
|
50
|
+
@logger.info "ACE started: #{ace_pid}"
|
51
|
+
fork do
|
52
|
+
# :nocov:
|
53
|
+
# FileCache and PluginCache cleanup timer started in a seperate fork
|
54
|
+
# so that there is only a single timer responsible for purging old files
|
55
|
+
@logger.info "FileCache process started: #{Process.pid}"
|
56
|
+
@fc_purge = BoltServer::FileCache.new(@config.data.merge('cache-dir' => tasks_cache_dir),
|
57
|
+
cache_dir_mutex: @mutex,
|
58
|
+
do_purge: true)
|
59
|
+
|
60
|
+
@pc_purge = ACE::PluginCache.new(environments_cache_dir,
|
61
|
+
cache_dir_mutex: @plugins_mutex, do_purge: true)
|
62
|
+
loop do
|
63
|
+
begin
|
64
|
+
# is the parent process alibve
|
65
|
+
Process.getpgid(ace_pid)
|
66
|
+
sleep 10 # how often to check if parent process is alive
|
67
|
+
rescue Interrupt
|
68
|
+
# handle ctrl-c event
|
69
|
+
break
|
70
|
+
rescue StandardError
|
71
|
+
# parent is no longer alive
|
72
|
+
break
|
73
|
+
end
|
74
|
+
end
|
75
|
+
@logger.info "FileCache process ended"
|
76
|
+
# :nocov:
|
77
|
+
end
|
78
|
+
|
43
79
|
super(nil)
|
44
80
|
end
|
45
81
|
|
@@ -84,11 +120,20 @@ module ACE
|
|
84
120
|
end
|
85
121
|
|
86
122
|
device_struct = Struct.new(:provider, :url, :name, :options)
|
123
|
+
type = target['remote-transport']
|
87
124
|
# Return device
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
125
|
+
begin
|
126
|
+
require 'puppet/resource_api/transport'
|
127
|
+
transport = Puppet::ResourceApi::Transport.connect(type, url)
|
128
|
+
Puppet::ResourceApi::Transport.inject_device(type, transport)
|
129
|
+
rescue Puppet::DevError, LoadError => e
|
130
|
+
raise e unless e.message.include?("Transport for `#{type}` not registered with") || e.class == LoadError
|
131
|
+
# fallback to puppet device if there's no transport
|
132
|
+
Puppet::Util::NetworkDevice.init(device_struct.new(transport,
|
133
|
+
url,
|
134
|
+
certname,
|
135
|
+
{}))
|
136
|
+
end
|
92
137
|
end
|
93
138
|
|
94
139
|
def scrub_stack_trace(result)
|
@@ -110,6 +155,12 @@ module ACE
|
|
110
155
|
end
|
111
156
|
end
|
112
157
|
|
158
|
+
def nest_metrics(metrics)
|
159
|
+
Hash[metrics.fetch('resources', {}).values.map do |name, _human_name, value|
|
160
|
+
[name, value]
|
161
|
+
end]
|
162
|
+
end
|
163
|
+
|
113
164
|
# returns a hash of trusted facts that will be used
|
114
165
|
# to request a catalog for the target
|
115
166
|
def self.trusted_facts(certname)
|
@@ -156,39 +207,85 @@ module ACE
|
|
156
207
|
begin
|
157
208
|
body = JSON.parse(request.body.read)
|
158
209
|
validate_schema(@schemas["run_task"], body)
|
210
|
+
opts = body['target'].merge('protocol' => 'remote')
|
211
|
+
|
212
|
+
# This is a workaround for Bolt due to the way it expects to receive the target info
|
213
|
+
# see: https://github.com/puppetlabs/bolt/pull/915#discussion_r268280535
|
214
|
+
# Systems calling into ACE will need to determine the nodename/certname and pass this as `name`
|
215
|
+
target = [Bolt::Target.new(body['target']['host'] || body['target']['name'], opts)]
|
159
216
|
rescue ACE::Error => e
|
160
|
-
request_error = {
|
217
|
+
request_error = {
|
218
|
+
"node": target,
|
219
|
+
"target": target,
|
220
|
+
"action": nil,
|
221
|
+
"object": nil,
|
222
|
+
"status": "failure",
|
223
|
+
"result": {
|
224
|
+
"_error": e.to_h
|
225
|
+
}
|
226
|
+
}
|
161
227
|
return [400, request_error.to_json]
|
162
|
-
rescue
|
228
|
+
rescue JSON::ParserError => e
|
163
229
|
request_error = {
|
164
|
-
|
165
|
-
|
166
|
-
|
230
|
+
"node": target,
|
231
|
+
"target": target,
|
232
|
+
"action": nil,
|
233
|
+
"object": nil,
|
234
|
+
"status": "failure",
|
235
|
+
"result": {
|
236
|
+
"_error": ACE::Error.to_h(e.message,
|
237
|
+
'puppetlabs/ace/request_exception',
|
238
|
+
class: e.class, backtrace: e.backtrace).to_h
|
239
|
+
}
|
167
240
|
}
|
168
241
|
return [400, request_error.to_json]
|
242
|
+
rescue StandardError => e
|
243
|
+
request_error = {
|
244
|
+
"node": target,
|
245
|
+
"target": target,
|
246
|
+
"action": nil,
|
247
|
+
"object": nil,
|
248
|
+
"status": "failure",
|
249
|
+
"result": {
|
250
|
+
"_error": ACE::Error.to_h(e.message,
|
251
|
+
'puppetlabs/ace/execution_exception',
|
252
|
+
class: e.class, backtrace: e.backtrace).to_h
|
253
|
+
}
|
254
|
+
}
|
255
|
+
return [500, request_error.to_json]
|
169
256
|
end
|
170
257
|
|
171
|
-
|
172
|
-
|
173
|
-
# This is a workaround for Bolt due to the way it expects to receive the target info
|
174
|
-
# see: https://github.com/puppetlabs/bolt/pull/915#discussion_r268280535
|
175
|
-
# Systems calling into ACE will need to determine the nodename/certname and pass this as `name`
|
176
|
-
target = [Bolt::Target.new(body['target']['host'] || body['target']['name'], opts)]
|
177
|
-
|
178
|
-
inventory = Bolt::Inventory.new(nil)
|
258
|
+
begin
|
259
|
+
inventory = Bolt::Inventory.new(nil)
|
179
260
|
|
180
|
-
|
261
|
+
target.first.inventory = inventory
|
181
262
|
|
182
|
-
|
263
|
+
task = Bolt::Task::PuppetServer.new(body['task'], @file_cache)
|
183
264
|
|
184
|
-
|
265
|
+
parameters = body['parameters'] || {}
|
185
266
|
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
267
|
+
result = ForkUtil.isolate do
|
268
|
+
# Since this will only be on one node we can just return the first result
|
269
|
+
results = @executor.run_task(target, task, parameters)
|
270
|
+
scrub_stack_trace(results.first.status_hash)
|
271
|
+
end
|
272
|
+
[200, result.to_json]
|
273
|
+
rescue Exception => e # rubocop:disable Lint/RescueException
|
274
|
+
# handle all the things and make it obvious what happened
|
275
|
+
process_error = {
|
276
|
+
"node": target,
|
277
|
+
"target": target,
|
278
|
+
"action": nil,
|
279
|
+
"object": nil,
|
280
|
+
"status": "failure",
|
281
|
+
"result": {
|
282
|
+
"_error": ACE::Error.to_h(e.message,
|
283
|
+
'puppetlabs/ace/processing_exception',
|
284
|
+
class: e.class, backtrace: e.backtrace).to_h
|
285
|
+
}
|
286
|
+
}
|
287
|
+
return [500, process_error.to_json]
|
190
288
|
end
|
191
|
-
[200, result.to_json]
|
192
289
|
end
|
193
290
|
|
194
291
|
post '/execute_catalog' do
|
@@ -199,6 +296,13 @@ module ACE
|
|
199
296
|
validate_schema(@schemas["execute_catalog"], body)
|
200
297
|
|
201
298
|
environment = body['compiler']['environment']
|
299
|
+
enforce_environment = body['compiler']['enforce_environment']
|
300
|
+
if environment == '' && !enforce_environment
|
301
|
+
environment = 'production'
|
302
|
+
elsif environment == '' && enforce_environment
|
303
|
+
raise ACE::Error.new('You MUST provide an `environment` when `enforce_environment` is set to true',
|
304
|
+
'puppetlabs/ace/execute_catalog')
|
305
|
+
end
|
202
306
|
certname = body['compiler']['certname']
|
203
307
|
trans_id = body['compiler']['transaction_uuid']
|
204
308
|
job_id = body['compiler']['job_id']
|
@@ -223,14 +327,40 @@ module ACE
|
|
223
327
|
end
|
224
328
|
|
225
329
|
begin
|
226
|
-
@plugins.with_synced_libdir(environment, certname) do
|
330
|
+
run_result = @plugins.with_synced_libdir(environment, enforce_environment, certname) do
|
227
331
|
ACE::TransportApp.init_puppet_target(certname, body['target']['remote-transport'], body['target'])
|
332
|
+
|
333
|
+
# Apply compiler flags for Configurer
|
334
|
+
Puppet.settings[:noop] = body['compiler']['noop'] || false
|
335
|
+
# grab the current debug level
|
336
|
+
current_log_level = Puppet.settings[:log_level] if body['compiler']['debug']
|
337
|
+
# apply debug level if its specified
|
338
|
+
Puppet.settings[:log_level] = :debug if body['compiler']['debug']
|
339
|
+
Puppet.settings[:trace] = body['compiler']['trace'] || false
|
340
|
+
Puppet.settings[:evaltrace] = body['compiler']['evaltrace'] || false
|
341
|
+
|
228
342
|
configurer = ACE::Configurer.new(body['compiler']['transaction_uuid'], body['compiler']['job_id'])
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
343
|
+
options = { transport_name: certname,
|
344
|
+
environment: environment,
|
345
|
+
network_device: true,
|
346
|
+
pluginsync: false,
|
347
|
+
trusted_facts: ACE::TransportApp.trusted_facts(certname) }
|
348
|
+
configurer.run(options)
|
349
|
+
# return logging level back to original
|
350
|
+
Puppet.settings[:log_level] = current_log_level if body['compiler']['debug']
|
351
|
+
# `options[:report]` gets populated by configurer.run with the report of the run with a
|
352
|
+
# Puppet::Transaction::Report instance
|
353
|
+
# see https://github.com/puppetlabs/puppet/blob/c956ad95fcdd9aabb28e196b55d1f112b5944777/lib/puppet/configurer.rb#L211
|
354
|
+
report = options[:report]
|
355
|
+
# remember that this hash gets munged by fork's json serialising
|
356
|
+
{
|
357
|
+
'time' => report.time,
|
358
|
+
'transaction_uuid' => trans_id,
|
359
|
+
'environment' => report.environment,
|
360
|
+
'status' => report.status,
|
361
|
+
'metrics' => nest_metrics(report.metrics),
|
362
|
+
'job_id' => job_id
|
363
|
+
}
|
234
364
|
end
|
235
365
|
rescue ACE::Error => e
|
236
366
|
process_error = {
|
@@ -255,11 +385,8 @@ module ACE
|
|
255
385
|
else
|
256
386
|
result = {
|
257
387
|
certname: certname,
|
258
|
-
status: '
|
259
|
-
result:
|
260
|
-
transaction_uuid: trans_id,
|
261
|
-
job_id: job_id
|
262
|
-
}
|
388
|
+
status: run_result.delete('status'),
|
389
|
+
result: run_result
|
263
390
|
}
|
264
391
|
[200, result.to_json]
|
265
392
|
end
|
data/lib/ace/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: agentless-catalog-executor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.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: 2019-
|
11
|
+
date: 2019-10-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bolt
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.31'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.31'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: hocon
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -211,6 +211,7 @@ files:
|
|
211
211
|
- ".rubocop.yml"
|
212
212
|
- ".travis.yml"
|
213
213
|
- CHANGELOG.md
|
214
|
+
- CODEOWNERS
|
214
215
|
- Dockerfile
|
215
216
|
- Gemfile
|
216
217
|
- LICENSE
|
@@ -239,6 +240,7 @@ files:
|
|
239
240
|
- lib/ace/config.rb
|
240
241
|
- lib/ace/configurer.rb
|
241
242
|
- lib/ace/error.rb
|
243
|
+
- lib/ace/file_mutex.rb
|
242
244
|
- lib/ace/fork_util.rb
|
243
245
|
- lib/ace/plugin_cache.rb
|
244
246
|
- lib/ace/puppet_util.rb
|
@@ -266,8 +268,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
266
268
|
- !ruby/object:Gem::Version
|
267
269
|
version: '0'
|
268
270
|
requirements: []
|
269
|
-
|
270
|
-
rubygems_version: 2.7.6
|
271
|
+
rubygems_version: 3.0.4
|
271
272
|
signing_key:
|
272
273
|
specification_version: 4
|
273
274
|
summary: ACE lets you run remote tasks and catalogs using puppet and bolt.
|