hybrid_platforms_conductor 33.2.4 → 33.3.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/CHANGELOG.md +12 -0
- data/docs/plugins.md +1 -0
- data/docs/plugins/secrets_reader/keepass.md +62 -0
- data/lib/hybrid_platforms_conductor/deployer.rb +2 -28
- data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/keepass.rb +173 -0
- data/lib/hybrid_platforms_conductor/plugins.rb +1 -0
- data/lib/hybrid_platforms_conductor/safe_merge.rb +37 -0
- data/lib/hybrid_platforms_conductor/topographer/plugins/graphviz.rb +5 -3
- data/lib/hybrid_platforms_conductor/version.rb +1 -1
- data/spec/hybrid_platforms_conductor_test.rb +4 -0
- data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb +8 -6
- data/spec/hybrid_platforms_conductor_test/api/config_spec.rb +48 -38
- data/spec/hybrid_platforms_conductor_test/api/deployer/config_dsl_spec.rb +13 -11
- data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/keepass_spec.rb +719 -0
- data/spec/hybrid_platforms_conductor_test/api/nodes_handler/cmdbs_plugins_api_spec.rb +2 -2
- data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +21 -15
- metadata +158 -139
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c0707386d30d5e671d5ceac5e1fec9d971cdccd2b7057c6ed3a75cb5d8bb6d85
|
|
4
|
+
data.tar.gz: e9e5c023662e7aa9283905f4ae54f4b8995d14f61bea1d844ef4fef32cba68dc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1b70dedf6605d48081ead37771b8f94e29d26334fb1c0f7f15ed8ed70cabc24809b145bd681af9e829cd0c968accd18cf87886987391709a7252908a00104096
|
|
7
|
+
data.tar.gz: cbe9033432aae4b83b4153501efad2330651696ba0fc8b487d21f5927430d481661e5d3bf2c3617ffb20c2ba7e254f82328d4225aeba4f98295873c55fe4cca9
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# [v33.3.0](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.2.4...v33.3.0) (2021-07-02 17:20:58)
|
|
2
|
+
|
|
3
|
+
## Global changes
|
|
4
|
+
### Patches
|
|
5
|
+
|
|
6
|
+
* [[Feature(secrets_reader_keepass)] [#79] Add Keepass secrets reader plugin to get secrets from KeePass databases](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/7ace48653a74f03ed535ee6b41b21242a6454ff3)
|
|
7
|
+
|
|
8
|
+
## Changes for secrets_reader_keepass
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* [[Feature(secrets_reader_keepass)] [#79] Add Keepass secrets reader plugin to get secrets from KeePass databases](https://github.com/sweet-delights/hybrid-platforms-conductor/commit/7ace48653a74f03ed535ee6b41b21242a6454ff3)
|
|
12
|
+
|
|
1
13
|
# [v33.2.4](https://github.com/sweet-delights/hybrid-platforms-conductor/compare/v33.2.3...v33.2.4) (2021-06-23 15:14:20)
|
|
2
14
|
|
|
3
15
|
## Global changes
|
data/docs/plugins.md
CHANGED
|
@@ -196,6 +196,7 @@ Check the [sample plugin file](../lib/hybrid_platforms_conductor/hpc_plugins/sec
|
|
|
196
196
|
|
|
197
197
|
Plugins shipped by default:
|
|
198
198
|
* [`cli`](plugins/secrets_reader/cli.md)
|
|
199
|
+
* [`keepass`](plugins/secrets_reader/keepass.md)
|
|
199
200
|
* [`thycotic`](plugins/secrets_reader/thycotic.md)
|
|
200
201
|
|
|
201
202
|
<a name="test"></a>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# Secrets reader plugin: `keepass`
|
|
2
|
+
|
|
3
|
+
The `keepass` secrets reader plugin retrieves secrets from [KeePass](https://keepass.info/) databases, using an actual KeePass installation with the [KPScript plugin](https://keepass.info/plugins.html#kpscript).
|
|
4
|
+
|
|
5
|
+
It is configured by giving the KPScript command-line (using `use_kpscript_from` config DSL method), the KeePass databases to be read (using `secrets_from_keepass` config DSL method) and uses the `keepass` credential ID to authenticate along with extra environment variables for eventual key files or encrypted passwords.
|
|
6
|
+
|
|
7
|
+
## Config DSL extension
|
|
8
|
+
|
|
9
|
+
### `use_kpscript_from`
|
|
10
|
+
|
|
11
|
+
Provide the KPScript command-line to be used. If KPScript is already in your path, using `KPScript.exe` or `kpscript` should be enough, otherwise the full path to the command-line will be needed. On Windows it is needed to also include double quotes if the path contains spaces (like `"C:\Program Files\KeePass\KPScript.exe"`).
|
|
12
|
+
|
|
13
|
+
It takes a simple `String` as parameter to get the command line.
|
|
14
|
+
|
|
15
|
+
Example:
|
|
16
|
+
```ruby
|
|
17
|
+
use_kpscript_from '/path/to/kpscript'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### `secrets_from_keepass`
|
|
21
|
+
|
|
22
|
+
Define a KeePass database to read secrets from.
|
|
23
|
+
A base group path of the KeePass database can also be specified to only read secrets from this group path.
|
|
24
|
+
|
|
25
|
+
All entries, attachments and sub-groups from the base group will be read as secrets.
|
|
26
|
+
|
|
27
|
+
Can be applied to subset of nodes using the [`for_nodes` DSL method](/docs/config_dsl.md#for_nodes).
|
|
28
|
+
|
|
29
|
+
It takes the following parameters:
|
|
30
|
+
* **database** (`String`): Database file path.
|
|
31
|
+
* **group_path** (`Array<String>`): Group path to extract from [default: `[]`].
|
|
32
|
+
|
|
33
|
+
Example:
|
|
34
|
+
```ruby
|
|
35
|
+
secrets_from_keepass(
|
|
36
|
+
database: '/path/to/database.kdbx',
|
|
37
|
+
group_path: %w[Secrets Automation]
|
|
38
|
+
)
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Used credentials
|
|
42
|
+
|
|
43
|
+
| Credential | Usage
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| `keepass` | Used to get the password to the database. No need to be set if the database opens without password. |
|
|
46
|
+
|
|
47
|
+
## Used Metadata
|
|
48
|
+
|
|
49
|
+
| Metadata | Type | Usage
|
|
50
|
+
| --- | --- | --- |
|
|
51
|
+
|
|
52
|
+
## Used environment variables
|
|
53
|
+
|
|
54
|
+
| Variable | Usage
|
|
55
|
+
| --- | --- |
|
|
56
|
+
| `hpc_key_file_for_keepass` | Optional path to the key file needed to open the database |
|
|
57
|
+
| `hpc_password_enc_for_keepass` | Optional encrypted password needed to open the database |
|
|
58
|
+
|
|
59
|
+
## External tools dependencies
|
|
60
|
+
|
|
61
|
+
* [KeePass](https://keepass.info/) to open databases.
|
|
62
|
+
* [KPScript KeePass plugin](https://keepass.info/plugins.html#kpscript) to query KeePass API.
|
|
@@ -9,6 +9,7 @@ require 'hybrid_platforms_conductor/logger_helpers'
|
|
|
9
9
|
require 'hybrid_platforms_conductor/nodes_handler'
|
|
10
10
|
require 'hybrid_platforms_conductor/services_handler'
|
|
11
11
|
require 'hybrid_platforms_conductor/plugins'
|
|
12
|
+
require 'hybrid_platforms_conductor/safe_merge'
|
|
12
13
|
|
|
13
14
|
module HybridPlatformsConductor
|
|
14
15
|
|
|
@@ -500,34 +501,7 @@ module HybridPlatformsConductor
|
|
|
500
501
|
|
|
501
502
|
private
|
|
502
503
|
|
|
503
|
-
|
|
504
|
-
# Safe-merging is done by:
|
|
505
|
-
# * Merging values that are hashes.
|
|
506
|
-
# * Reporting errors when values conflict.
|
|
507
|
-
# When values are conflicting, the initial hash won't modify those conflicting values and will stop the merge.
|
|
508
|
-
#
|
|
509
|
-
# Parameters::
|
|
510
|
-
# * *hash* (Hash): Hash to be modified merging hash_to_merge
|
|
511
|
-
# * *hash_to_merge* (Hash): Hash to be merged into hash
|
|
512
|
-
# Result::
|
|
513
|
-
# * nil or Array<Object>: nil in case of success, or the keys path leading to a conflicting value in case of error
|
|
514
|
-
def safe_merge(hash, hash_to_merge)
|
|
515
|
-
conflicting_path = nil
|
|
516
|
-
hash_to_merge.each do |key, value_to_merge|
|
|
517
|
-
if hash.key?(key)
|
|
518
|
-
if hash[key].is_a?(Hash) && value_to_merge.is_a?(Hash)
|
|
519
|
-
sub_conflicting_path = safe_merge(hash[key], value_to_merge)
|
|
520
|
-
conflicting_path = [key] + sub_conflicting_path unless sub_conflicting_path.nil?
|
|
521
|
-
elsif hash[key] != value_to_merge
|
|
522
|
-
conflicting_path = [key]
|
|
523
|
-
end
|
|
524
|
-
else
|
|
525
|
-
hash[key] = value_to_merge
|
|
526
|
-
end
|
|
527
|
-
break unless conflicting_path.nil?
|
|
528
|
-
end
|
|
529
|
-
conflicting_path
|
|
530
|
-
end
|
|
504
|
+
include SafeMerge
|
|
531
505
|
|
|
532
506
|
# Get the list of retriable errors a node got from deployment logs.
|
|
533
507
|
# Useful to know if an error is non-deterministic (due to external and temporary factors).
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
require 'base64'
|
|
2
|
+
require 'nokogiri'
|
|
3
|
+
require 'tempfile'
|
|
4
|
+
require 'keepass_kpscript'
|
|
5
|
+
require 'zlib'
|
|
6
|
+
require 'hybrid_platforms_conductor/credentials'
|
|
7
|
+
require 'hybrid_platforms_conductor/safe_merge'
|
|
8
|
+
require 'hybrid_platforms_conductor/secrets_reader'
|
|
9
|
+
|
|
10
|
+
module HybridPlatformsConductor
|
|
11
|
+
|
|
12
|
+
module HpcPlugins
|
|
13
|
+
|
|
14
|
+
module SecretsReader
|
|
15
|
+
|
|
16
|
+
# Get secrets from a KeePass database
|
|
17
|
+
class Keepass < HybridPlatformsConductor::SecretsReader
|
|
18
|
+
|
|
19
|
+
include SafeMerge
|
|
20
|
+
|
|
21
|
+
# Extend the Config DSL
|
|
22
|
+
module ConfigDSLExtension
|
|
23
|
+
|
|
24
|
+
# List of defined KeePass secrets. Each info has the following properties:
|
|
25
|
+
# * *nodes_selectors_stack* (Array<Object>): Stack of nodes selectors impacted by this rule.
|
|
26
|
+
# * *database* (String): Database file path.
|
|
27
|
+
# * *group_path* (Array<String>): Group path to extract from.
|
|
28
|
+
# Array< Hash<Symbol, Object> >
|
|
29
|
+
attr_reader :keepass_secrets
|
|
30
|
+
|
|
31
|
+
# String: The KPScript command line
|
|
32
|
+
attr_reader :kpscript
|
|
33
|
+
|
|
34
|
+
# Mixin initializer
|
|
35
|
+
def init_keepass_config
|
|
36
|
+
@keepass_secrets = []
|
|
37
|
+
@kpscript = nil
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Set the KPScript command line
|
|
41
|
+
#
|
|
42
|
+
# Parameters::
|
|
43
|
+
# * *cmd* (String): KPScript command line
|
|
44
|
+
def use_kpscript_from(cmd)
|
|
45
|
+
@kpscript = cmd
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Set a KeePass database configuration
|
|
49
|
+
#
|
|
50
|
+
# Parameters::
|
|
51
|
+
# * *database* (String): Database file path.
|
|
52
|
+
# * *group_path* (Array<String>): Group path to extract from [default: []].
|
|
53
|
+
def secrets_from_keepass(database:, group_path: [])
|
|
54
|
+
@keepass_secrets << {
|
|
55
|
+
nodes_selectors_stack: current_nodes_selectors_stack,
|
|
56
|
+
database: database,
|
|
57
|
+
group_path: group_path
|
|
58
|
+
}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
Config.extend_config_dsl_with ConfigDSLExtension, :init_keepass_config
|
|
64
|
+
|
|
65
|
+
# Return secrets for a given service to be deployed on a node.
|
|
66
|
+
# [API] - This method is mandatory
|
|
67
|
+
# [API] - The following API components are accessible:
|
|
68
|
+
# * *@config* (Config): Main configuration API.
|
|
69
|
+
# * *@cmd_runner* (CmdRunner): Command Runner API.
|
|
70
|
+
# * *@nodes_handler* (NodesHandler): Nodes handler API.
|
|
71
|
+
#
|
|
72
|
+
# Parameters::
|
|
73
|
+
# * *node* (String): Node to be deployed
|
|
74
|
+
# * *service* (String): Service to be deployed
|
|
75
|
+
# Result::
|
|
76
|
+
# * Hash: The secrets
|
|
77
|
+
def secrets_for(node, service)
|
|
78
|
+
secrets = {}
|
|
79
|
+
# As we are dealing with global secrets, cache the reading for performance between nodes and services.
|
|
80
|
+
# Keep secrets cache grouped by URL/ID
|
|
81
|
+
@secrets = {} unless defined?(@secrets)
|
|
82
|
+
@nodes_handler.select_confs_for_node(node, @config.keepass_secrets).each do |keepass_secrets_info|
|
|
83
|
+
secret_id = "#{keepass_secrets_info[:database]}:#{keepass_secrets_info[:group_path].join('/')}"
|
|
84
|
+
unless @secrets.key?(secret_id)
|
|
85
|
+
raise 'Missing KPScript configuration. Please use use_kpscript_from to set it.' if @config.kpscript.nil?
|
|
86
|
+
|
|
87
|
+
Credentials.with_credentials_for(:keepass, @logger, @logger_stderr) do |_user, password|
|
|
88
|
+
Tempfile.create('hpc_keepass') do |xml_file|
|
|
89
|
+
key_file = ENV['hpc_key_file_for_keepass']
|
|
90
|
+
password_enc = ENV['hpc_password_enc_for_keepass']
|
|
91
|
+
keepass_credentials = {}
|
|
92
|
+
keepass_credentials[:password] = password if password
|
|
93
|
+
keepass_credentials[:password_enc] = password_enc if password_enc
|
|
94
|
+
keepass_credentials[:key_file] = key_file if key_file
|
|
95
|
+
KeepassKpscript.
|
|
96
|
+
use(@config.kpscript, debug: log_debug?).
|
|
97
|
+
open(keepass_secrets_info[:database], **keepass_credentials).
|
|
98
|
+
export('KeePass XML (2.x)', xml_file.path, group_path: keepass_secrets_info[:group_path].empty? ? nil : keepass_secrets_info[:group_path])
|
|
99
|
+
@secrets[secret_id] = parse_xml_secrets(Nokogiri::XML(xml_file).at_xpath('KeePassFile/Root/Group'))
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
conflicting_path = safe_merge(secrets, @secrets[secret_id])
|
|
104
|
+
raise "Secret set at path #{conflicting_path.join('->')} by #{keepass_secrets_info[:database]}#{keepass_secrets_info[:group_path].empty? ? '' : " from group #{keepass_secrets_info[:group_path].join('/')}"} for service #{service} on node #{node} has conflicting values (#{log_debug? ? "#{@secrets[secret_id].dig(*conflicting_path)} != #{secrets.dig(*conflicting_path)}" : 'set debug for value details'})." unless conflicting_path.nil?
|
|
105
|
+
end
|
|
106
|
+
secrets
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
private
|
|
110
|
+
|
|
111
|
+
# List of fields to include in the secrets and their corresponding XML name
|
|
112
|
+
FIELDS = {
|
|
113
|
+
notes: 'Notes',
|
|
114
|
+
password: 'Password',
|
|
115
|
+
url: 'URL',
|
|
116
|
+
user_name: 'UserName'
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# Parse XML secrets from a Nokogiri XML group node
|
|
120
|
+
#
|
|
121
|
+
# Parameters::
|
|
122
|
+
# * *group* (Nokogiri::XML::Element): The group to parse
|
|
123
|
+
# Result::
|
|
124
|
+
# * Hash: The JSON secrets parsed from this group
|
|
125
|
+
def parse_xml_secrets(group)
|
|
126
|
+
# Parse all entries
|
|
127
|
+
group.xpath('Entry').map do |entry|
|
|
128
|
+
[
|
|
129
|
+
entry.at_xpath('String/Key[contains(.,"Title")]/../Value').text,
|
|
130
|
+
FIELDS.map do |property, field|
|
|
131
|
+
value = entry.at_xpath("String/Key[contains(.,\"#{field}\")]/../Value")&.text
|
|
132
|
+
if value.nil? || value.empty?
|
|
133
|
+
nil
|
|
134
|
+
else
|
|
135
|
+
[
|
|
136
|
+
property.to_s,
|
|
137
|
+
value
|
|
138
|
+
]
|
|
139
|
+
end
|
|
140
|
+
end.compact.to_h.merge(
|
|
141
|
+
entry.xpath('Binary').map do |binary|
|
|
142
|
+
binary_meta = group.document.at_xpath("KeePassFile/Meta/Binaries/Binary[@ID=#{Integer(binary.xpath('Value').attr('Ref').value)}]")
|
|
143
|
+
binary_content = Base64.decode64(binary_meta.text)
|
|
144
|
+
if binary_meta.attr('Compressed') == 'True'
|
|
145
|
+
gz = Zlib::GzipReader.new(StringIO.new(binary_content))
|
|
146
|
+
binary_content = gz.read
|
|
147
|
+
gz.close
|
|
148
|
+
end
|
|
149
|
+
[
|
|
150
|
+
binary.xpath('Key').text,
|
|
151
|
+
binary_content
|
|
152
|
+
]
|
|
153
|
+
end.to_h
|
|
154
|
+
)
|
|
155
|
+
]
|
|
156
|
+
end.to_h.merge(
|
|
157
|
+
# Add children groups
|
|
158
|
+
group.xpath('Group').map do |sub_group|
|
|
159
|
+
[
|
|
160
|
+
sub_group.at_xpath('Name').text,
|
|
161
|
+
parse_xml_secrets(sub_group)
|
|
162
|
+
]
|
|
163
|
+
end.to_h
|
|
164
|
+
)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module HybridPlatformsConductor
|
|
2
|
+
|
|
3
|
+
# Provide an easy way to safe-merge hashes
|
|
4
|
+
module SafeMerge
|
|
5
|
+
|
|
6
|
+
# Safe-merge 2 hashes.
|
|
7
|
+
# Safe-merging is done by:
|
|
8
|
+
# * Merging values that are hashes.
|
|
9
|
+
# * Reporting errors when values conflict.
|
|
10
|
+
# When values are conflicting, the initial hash won't modify those conflicting values and will stop the merge.
|
|
11
|
+
#
|
|
12
|
+
# Parameters::
|
|
13
|
+
# * *hash* (Hash): Hash to be modified merging hash_to_merge
|
|
14
|
+
# * *hash_to_merge* (Hash): Hash to be merged into hash
|
|
15
|
+
# Result::
|
|
16
|
+
# * nil or Array<Object>: nil in case of success, or the keys path leading to a conflicting value in case of error
|
|
17
|
+
def safe_merge(hash, hash_to_merge)
|
|
18
|
+
conflicting_path = nil
|
|
19
|
+
hash_to_merge.each do |key, value_to_merge|
|
|
20
|
+
if hash.key?(key)
|
|
21
|
+
if hash[key].is_a?(Hash) && value_to_merge.is_a?(Hash)
|
|
22
|
+
sub_conflicting_path = safe_merge(hash[key], value_to_merge)
|
|
23
|
+
conflicting_path = [key] + sub_conflicting_path unless sub_conflicting_path.nil?
|
|
24
|
+
elsif hash[key] != value_to_merge
|
|
25
|
+
conflicting_path = [key]
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
hash[key] = value_to_merge
|
|
29
|
+
end
|
|
30
|
+
break unless conflicting_path.nil?
|
|
31
|
+
end
|
|
32
|
+
conflicting_path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
@@ -17,9 +17,11 @@ module HybridPlatformsConductor
|
|
|
17
17
|
@topographer.force_cluster_strict_hierarchy
|
|
18
18
|
# Write a Graphviz file
|
|
19
19
|
File.open(file_name, 'w') do |f|
|
|
20
|
-
f.puts
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
f.puts <<~EO_GRAPHVIZ
|
|
21
|
+
digraph unix {
|
|
22
|
+
size="6,6";
|
|
23
|
+
node [style=filled];
|
|
24
|
+
EO_GRAPHVIZ
|
|
23
25
|
# First write the definition of all nodes
|
|
24
26
|
# Find all nodes belonging to no cluster
|
|
25
27
|
orphan_nodes = @topographer.nodes_graph.keys
|
|
@@ -101,6 +101,10 @@ module HybridPlatformsConductorTest
|
|
|
101
101
|
ENV.delete 'hpc_user_for_thycotic'
|
|
102
102
|
ENV.delete 'hpc_password_for_thycotic'
|
|
103
103
|
ENV.delete 'hpc_domain_for_thycotic'
|
|
104
|
+
ENV.delete 'hpc_user_for_keepass'
|
|
105
|
+
ENV.delete 'hpc_password_for_keepass'
|
|
106
|
+
ENV.delete 'hpc_password_enc_for_keepass'
|
|
107
|
+
ENV.delete 'hpc_key_file_for_keepass'
|
|
104
108
|
ENV.delete 'hpc_certificates'
|
|
105
109
|
ENV.delete 'hpc_interactive'
|
|
106
110
|
ENV.delete 'hpc_test_cookbooks_path'
|
data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/config_dsl_spec.rb
CHANGED
|
@@ -13,10 +13,10 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
it 'returns 1 defined gateway with its content' do
|
|
16
|
-
ssh_gateway =
|
|
16
|
+
ssh_gateway = <<~EO_CONFIG
|
|
17
17
|
Host gateway
|
|
18
18
|
Hostname mygateway.com
|
|
19
|
-
|
|
19
|
+
EO_CONFIG
|
|
20
20
|
with_repository do
|
|
21
21
|
with_platforms "gateway :gateway_1, '#{ssh_gateway}'" do
|
|
22
22
|
expect(test_config.ssh_for_gateway(:gateway_1)).to eq ssh_gateway
|
|
@@ -34,10 +34,12 @@ describe HybridPlatformsConductor::ActionsExecutor do
|
|
|
34
34
|
|
|
35
35
|
it 'returns several defined gateways' do
|
|
36
36
|
with_repository do
|
|
37
|
-
with_platforms
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
37
|
+
with_platforms(
|
|
38
|
+
<<~EO_CONFIG
|
|
39
|
+
gateway :gateway_1, ''
|
|
40
|
+
gateway :gateway_2, ''
|
|
41
|
+
EO_CONFIG
|
|
42
|
+
) do
|
|
41
43
|
expect(test_config.known_gateways.sort).to eq %i[gateway_1 gateway_2].sort
|
|
42
44
|
end
|
|
43
45
|
end
|
|
@@ -19,10 +19,12 @@ describe HybridPlatformsConductor::Config do
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
it 'returns several defined OS images' do
|
|
22
|
-
with_platforms
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
with_platforms(
|
|
23
|
+
<<~EO_CONFIG
|
|
24
|
+
os_image :image_1, '/path/to/image_1'
|
|
25
|
+
os_image :image_2, '/path/to/image_2'
|
|
26
|
+
EO_CONFIG
|
|
27
|
+
) do
|
|
26
28
|
expect(test_config.known_os_images.sort).to eq %i[image_1 image_2].sort
|
|
27
29
|
end
|
|
28
30
|
end
|
|
@@ -49,11 +51,13 @@ describe HybridPlatformsConductor::Config do
|
|
|
49
51
|
end
|
|
50
52
|
|
|
51
53
|
it 'includes several configuration files' do
|
|
52
|
-
with_platforms
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
with_platforms(
|
|
55
|
+
<<~'EO_CONFIG'
|
|
56
|
+
os_image :image_1, '/path/to/image_1'
|
|
57
|
+
include_config_from "#{__dir__}/my_conf_1.rb"
|
|
58
|
+
include_config_from "#{__dir__}/my_conf_2.rb"
|
|
59
|
+
EO_CONFIG
|
|
60
|
+
) do |hybrid_platforms_dir|
|
|
57
61
|
File.write("#{hybrid_platforms_dir}/my_conf_1.rb", <<~'EO_CONFIG')
|
|
58
62
|
os_image :image_4, '/path/to/image_4'
|
|
59
63
|
include_config_from "#{__dir__}/my_conf_3.rb"
|
|
@@ -65,9 +69,7 @@ describe HybridPlatformsConductor::Config do
|
|
|
65
69
|
end
|
|
66
70
|
|
|
67
71
|
it 'applies nodes specific configuration to all nodes by default' do
|
|
68
|
-
with_platforms '
|
|
69
|
-
expect_tests_to_fail :my_test, \'Failure reason\'
|
|
70
|
-
' do
|
|
72
|
+
with_platforms 'expect_tests_to_fail :my_test, \'Failure reason\'' do
|
|
71
73
|
expect(test_config.expected_failures).to eq [
|
|
72
74
|
{
|
|
73
75
|
nodes_selectors_stack: [],
|
|
@@ -79,12 +81,14 @@ describe HybridPlatformsConductor::Config do
|
|
|
79
81
|
end
|
|
80
82
|
|
|
81
83
|
it 'filters nodes specific configuration to nodes sets in a scope' do
|
|
82
|
-
with_platforms
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
84
|
+
with_platforms(
|
|
85
|
+
<<~EO_CONFIG
|
|
86
|
+
for_nodes(%w[node1 node2 node3]) do
|
|
87
|
+
expect_tests_to_fail :my_test_1, 'Failure reason 1'
|
|
88
|
+
end
|
|
89
|
+
expect_tests_to_fail :my_test_2, 'Failure reason 2'
|
|
90
|
+
EO_CONFIG
|
|
91
|
+
) do
|
|
88
92
|
sort_proc = proc { |expected_failure_info| expected_failure_info[:reason] }
|
|
89
93
|
expect(test_config.expected_failures.sort_by(&sort_proc)).to eq [
|
|
90
94
|
{
|
|
@@ -102,14 +106,16 @@ describe HybridPlatformsConductor::Config do
|
|
|
102
106
|
end
|
|
103
107
|
|
|
104
108
|
it 'filters nodes specific configuration in a scoped stack' do
|
|
105
|
-
with_platforms
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
109
|
+
with_platforms(
|
|
110
|
+
<<~EO_CONFIG
|
|
111
|
+
for_nodes(%w[node1 node2 node3]) do
|
|
112
|
+
expect_tests_to_fail :my_test_1, 'Failure reason 1'
|
|
113
|
+
for_nodes(%w[node2 node3 node4]) do
|
|
114
|
+
expect_tests_to_fail :my_test_2, 'Failure reason 2'
|
|
115
|
+
end
|
|
110
116
|
end
|
|
111
|
-
|
|
112
|
-
|
|
117
|
+
EO_CONFIG
|
|
118
|
+
) do
|
|
113
119
|
sort_proc = proc { |expected_failure_info| expected_failure_info[:reason] }
|
|
114
120
|
expect(test_config.expected_failures.sort_by(&sort_proc)).to eq [
|
|
115
121
|
{
|
|
@@ -127,13 +133,15 @@ describe HybridPlatformsConductor::Config do
|
|
|
127
133
|
end
|
|
128
134
|
|
|
129
135
|
it 'returns the expected failures correctly' do
|
|
130
|
-
with_platforms
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
136
|
+
with_platforms(
|
|
137
|
+
<<~EO_CONFIG
|
|
138
|
+
expect_tests_to_fail :my_test_1, 'Failure reason 1'
|
|
139
|
+
expect_tests_to_fail %i[my_test_2 my_test_3], 'Failure reason 23'
|
|
140
|
+
for_nodes(%w[node1 node2 node3]) do
|
|
141
|
+
expect_tests_to_fail :my_test_4, 'Failure reason 4'
|
|
142
|
+
end
|
|
143
|
+
EO_CONFIG
|
|
144
|
+
) do
|
|
137
145
|
sort_proc = proc { |expected_failure_info| expected_failure_info[:reason] }
|
|
138
146
|
expect(test_config.expected_failures.sort_by(&sort_proc)).to eq [
|
|
139
147
|
{
|
|
@@ -156,12 +164,14 @@ describe HybridPlatformsConductor::Config do
|
|
|
156
164
|
end
|
|
157
165
|
|
|
158
166
|
it 'returns the deployment schedules correctly' do
|
|
159
|
-
with_platforms
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
167
|
+
with_platforms(
|
|
168
|
+
<<~EO_CONFIG
|
|
169
|
+
deployment_schedule(IceCube::Schedule.new(Time.parse('2020-05-01 11:22:33 UTC')))
|
|
170
|
+
for_nodes(%w[node1 node2 node3]) do
|
|
171
|
+
deployment_schedule(IceCube::Schedule.new(Time.parse('2020-05-02 22:33:44 UTC')))
|
|
172
|
+
end
|
|
173
|
+
EO_CONFIG
|
|
174
|
+
) do
|
|
165
175
|
sort_proc = proc { |deployment_schedule_info| deployment_schedule_info[:schedule].to_ical }
|
|
166
176
|
expect(test_config.deployment_schedules.sort_by(&sort_proc)).to eq [
|
|
167
177
|
{
|