bolt 1.7.0 → 1.8.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of bolt might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/bolt/pal.rb +6 -6
- data/lib/bolt/version.rb +1 -1
- data/lib/bolt_server/base_config.rb +105 -0
- data/lib/bolt_server/config.rb +27 -83
- data/lib/bolt_server/file_cache.rb +7 -7
- data/lib/plan_executor/app.rb +4 -1
- data/lib/plan_executor/applicator.rb +30 -0
- data/lib/plan_executor/config.rb +39 -0
- metadata +5 -4
- data/exe/bolt-server +0 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e9fd995a1caaab8cc183d8e20404f29ac10509586099832df91ddb45829aed5
|
4
|
+
data.tar.gz: d45036383b14dbc2df9cedccf2bc9a669febab613161e37ef680228dd42fd50e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83bedc800fcfb5f1449ed873a189dc32845efa1311670332bcc8ab746ac83c3c5453c8bf1a6e6640a5abaa403bebbdce5d6ff1c26dce3ab28b2a13e49dd2081c
|
7
|
+
data.tar.gz: d7ec493dcc3289ae3fa24b6edf3a663677044929fec82e5d7f7498ab0540c3fb475aa83aa17492afe4a1d544291ec357f4132b79bfe5e10a1d783696c057f0d3
|
data/lib/bolt/pal.rb
CHANGED
@@ -120,12 +120,12 @@ module Bolt
|
|
120
120
|
r
|
121
121
|
end
|
122
122
|
|
123
|
-
def with_bolt_executor(executor, inventory, pdb_client = nil, &block)
|
123
|
+
def with_bolt_executor(executor, inventory, pdb_client = nil, applicator = nil, &block)
|
124
124
|
opts = {
|
125
125
|
bolt_executor: executor,
|
126
126
|
bolt_inventory: inventory,
|
127
127
|
bolt_pdb_client: pdb_client,
|
128
|
-
apply_executor: Applicator.new(
|
128
|
+
apply_executor: applicator || Applicator.new(
|
129
129
|
inventory,
|
130
130
|
executor,
|
131
131
|
@modulepath,
|
@@ -141,8 +141,8 @@ module Bolt
|
|
141
141
|
Puppet.override(opts, &block)
|
142
142
|
end
|
143
143
|
|
144
|
-
def in_plan_compiler(executor, inventory, pdb_client)
|
145
|
-
with_bolt_executor(executor, inventory, pdb_client) do
|
144
|
+
def in_plan_compiler(executor, inventory, pdb_client, applicator = nil)
|
145
|
+
with_bolt_executor(executor, inventory, pdb_client, applicator) do
|
146
146
|
# TODO: remove this call and see if anything breaks when
|
147
147
|
# settings dirs don't actually exist. Plans shouldn't
|
148
148
|
# actually be using them.
|
@@ -287,8 +287,8 @@ module Bolt
|
|
287
287
|
end
|
288
288
|
end
|
289
289
|
|
290
|
-
def run_plan(plan_name, params, executor = nil, inventory = nil, pdb_client = nil)
|
291
|
-
in_plan_compiler(executor, inventory, pdb_client) do |compiler|
|
290
|
+
def run_plan(plan_name, params, executor = nil, inventory = nil, pdb_client = nil, applicator = nil)
|
291
|
+
in_plan_compiler(executor, inventory, pdb_client, applicator) do |compiler|
|
292
292
|
r = compiler.call_function('run_plan', plan_name, params.merge('_bolt_api_call' => true))
|
293
293
|
Bolt::PlanResult.from_pcore(r, 'success')
|
294
294
|
end
|
data/lib/bolt/version.rb
CHANGED
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hocon'
|
4
|
+
require 'bolt/error'
|
5
|
+
|
6
|
+
module BoltServer
|
7
|
+
class BaseConfig
|
8
|
+
def config_keys
|
9
|
+
['host', 'port', 'ssl-cert', 'ssl-key', 'ssl-ca-cert',
|
10
|
+
'ssl-cipher-suites', 'loglevel', 'logfile', 'whitelist']
|
11
|
+
end
|
12
|
+
|
13
|
+
def env_keys
|
14
|
+
['ssl-cert', 'ssl-key', 'ssl-ca-cert', 'loglevel']
|
15
|
+
end
|
16
|
+
|
17
|
+
def defaults
|
18
|
+
{ 'host' => '127.0.0.1',
|
19
|
+
'loglevel' => 'notice',
|
20
|
+
'ssl-cipher-suites' => ['ECDHE-ECDSA-AES256-GCM-SHA384',
|
21
|
+
'ECDHE-RSA-AES256-GCM-SHA384',
|
22
|
+
'ECDHE-ECDSA-CHACHA20-POLY1305',
|
23
|
+
'ECDHE-RSA-CHACHA20-POLY1305',
|
24
|
+
'ECDHE-ECDSA-AES128-GCM-SHA256',
|
25
|
+
'ECDHE-RSA-AES128-GCM-SHA256',
|
26
|
+
'ECDHE-ECDSA-AES256-SHA384',
|
27
|
+
'ECDHE-RSA-AES256-SHA384',
|
28
|
+
'ECDHE-ECDSA-AES128-SHA256',
|
29
|
+
'ECDHE-RSA-AES128-SHA256'] }
|
30
|
+
end
|
31
|
+
|
32
|
+
def ssl_keys
|
33
|
+
['ssl-cert', 'ssl-key', 'ssl-ca-cert']
|
34
|
+
end
|
35
|
+
|
36
|
+
def required_keys
|
37
|
+
ssl_keys
|
38
|
+
end
|
39
|
+
|
40
|
+
def service_name
|
41
|
+
raise "Method service_name must be defined in the service class"
|
42
|
+
end
|
43
|
+
|
44
|
+
def initialize(config = nil)
|
45
|
+
@data = defaults
|
46
|
+
@data = @data.merge(config.select { |key, _| config_keys.include?(key) }) if config
|
47
|
+
@config_path = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def load_file_config(path)
|
51
|
+
@config_path = path
|
52
|
+
begin
|
53
|
+
# This lets us get the actual config values without needing to
|
54
|
+
# know the service name
|
55
|
+
parsed_hocon = Hocon.load(path)[service_name]
|
56
|
+
rescue Hocon::ConfigError => e
|
57
|
+
raise "Hocon data in '#{path}' failed to load.\n Error: '#{e.message}'"
|
58
|
+
rescue Errno::EACCES
|
59
|
+
raise "Your user doesn't have permission to read #{path}"
|
60
|
+
end
|
61
|
+
|
62
|
+
raise "Could not find service config at #{path}" if parsed_hocon.nil?
|
63
|
+
|
64
|
+
parsed_hocon = parsed_hocon.select { |key, _| config_keys.include?(key) }
|
65
|
+
|
66
|
+
@data = @data.merge(parsed_hocon)
|
67
|
+
end
|
68
|
+
|
69
|
+
def load_env_config
|
70
|
+
raise "load_env_config should be defined in the service class"
|
71
|
+
end
|
72
|
+
|
73
|
+
def natural?(num)
|
74
|
+
num.is_a?(Integer) && num.positive?
|
75
|
+
end
|
76
|
+
|
77
|
+
def validate
|
78
|
+
required_keys.each do |k|
|
79
|
+
next unless @data[k].nil?
|
80
|
+
raise Bolt::ValidationError, "You must configure #{k} in #{@config_path}"
|
81
|
+
end
|
82
|
+
|
83
|
+
unless natural?(@data['port'])
|
84
|
+
raise Bolt::ValidationError, "Configured 'port' must be a valid integer greater than 0"
|
85
|
+
end
|
86
|
+
ssl_keys.each do |sk|
|
87
|
+
unless File.file?(@data[sk]) && File.readable?(@data[sk])
|
88
|
+
raise Bolt::ValidationError, "Configured #{sk} must be a valid filepath"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
unless @data['ssl-cipher-suites'].is_a?(Array)
|
93
|
+
raise Bolt::ValidationError, "Configured 'ssl-cipher-suites' must be an array of cipher suite names"
|
94
|
+
end
|
95
|
+
|
96
|
+
unless @data['whitelist'].nil? || @data['whitelist'].is_a?(Array)
|
97
|
+
raise Bolt::ValidationError, "Configured 'whitelist' must be an array of names"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def [](key)
|
102
|
+
@data[key]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/bolt_server/config.rb
CHANGED
@@ -1,70 +1,45 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'hocon'
|
4
|
+
require 'bolt_server/base_config'
|
4
5
|
require 'bolt/error'
|
5
6
|
|
6
7
|
module BoltServer
|
7
|
-
class Config
|
8
|
-
|
9
|
-
|
10
|
-
'cache-dir', 'file-server-conn-timeout', 'file-server-uri'].freeze
|
11
|
-
|
12
|
-
ENV_KEYS = ['ssl-cert', 'ssl-key', 'ssl-ca-cert', 'loglevel',
|
13
|
-
'concurrency', 'file-server-conn-timeout', 'file-server-uri'].freeze
|
14
|
-
|
15
|
-
DEFAULTS = {
|
16
|
-
'host' => '127.0.0.1',
|
17
|
-
'port' => 62658,
|
18
|
-
'ssl-cipher-suites' => ['ECDHE-ECDSA-AES256-GCM-SHA384',
|
19
|
-
'ECDHE-RSA-AES256-GCM-SHA384',
|
20
|
-
'ECDHE-ECDSA-CHACHA20-POLY1305',
|
21
|
-
'ECDHE-RSA-CHACHA20-POLY1305',
|
22
|
-
'ECDHE-ECDSA-AES128-GCM-SHA256',
|
23
|
-
'ECDHE-RSA-AES128-GCM-SHA256',
|
24
|
-
'ECDHE-ECDSA-AES256-SHA384',
|
25
|
-
'ECDHE-RSA-AES256-SHA384',
|
26
|
-
'ECDHE-ECDSA-AES128-SHA256',
|
27
|
-
'ECDHE-RSA-AES128-SHA256'],
|
28
|
-
'loglevel' => 'notice',
|
29
|
-
'concurrency' => 100,
|
30
|
-
'cache-dir' => "/opt/puppetlabs/server/data/bolt-server/cache",
|
31
|
-
'file-server-conn-timeout' => 120
|
32
|
-
}.freeze
|
33
|
-
|
34
|
-
CONFIG_KEYS.each do |key|
|
35
|
-
define_method(key.tr('-', '_').to_sym) do
|
36
|
-
@data[key]
|
37
|
-
end
|
8
|
+
class Config < BoltServer::BaseConfig
|
9
|
+
def config_keys
|
10
|
+
super + %w[concurrency cache-dir file-server-conn-timeout file-server-uri]
|
38
11
|
end
|
39
12
|
|
40
|
-
def
|
41
|
-
|
42
|
-
@data = @data.merge(config.select { |key, _| CONFIG_KEYS.include?(key) }) if config
|
43
|
-
@config_path = nil
|
13
|
+
def env_keys
|
14
|
+
super + %w[concurrency file-server-conn-timeout file-server-uri]
|
44
15
|
end
|
45
16
|
|
46
|
-
def
|
47
|
-
|
48
|
-
|
49
|
-
parsed_hocon = Hocon.load(path)['bolt-server']
|
50
|
-
rescue Hocon::ConfigError => e
|
51
|
-
raise "Hocon data in '#{path}' failed to load.\n Error: '#{e.message}'"
|
52
|
-
rescue Errno::EACCES
|
53
|
-
raise "Your user doesn't have permission to read #{path}"
|
54
|
-
end
|
17
|
+
def int_keys
|
18
|
+
%w[concurrency file-server-conn-timeout]
|
19
|
+
end
|
55
20
|
|
56
|
-
|
21
|
+
def defaults
|
22
|
+
super.merge(
|
23
|
+
'port' => 62658,
|
24
|
+
'concurrency' => 100,
|
25
|
+
'cache-dir' => "/opt/puppetlabs/server/data/bolt-server/cache",
|
26
|
+
'file-server-conn-timeout' => 120
|
27
|
+
)
|
28
|
+
end
|
57
29
|
|
58
|
-
|
30
|
+
def required_keys
|
31
|
+
super + %w[file-server-uri]
|
32
|
+
end
|
59
33
|
|
60
|
-
|
34
|
+
def service_name
|
35
|
+
'bolt-server'
|
61
36
|
end
|
62
37
|
|
63
38
|
def load_env_config
|
64
|
-
|
39
|
+
env_keys.each do |key|
|
65
40
|
transformed_key = "BOLT_#{key.tr('-', '_').upcase}"
|
66
41
|
next unless ENV.key?(transformed_key)
|
67
|
-
@data[key] = if
|
42
|
+
@data[key] = if int_keys.include?(key)
|
68
43
|
ENV[transformed_key].to_i
|
69
44
|
else
|
70
45
|
ENV[transformed_key]
|
@@ -72,47 +47,16 @@ module BoltServer
|
|
72
47
|
end
|
73
48
|
end
|
74
49
|
|
75
|
-
def natural?(num)
|
76
|
-
num.is_a?(Integer) && num.positive?
|
77
|
-
end
|
78
|
-
|
79
50
|
def validate
|
80
|
-
|
81
|
-
required_keys = ssl_keys + ['file-server-uri']
|
51
|
+
super
|
82
52
|
|
83
|
-
|
84
|
-
next unless @data[k].nil?
|
85
|
-
raise Bolt::ValidationError, "You must configure #{k} in #{@config_path}"
|
86
|
-
end
|
87
|
-
|
88
|
-
unless natural?(port)
|
89
|
-
raise Bolt::ValidationError, "Configured 'port' must be a valid integer greater than 0"
|
90
|
-
end
|
91
|
-
ssl_keys.each do |sk|
|
92
|
-
unless File.file?(@data[sk]) && File.readable?(@data[sk])
|
93
|
-
raise Bolt::ValidationError, "Configured #{sk} must be a valid filepath"
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
unless ssl_cipher_suites.is_a?(Array)
|
98
|
-
raise Bolt::ValidationError, "Configured 'ssl-cipher-suites' must be an array of cipher suite names"
|
99
|
-
end
|
100
|
-
|
101
|
-
unless whitelist.nil? || whitelist.is_a?(Array)
|
102
|
-
raise Bolt::ValidationError, "Configured 'whitelist' must be an array of names"
|
103
|
-
end
|
104
|
-
|
105
|
-
unless natural?(concurrency)
|
53
|
+
unless natural?(@data['concurrency'])
|
106
54
|
raise Bolt::ValidationError, "Configured 'concurrency' must be a positive integer"
|
107
55
|
end
|
108
56
|
|
109
|
-
unless natural?(
|
57
|
+
unless natural?(@data['file-server-conn-timeout'])
|
110
58
|
raise Bolt::ValidationError, "Configured 'file-server-conn-timeout' must be a positive integer"
|
111
59
|
end
|
112
60
|
end
|
113
|
-
|
114
|
-
def [](key)
|
115
|
-
@data[key]
|
116
|
-
end
|
117
61
|
end
|
118
62
|
end
|
@@ -26,7 +26,7 @@ module BoltServer
|
|
26
26
|
purge_timeout: PURGE_TIMEOUT,
|
27
27
|
purge_ttl: PURGE_TTL)
|
28
28
|
@executor = executor
|
29
|
-
@cache_dir = config
|
29
|
+
@cache_dir = config['cache-dir']
|
30
30
|
@config = config
|
31
31
|
@logger = Logging.logger[self]
|
32
32
|
@cache_dir_mutex = Concurrent::ReadWriteLock.new
|
@@ -48,30 +48,30 @@ module BoltServer
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def ssl_cert
|
51
|
-
@ssl_cert ||= File.read(@config
|
51
|
+
@ssl_cert ||= File.read(@config['ssl-cert'])
|
52
52
|
end
|
53
53
|
|
54
54
|
def ssl_key
|
55
|
-
@ssl_key ||= File.read(@config
|
55
|
+
@ssl_key ||= File.read(@config['ssl-key'])
|
56
56
|
end
|
57
57
|
|
58
58
|
def client
|
59
59
|
@client ||= begin
|
60
|
-
uri = URI(@config
|
60
|
+
uri = URI(@config['file-server-uri'])
|
61
61
|
https = Net::HTTP.new(uri.host, uri.port)
|
62
62
|
https.use_ssl = true
|
63
63
|
https.ssl_version = :TLSv1_2
|
64
|
-
https.ca_file = @config
|
64
|
+
https.ca_file = @config['ssl-ca-cert']
|
65
65
|
https.cert = OpenSSL::X509::Certificate.new(ssl_cert)
|
66
66
|
https.key = OpenSSL::PKey::RSA.new(ssl_key)
|
67
67
|
https.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
68
|
-
https.open_timeout = @config
|
68
|
+
https.open_timeout = @config['file-server-conn-timeout']
|
69
69
|
https
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
73
|
def request_file(path, params, file)
|
74
|
-
uri = "#{@config.
|
74
|
+
uri = "#{@config['file-server-uri'].chomp('/')}#{path}"
|
75
75
|
uri = URI(uri)
|
76
76
|
uri.query = URI.encode_www_form(params)
|
77
77
|
|
data/lib/plan_executor/app.rb
CHANGED
@@ -7,6 +7,7 @@ require 'bolt/executor'
|
|
7
7
|
require 'bolt/inventory'
|
8
8
|
require 'bolt/pal'
|
9
9
|
require 'bolt/puppetdb'
|
10
|
+
require 'plan_executor/applicator'
|
10
11
|
require 'concurrent'
|
11
12
|
require 'json'
|
12
13
|
require 'json-schema'
|
@@ -36,6 +37,8 @@ module PlanExecutor
|
|
36
37
|
# TODO: what should max compiles be set to for apply?
|
37
38
|
@pal = Bolt::PAL.new(modulepath, nil)
|
38
39
|
|
40
|
+
@applicator = PlanExecutor::Applicator.new(@inventory, @executor, nil)
|
41
|
+
|
39
42
|
super(nil)
|
40
43
|
end
|
41
44
|
|
@@ -82,7 +85,7 @@ module PlanExecutor
|
|
82
85
|
# This provides a wait function, which promise doesn't
|
83
86
|
result = Concurrent::Future.execute(executor: @worker) do
|
84
87
|
# Stores result in result for testing
|
85
|
-
@pal.run_plan(name, params, @executor, @inventory, puppetdb_client)
|
88
|
+
@pal.run_plan(name, params, @executor, @inventory, puppetdb_client, @applicator)
|
86
89
|
end
|
87
90
|
|
88
91
|
[200, { status: 'running' }.to_json]
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'bolt/error'
|
4
|
+
|
5
|
+
module PlanExecutor
|
6
|
+
class Applicator
|
7
|
+
def initialize(inventory, executor, config)
|
8
|
+
@inventory = inventory
|
9
|
+
@executor = executor
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def raise_not_implemented(feature)
|
14
|
+
raise Bolt::Error.new("#{feature} not implemented for plan executor service.",
|
15
|
+
'bolt.plan-executor/not-implemented')
|
16
|
+
end
|
17
|
+
|
18
|
+
def apply(_args, _apply_body, _scope)
|
19
|
+
raise_not_implemented("apply")
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_plugin_tarball
|
23
|
+
raise_not_implemented("build_plugin_tarball")
|
24
|
+
end
|
25
|
+
|
26
|
+
def custom_facts_task
|
27
|
+
raise_not_implemented('custom_facts_task')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hocon'
|
4
|
+
require 'bolt_server/base_config'
|
5
|
+
require 'bolt/error'
|
6
|
+
|
7
|
+
module PlanExecutor
|
8
|
+
class Config < BoltServer::BaseConfig
|
9
|
+
def config_keys
|
10
|
+
super + %w[modulepath workers]
|
11
|
+
end
|
12
|
+
|
13
|
+
def defaults
|
14
|
+
super.merge(
|
15
|
+
'port' => 62659,
|
16
|
+
'workers' => 1
|
17
|
+
)
|
18
|
+
end
|
19
|
+
|
20
|
+
def service_name
|
21
|
+
'plan-executor'
|
22
|
+
end
|
23
|
+
|
24
|
+
def load_env_config
|
25
|
+
env_keys.each do |key|
|
26
|
+
transformed_key = "BOLT_#{key.tr('-', '_').upcase}"
|
27
|
+
next unless ENV.key?(transformed_key)
|
28
|
+
@data[key] = ENV[transformed_key]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def validate
|
33
|
+
super
|
34
|
+
unless natural?(@data['workers'])
|
35
|
+
raise Bolt::ValidationError, "Configured 'workers' must be a positive integer"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-01-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -288,7 +288,6 @@ email:
|
|
288
288
|
executables:
|
289
289
|
- bolt
|
290
290
|
- bolt-inventory-pdb
|
291
|
-
- bolt-server
|
292
291
|
extensions: []
|
293
292
|
extra_rdoc_files: []
|
294
293
|
files:
|
@@ -319,7 +318,6 @@ files:
|
|
319
318
|
- bolt-modules/boltlib/types/targetspec.pp
|
320
319
|
- exe/bolt
|
321
320
|
- exe/bolt-inventory-pdb
|
322
|
-
- exe/bolt-server
|
323
321
|
- lib/bolt.rb
|
324
322
|
- lib/bolt/analytics.rb
|
325
323
|
- lib/bolt/applicator.rb
|
@@ -372,6 +370,7 @@ files:
|
|
372
370
|
- lib/bolt/version.rb
|
373
371
|
- lib/bolt_ext/puppetdb_inventory.rb
|
374
372
|
- lib/bolt_server/acl.rb
|
373
|
+
- lib/bolt_server/base_config.rb
|
375
374
|
- lib/bolt_server/config.rb
|
376
375
|
- lib/bolt_server/file_cache.rb
|
377
376
|
- lib/bolt_server/schemas/ssh-run_task.json
|
@@ -387,6 +386,8 @@ files:
|
|
387
386
|
- lib/bolt_spec/plans/mock_executor.rb
|
388
387
|
- lib/bolt_spec/run.rb
|
389
388
|
- lib/plan_executor/app.rb
|
389
|
+
- lib/plan_executor/applicator.rb
|
390
|
+
- lib/plan_executor/config.rb
|
390
391
|
- lib/plan_executor/schemas/run_plan.json
|
391
392
|
- libexec/apply_catalog.rb
|
392
393
|
- libexec/bolt_catalog
|