hybrid_platforms_conductor 32.16.3 → 33.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.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +42 -0
  3. data/README.md +6 -3
  4. data/bin/last_deploys +4 -1
  5. data/bin/nodes_to_deploy +5 -5
  6. data/docs/config_dsl.md +45 -1
  7. data/docs/executables.md +6 -7
  8. data/docs/executables/check-node.md +3 -3
  9. data/docs/executables/deploy.md +3 -3
  10. data/docs/executables/dump_nodes_json.md +3 -3
  11. data/docs/executables/test.md +3 -3
  12. data/docs/executables/topograph.md +3 -3
  13. data/docs/gen/mermaid/README.md-0.png +0 -0
  14. data/docs/gen/mermaid/docs/executables/check-node.md-0.png +0 -0
  15. data/docs/gen/mermaid/docs/executables/deploy.md-0.png +0 -0
  16. data/docs/gen/mermaid/docs/executables/free_ips.md-0.png +0 -0
  17. data/docs/gen/mermaid/docs/executables/get_impacted_nodes.md-0.png +0 -0
  18. data/docs/gen/mermaid/docs/executables/last_deploys.md-0.png +0 -0
  19. data/docs/gen/mermaid/docs/executables/nodes_to_deploy.md-0.png +0 -0
  20. data/docs/gen/mermaid/docs/executables/report.md-0.png +0 -0
  21. data/docs/gen/mermaid/docs/executables/run.md-0.png +0 -0
  22. data/docs/gen/mermaid/docs/executables/ssh_config.md-0.png +0 -0
  23. data/docs/gen/mermaid/docs/executables/test.md-0.png +0 -0
  24. data/docs/plugins.md +47 -0
  25. data/docs/plugins/connector/ssh.md +1 -1
  26. data/docs/plugins/log/remote_fs.md +26 -0
  27. data/docs/plugins/secrets_reader/cli.md +31 -0
  28. data/docs/plugins/secrets_reader/thycotic.md +46 -0
  29. data/docs/plugins/test/bitbucket_conf.md +1 -1
  30. data/docs/plugins/test/check_deploy_and_idempotence.md +1 -1
  31. data/docs/plugins/test/connection.md +1 -0
  32. data/docs/plugins/test/deploy_removes_root_access.md +1 -1
  33. data/docs/plugins/test/file_system.md +1 -0
  34. data/docs/plugins/test/github_ci.md +48 -0
  35. data/docs/plugins/test/hostname.md +1 -0
  36. data/docs/plugins/test/ip.md +1 -0
  37. data/docs/plugins/test/jenkins_ci_conf.md +1 -1
  38. data/docs/plugins/test/jenkins_ci_masters_ok.md +1 -1
  39. data/docs/plugins/test/local_users.md +1 -0
  40. data/docs/plugins/test/mounts.md +1 -0
  41. data/docs/plugins/test/orphan_files.md +1 -0
  42. data/docs/plugins/test/ports.md +1 -0
  43. data/docs/plugins/test/spectre.md +1 -0
  44. data/docs/plugins/test/vulnerabilities.md +1 -0
  45. data/lib/hybrid_platforms_conductor/actions_executor.rb +8 -1
  46. data/lib/hybrid_platforms_conductor/common_config_dsl/github.rb +62 -0
  47. data/lib/hybrid_platforms_conductor/deployer.rb +193 -141
  48. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +3 -3
  49. data/lib/hybrid_platforms_conductor/hpc_plugins/log/my_log_plugin.rb.sample +100 -0
  50. data/lib/hybrid_platforms_conductor/hpc_plugins/log/remote_fs.rb +179 -0
  51. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/cli.rb +75 -0
  52. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/my_secrets_reader_plugin.rb.sample +46 -0
  53. data/lib/hybrid_platforms_conductor/hpc_plugins/secrets_reader/thycotic.rb +87 -0
  54. data/lib/hybrid_platforms_conductor/hpc_plugins/test/check_deploy_and_idempotence.rb +1 -1
  55. data/lib/hybrid_platforms_conductor/hpc_plugins/test/connection.rb +3 -1
  56. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +7 -20
  57. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +1 -1
  58. data/lib/hybrid_platforms_conductor/hpc_plugins/test/file_system.rb +2 -1
  59. data/lib/hybrid_platforms_conductor/hpc_plugins/test/github_ci.rb +32 -0
  60. data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +3 -1
  61. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +3 -1
  62. data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +3 -1
  63. data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +3 -1
  64. data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +3 -1
  65. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ports.rb +3 -1
  66. data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +3 -1
  67. data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +2 -1
  68. data/lib/hybrid_platforms_conductor/log.rb +31 -0
  69. data/lib/hybrid_platforms_conductor/plugins.rb +1 -0
  70. data/lib/hybrid_platforms_conductor/secrets_reader.rb +31 -0
  71. data/lib/hybrid_platforms_conductor/test_only_remote_node.rb +18 -0
  72. data/lib/hybrid_platforms_conductor/version.rb +1 -1
  73. data/spec/hybrid_platforms_conductor_test.rb +27 -6
  74. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/connections_spec.rb +3 -3
  75. data/spec/hybrid_platforms_conductor_test/api/deployer/config_dsl_spec.rb +46 -4
  76. data/spec/hybrid_platforms_conductor_test/api/deployer/deploy_spec.rb +187 -212
  77. data/spec/hybrid_platforms_conductor_test/api/deployer/log_plugins/remote_fs_spec.rb +223 -0
  78. data/spec/hybrid_platforms_conductor_test/api/deployer/provisioner_spec.rb +4 -4
  79. data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/cli_spec.rb +63 -0
  80. data/spec/hybrid_platforms_conductor_test/api/deployer/secrets_reader_plugins/thycotic_spec.rb +253 -0
  81. data/spec/hybrid_platforms_conductor_test/api/tests_runner/global_spec.rb +1 -1
  82. data/spec/hybrid_platforms_conductor_test/api/tests_runner/test_plugins/github_ci_spec.rb +72 -0
  83. data/spec/hybrid_platforms_conductor_test/executables/last_deploys_spec.rb +146 -98
  84. data/spec/hybrid_platforms_conductor_test/executables/nodes_to_deploy_spec.rb +240 -83
  85. data/spec/hybrid_platforms_conductor_test/executables/options/common_spec.rb +2 -1
  86. data/spec/hybrid_platforms_conductor_test/executables/options/deployer_spec.rb +0 -182
  87. data/spec/hybrid_platforms_conductor_test/helpers/connector_ssh_helpers.rb +1 -1
  88. data/spec/hybrid_platforms_conductor_test/helpers/deployer_helpers.rb +40 -53
  89. data/spec/hybrid_platforms_conductor_test/helpers/deployer_test_helpers.rb +251 -15
  90. data/spec/hybrid_platforms_conductor_test/test_log_no_read_plugin.rb +82 -0
  91. data/spec/hybrid_platforms_conductor_test/test_log_plugin.rb +103 -0
  92. data/spec/hybrid_platforms_conductor_test/test_secrets_reader_plugin.rb +45 -0
  93. metadata +41 -2
@@ -136,7 +136,7 @@ module HybridPlatformsConductorTest
136
136
  session_exec: true
137
137
  )
138
138
  with_test_platform(
139
- { nodes: { 'node' => { meta: { host_ip: '192.168.42.42', ssh_session_exec: session_exec ? 'true' : 'false' } } } },
139
+ { nodes: { 'node' => { meta: { host_ip: '192.168.42.42', ssh_session_exec: session_exec } } } },
140
140
  false,
141
141
  additional_config
142
142
  ) do
@@ -68,71 +68,21 @@ module HybridPlatformsConductorTest
68
68
  Hash[nodes.map { |node| [node, [0, 'Release mutex successful', '']] }]
69
69
  end
70
70
 
71
- # Expect a given set of actions to upload log files on a list of nodes
71
+ # Expect a given set of actions to upload log files on a list of nodes (using the test_log log plugin)
72
72
  #
73
73
  # Parameters::
74
74
  # * *actions* (Object): Actions
75
75
  # * *nodes* (String or Array<String>): Node (or list of nodes) that should be checked
76
- # * *sudo* (String or nil): sudo supposed to be used, or nil if none [default: 'sudo -u root']
77
- def expect_actions_to_upload_logs(actions, nodes, sudo: 'sudo -u root')
76
+ def expect_actions_to_upload_logs(actions, nodes)
78
77
  nodes = [nodes] if nodes.is_a?(String)
79
78
  expect(actions.size).to eq nodes.size
80
79
  nodes.each do |node|
81
80
  expect(actions.key?(node)).to eq true
82
- expect(actions[node][:remote_bash]).to eq "#{sudo ? "#{sudo} " : ''}mkdir -p /var/log/deployments"
83
- expect(actions[node][:scp].first[1]).to eq '/var/log/deployments'
84
- expect(actions[node][:scp][:group]).to eq 'root'
85
- expect(actions[node][:scp][:owner]).to eq 'root'
86
- expect(actions[node][:scp][:sudo]).to eq (!sudo.nil?)
81
+ expect(actions[node]).to eq [{ bash: "echo Save test logs to #{node}" }]
87
82
  end
88
83
  Hash[nodes.map { |node| [node, [0, 'Logs uploaded', '']] }]
89
84
  end
90
85
 
91
- # Expect some logs to have the following information.
92
- # Expected logs format:
93
- #
94
- # date: 2019-08-14 17:02:57
95
- # user: muriel
96
- # debug: Yes
97
- # repo_name: my_remote_platform
98
- # commit_id: c0d16b1b7ae286ae4a059185957e08f0ddc95517
99
- # commit_message: Test commit
100
- # diff_files:
101
- # ===== STDOUT =====
102
- # Deploy successful
103
- # ===== STDERR =====
104
- #
105
- # Parameters::
106
- # * *logs* (String): The logs content
107
- # * *stdout* (String): Expected STDOUT
108
- # * *stderr* (String): Expected STDERR
109
- # * *properties* (Hash<Symbol, String or Regexp>): Expected properties values, per name. Values can be exact strings or regexps.
110
- def expect_logs_to_be(logs, stdout, stderr, properties)
111
- lines = logs.split("\n")
112
- idx_stdout = lines.index('===== STDOUT =====')
113
- expect(idx_stdout).not_to eq nil
114
- idx_stderr = lines.index('===== STDERR =====')
115
- expect(idx_stderr).not_to eq nil
116
- logs_properties = Hash[lines[0..idx_stdout - 1].map do |property_line|
117
- property_fields = property_line.split(': ')
118
- [
119
- property_fields.first.to_sym,
120
- property_fields[1..-1].join(': ')
121
- ]
122
- end]
123
- expect(logs_properties.size).to eq properties.size
124
- properties.each do |expected_property, expected_property_value|
125
- expect(logs_properties.key?(expected_property)).to eq true
126
- if expected_property_value.is_a?(String)
127
- expect(logs_properties[expected_property]).to eq expected_property_value
128
- else
129
- expect(logs_properties[expected_property]).to match expected_property_value
130
- end
131
- end
132
- expect(lines[idx_stdout + 1..idx_stderr - 1].join("\n")).to eq stdout
133
- expect(lines[idx_stderr + 1..-1].join("\n")).to eq stderr
134
- end
135
-
136
86
  # Get a test Deployer
137
87
  #
138
88
  # Result::
@@ -142,6 +92,43 @@ module HybridPlatformsConductorTest
142
92
  @deployer
143
93
  end
144
94
 
95
+ # Expect the test services handler to be called to deploy a given list of services
96
+ #
97
+ # Parameters::
98
+ # * *services* (Hash<String, Array<String> >): List of services to be expected, per node name
99
+ def expect_services_handler_to_deploy(services)
100
+ expect(test_services_handler).to receive(:deploy_allowed?).with(
101
+ services: services,
102
+ secrets: {},
103
+ local_environment: false
104
+ ) do
105
+ nil
106
+ end
107
+ expect(test_services_handler).to receive(:package).with(
108
+ services: services,
109
+ secrets: {},
110
+ local_environment: false
111
+ )
112
+ expect(test_services_handler).to receive(:prepare_for_deploy).with(
113
+ services: services,
114
+ secrets: {},
115
+ local_environment: false,
116
+ why_run: false
117
+ )
118
+ services.each do |node, services|
119
+ expect(test_services_handler).to receive(:actions_to_deploy_on).with(node, services, false) do
120
+ [{ bash: "echo \"Deploying on #{node}\"" }]
121
+ end
122
+ expect(test_services_handler).to receive(:log_info_for).with(node, services) do
123
+ {
124
+ repo_name_0: 'platform',
125
+ commit_id_0: '123456',
126
+ commit_message_0: "Test commit for #{node}: #{services.join(', ')}"
127
+ }
128
+ end
129
+ end
130
+ end
131
+
145
132
  end
146
133
 
147
134
  end
@@ -69,7 +69,7 @@ module HybridPlatformsConductorTest
69
69
  }
70
70
  end
71
71
  end
72
- actions << proc { |actions_per_nodes| expect_actions_to_upload_logs(actions_per_nodes, services.keys, sudo: sudo) }
72
+ actions << proc { |actions_per_nodes| expect_actions_to_upload_logs(actions_per_nodes, services.keys) }
73
73
  end
74
74
  actions
75
75
  end
@@ -78,6 +78,8 @@ module HybridPlatformsConductorTest
78
78
  #
79
79
  # Parameters::
80
80
  # * *nodes_info* (Hash): Node info to give the platform [default: 1 node having 1 service]
81
+ # * *expect_services_to_deploy* (Hash<String,Array<String>>): Expected services to be deployed [default: all services from nodes_info]
82
+ # * *expect_deploy_allowed* (Boolean): Should we expect the call to deploy_allowed? [default: true]
81
83
  # * *expect_package* (Boolean): Should we expect packaging? [default: true]
82
84
  # * *expect_prepare_for_deploy* (Boolean): Should we expect calls to prepare for deploy? [default: true]
83
85
  # * *expect_connections_to_nodes* (Boolean): Should we expect connections to nodes? [default: true]
@@ -95,6 +97,8 @@ module HybridPlatformsConductorTest
95
97
  # * *repository* (String): Path to the repository
96
98
  def with_platform_to_deploy(
97
99
  nodes_info: { nodes: { 'node' => { services: %w[service] } } },
100
+ expect_services_to_deploy: Hash[nodes_info[:nodes].map { |node, node_info| [node, node_info[:services]] }],
101
+ expect_deploy_allowed: true,
98
102
  expect_package: true,
99
103
  expect_prepare_for_deploy: true,
100
104
  expect_connections_to_nodes: true,
@@ -109,12 +113,9 @@ module HybridPlatformsConductorTest
109
113
  additional_config: ''
110
114
  )
111
115
  platform_name = check_mode ? 'platform' : 'my_remote_platform'
112
- with_test_platform(nodes_info, !check_mode, additional_config) do |repository|
116
+ with_test_platform(nodes_info, !check_mode, additional_config + "\nsend_logs_to :test_log") do |repository|
113
117
  # Mock the ServicesHandler accesses
114
- expect_services_to_deploy = Hash[nodes_info[:nodes].map do |node, node_info|
115
- [node, node_info[:services]]
116
- end]
117
- unless check_mode
118
+ if !check_mode && expect_deploy_allowed
118
119
  expect(test_services_handler).to receive(:deploy_allowed?).with(
119
120
  services: expect_services_to_deploy,
120
121
  secrets: expect_secrets,
@@ -144,7 +145,7 @@ module HybridPlatformsConductorTest
144
145
  end
145
146
  test_deployer.use_why_run = true if check_mode
146
147
  if expect_connections_to_nodes
147
- with_connections_mocked_on(nodes_info[:nodes].keys) do
148
+ with_connections_mocked_on(expect_services_to_deploy.keys) do
148
149
  expect_actions_executor_runs(expected_actions_for_deploy_on(
149
150
  services: expect_services_to_deploy,
150
151
  check_mode: check_mode,
@@ -218,14 +219,7 @@ module HybridPlatformsConductorTest
218
219
 
219
220
  it 'deploys on 1 node using 1 secret' do
220
221
  with_platform_to_deploy(expect_secrets: { 'secret1' => 'password1' }) do
221
- test_deployer.secrets = [{ 'secret1' => 'password1' }]
222
- expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
223
- end
224
- end
225
-
226
- it 'deploys on 1 node using several secrets' do
227
- with_platform_to_deploy(expect_secrets: { 'secret1' => 'password1', 'secret2' => 'password2' }) do
228
- test_deployer.secrets = [{ 'secret1' => 'password1' }, { 'secret2' => 'password2' }]
222
+ test_deployer.override_secrets('secret1' => 'password1')
229
223
  expect(test_deployer.deploy_on('node')).to eq('node' => expected_deploy_result)
230
224
  end
231
225
  end
@@ -901,6 +895,248 @@ module HybridPlatformsConductorTest
901
895
 
902
896
  end
903
897
 
898
+ context 'checking secrets handling' do
899
+
900
+ it 'calls secrets readers only for nodes and services to be deployed and merges their secrets' do
901
+ register_plugins(
902
+ :secrets_reader,
903
+ {
904
+ secrets_reader1: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
905
+ secrets_reader2: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
906
+ secrets_reader3: HybridPlatformsConductorTest::TestSecretsReaderPlugin
907
+ }
908
+ )
909
+ with_platform_to_deploy(
910
+ nodes_info: {
911
+ nodes: {
912
+ 'node1' => { services: %w[service1 service2] },
913
+ 'node2' => { services: %w[service2 service3] },
914
+ 'node3' => { services: %w[service3] },
915
+ 'node4' => { services: %w[service1 service3] }
916
+ }
917
+ },
918
+ expect_services_to_deploy: {
919
+ 'node1' => %w[service1 service2],
920
+ 'node2' => %w[service2 service3],
921
+ 'node3' => %w[service3]
922
+ },
923
+ expect_secrets: {
924
+ 'node1' => {
925
+ 'service1' => {
926
+ 'secrets_reader1' => 'Secret value',
927
+ 'secrets_reader2' => 'Secret value'
928
+ },
929
+ 'service2' => {
930
+ 'secrets_reader1' => 'Secret value',
931
+ 'secrets_reader2' => 'Secret value'
932
+ }
933
+ },
934
+ 'node2' => {
935
+ 'service2' => {
936
+ 'secrets_reader1' => 'Secret value',
937
+ 'secrets_reader2' => 'Secret value',
938
+ 'secrets_reader3' => 'Secret value'
939
+ },
940
+ 'service3' => {
941
+ 'secrets_reader1' => 'Secret value',
942
+ 'secrets_reader2' => 'Secret value',
943
+ 'secrets_reader3' => 'Secret value'
944
+ }
945
+ },
946
+ 'node3' => {
947
+ 'service3' => {
948
+ 'secrets_reader1' => 'Secret value',
949
+ 'secrets_reader2' => 'Secret value'
950
+ }
951
+ }
952
+ },
953
+ additional_config: <<~EOS
954
+ read_secrets_from %i[secrets_reader1 secrets_reader2]
955
+ for_nodes('node2') { read_secrets_from :secrets_reader3 }
956
+ EOS
957
+ ) do
958
+ TestSecretsReaderPlugin.deployer = test_deployer
959
+ expect(test_deployer.deploy_on(%w[node1 node2 node3])).to eq(
960
+ 'node1' => expected_deploy_result,
961
+ 'node2' => expected_deploy_result,
962
+ 'node3' => expected_deploy_result
963
+ )
964
+ expect(HybridPlatformsConductorTest::TestSecretsReaderPlugin.calls).to eq [
965
+ { instance: :secrets_reader1, node: 'node1', service: 'service1' },
966
+ { instance: :secrets_reader1, node: 'node1', service: 'service2' },
967
+ { instance: :secrets_reader2, node: 'node1', service: 'service1' },
968
+ { instance: :secrets_reader2, node: 'node1', service: 'service2' },
969
+ { instance: :secrets_reader1, node: 'node2', service: 'service2' },
970
+ { instance: :secrets_reader1, node: 'node2', service: 'service3' },
971
+ { instance: :secrets_reader2, node: 'node2', service: 'service2' },
972
+ { instance: :secrets_reader2, node: 'node2', service: 'service3' },
973
+ { instance: :secrets_reader3, node: 'node2', service: 'service2' },
974
+ { instance: :secrets_reader3, node: 'node2', service: 'service3' },
975
+ { instance: :secrets_reader1, node: 'node3', service: 'service3' },
976
+ { instance: :secrets_reader2, node: 'node3', service: 'service3' }
977
+ ]
978
+ end
979
+ end
980
+
981
+ it 'merges secrets having same values' do
982
+ register_plugins(
983
+ :secrets_reader,
984
+ {
985
+ secrets_reader1: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
986
+ secrets_reader2: HybridPlatformsConductorTest::TestSecretsReaderPlugin
987
+ }
988
+ )
989
+ with_platform_to_deploy(
990
+ nodes_info: {
991
+ nodes: {
992
+ 'node1' => { services: %w[service1] },
993
+ 'node2' => { services: %w[service2] }
994
+ }
995
+ },
996
+ expect_secrets: {
997
+ 'global1' => 'value1',
998
+ 'global2' => 'value2',
999
+ 'global3' => 'value3',
1000
+ 'global4' => 'value4'
1001
+ },
1002
+ additional_config: <<~EOS
1003
+ read_secrets_from :secrets_reader1
1004
+ for_nodes('node2') { read_secrets_from :secrets_reader2 }
1005
+ EOS
1006
+ ) do
1007
+ TestSecretsReaderPlugin.deployer = test_deployer
1008
+ TestSecretsReaderPlugin.mocked_secrets = {
1009
+ 'node1' => {
1010
+ 'service1' => {
1011
+ secrets_reader1: {
1012
+ 'global1' => 'value1',
1013
+ 'global2' => 'value2'
1014
+ }
1015
+ }
1016
+ },
1017
+ 'node2' => {
1018
+ 'service2' => {
1019
+ secrets_reader1: {
1020
+ 'global2' => 'value2',
1021
+ 'global3' => 'value3'
1022
+ },
1023
+ secrets_reader2: {
1024
+ 'global3' => 'value3',
1025
+ 'global4' => 'value4'
1026
+ }
1027
+ }
1028
+ }
1029
+ }
1030
+ expect(test_deployer.deploy_on(%w[node1 node2])).to eq(
1031
+ 'node1' => expected_deploy_result,
1032
+ 'node2' => expected_deploy_result
1033
+ )
1034
+ expect(HybridPlatformsConductorTest::TestSecretsReaderPlugin.calls).to eq [
1035
+ { instance: :secrets_reader1, node: 'node1', service: 'service1' },
1036
+ { instance: :secrets_reader1, node: 'node2', service: 'service2' },
1037
+ { instance: :secrets_reader2, node: 'node2', service: 'service2' }
1038
+ ]
1039
+ end
1040
+ end
1041
+
1042
+ it 'fails when merging secrets having different values' do
1043
+ register_plugins(
1044
+ :secrets_reader,
1045
+ {
1046
+ secrets_reader1: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
1047
+ secrets_reader2: HybridPlatformsConductorTest::TestSecretsReaderPlugin
1048
+ }
1049
+ )
1050
+ with_platform_to_deploy(
1051
+ nodes_info: {
1052
+ nodes: {
1053
+ 'node1' => { services: %w[service1] },
1054
+ 'node2' => { services: %w[service2] }
1055
+ }
1056
+ },
1057
+ expect_deploy_allowed: false,
1058
+ expect_package: false,
1059
+ expect_prepare_for_deploy: false,
1060
+ expect_connections_to_nodes: false,
1061
+ additional_config: <<~EOS
1062
+ read_secrets_from :secrets_reader1
1063
+ for_nodes('node2') { read_secrets_from :secrets_reader2 }
1064
+ EOS
1065
+ ) do
1066
+ TestSecretsReaderPlugin.deployer = test_deployer
1067
+ TestSecretsReaderPlugin.mocked_secrets = {
1068
+ 'node1' => {
1069
+ 'service1' => {
1070
+ secrets_reader1: {
1071
+ 'global1' => 'value1',
1072
+ 'global2' => 'value2'
1073
+ }
1074
+ }
1075
+ },
1076
+ 'node2' => {
1077
+ 'service2' => {
1078
+ secrets_reader1: {
1079
+ 'global2' => 'value2',
1080
+ 'global3' => {
1081
+ 'sub_key' => 'value3'
1082
+ }
1083
+ },
1084
+ secrets_reader2: {
1085
+ 'global3' => {
1086
+ 'sub_key' => 'Other value'
1087
+ },
1088
+ 'global4' => 'value4'
1089
+ }
1090
+ }
1091
+ }
1092
+ }
1093
+ expect { test_deployer.deploy_on(%w[node1 node2]) }.to raise_error 'Secret set at path global3->sub_key by secrets_reader2 for service service2 on node node2 has conflicting values (set debug for value details).'
1094
+ expect(HybridPlatformsConductorTest::TestSecretsReaderPlugin.calls).to eq [
1095
+ { instance: :secrets_reader1, node: 'node1', service: 'service1' },
1096
+ { instance: :secrets_reader1, node: 'node2', service: 'service2' },
1097
+ { instance: :secrets_reader2, node: 'node2', service: 'service2' }
1098
+ ]
1099
+ end
1100
+ end
1101
+
1102
+ it 'does not call secrets readers when secrets are overridden' do
1103
+ register_plugins(
1104
+ :secrets_reader,
1105
+ {
1106
+ secrets_reader1: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
1107
+ secrets_reader2: HybridPlatformsConductorTest::TestSecretsReaderPlugin,
1108
+ secrets_reader3: HybridPlatformsConductorTest::TestSecretsReaderPlugin
1109
+ }
1110
+ )
1111
+ with_platform_to_deploy(
1112
+ nodes_info: {
1113
+ nodes: {
1114
+ 'node1' => { services: %w[service1] },
1115
+ 'node2' => { services: %w[service2] },
1116
+ 'node3' => { services: %w[service3] }
1117
+ }
1118
+ },
1119
+ expect_secrets: {
1120
+ 'overridden_secrets' => 'value'
1121
+ },
1122
+ additional_config: <<~EOS
1123
+ read_secrets_from %i[secrets_reader1 secrets_reader2]
1124
+ for_nodes('node2') { read_secrets_from :secrets_reader3 }
1125
+ EOS
1126
+ ) do
1127
+ TestSecretsReaderPlugin.deployer = test_deployer
1128
+ test_deployer.override_secrets('overridden_secrets' => 'value')
1129
+ expect(test_deployer.deploy_on(%w[node1 node2 node3])).to eq(
1130
+ 'node1' => expected_deploy_result,
1131
+ 'node2' => expected_deploy_result,
1132
+ 'node3' => expected_deploy_result
1133
+ )
1134
+ expect(HybridPlatformsConductorTest::TestSecretsReaderPlugin.calls).to eq []
1135
+ end
1136
+ end
1137
+
1138
+ end
1139
+
904
1140
  end
905
1141
 
906
1142
  end
@@ -0,0 +1,82 @@
1
+ module HybridPlatformsConductorTest
2
+
3
+ # Test log without reading actions
4
+ class TestLogNoReadPlugin < HybridPlatformsConductor::Log
5
+
6
+ class << self
7
+ attr_accessor :calls
8
+ end
9
+
10
+ # Get actions to save logs
11
+ # [API] - This method is mandatory.
12
+ # [API] - The following API components are accessible:
13
+ # * *@config* (Config): Main configuration API.
14
+ # * *@nodes_handler* (NodesHandler): Nodes handler API.
15
+ # * *@actions_executor* (ActionsExecutor): Actions executor API.
16
+ #
17
+ # Parameters::
18
+ # * *node* (String): Node for which logs are being saved
19
+ # * *services* (Array<String>): The list of services that have been deployed on this node
20
+ # * *deployment_info* (Hash<Symbol,Object>): Additional information to attach to the logs
21
+ # * *exit_status* (Integer or Symbol): Exit status of the deployment
22
+ # * *stdout* (String): Deployment's stdout
23
+ # * *stderr* (String): Deployment's stderr
24
+ # Result::
25
+ # * Array< Hash<Symbol,Object> >: List of actions to be done
26
+ def actions_to_save_logs(node, services, deployment_info, exit_status, stdout, stderr)
27
+ TestLogNoReadPlugin.calls << {
28
+ method: :actions_to_save_logs,
29
+ node: node,
30
+ services: services,
31
+ # Don't store the date
32
+ deployment_info: deployment_info.select { |k, _v| k != :date },
33
+ exit_status: exit_status,
34
+ stdout: stdout,
35
+ stderr: stderr
36
+ }
37
+ [{ bash: "echo Save test logs to #{node}" }]
38
+ end
39
+
40
+ # Get deployment logs from a node.
41
+ # This method can use the result of actions previously run to read logs, as returned by the actions_to_read_logs method.
42
+ # [API] - This method is mandatory.
43
+ # [API] - The following API components are accessible:
44
+ # * *@config* (Config): Main configuration API.
45
+ # * *@nodes_handler* (NodesHandler): Nodes handler API.
46
+ # * *@actions_executor* (ActionsExecutor): Actions executor API.
47
+ #
48
+ # Parameters::
49
+ # * *node* (String): The node we want deployment logs from
50
+ # * *exit_status* (Integer, Symbol or nil): Exit status of actions to read logs, or nil if no action was returned by actions_to_read_logs
51
+ # * *stdout* (String or nil): stdout of actions to read logs, or nil if no action was returned by actions_to_read_logs
52
+ # * *stderr* (String or nil): stderr of actions to read logs, or nil if no action was returned by actions_to_read_logs
53
+ # Result::
54
+ # * Hash<Symbol,Object>: Deployment log information:
55
+ # * *error* (String): Error string in case deployment logs could not be retrieved. If set then further properties will be ignored. [optional]
56
+ # * *services* (Array<String>): List of services deployed on the node
57
+ # * *deployment_info* (Hash<Symbol,Object>): Deployment metadata
58
+ # * *exit_status* (Integer or Symbol): Deployment exit status
59
+ # * *stdout* (String): Deployment stdout
60
+ # * *stderr* (String): Deployment stderr
61
+ def logs_for(node, exit_status, stdout, stderr)
62
+ TestLogNoReadPlugin.calls << {
63
+ method: :logs_for,
64
+ node: node,
65
+ exit_status: exit_status,
66
+ stdout: stdout,
67
+ stderr: stderr
68
+ }
69
+ {
70
+ services: %w[unknown],
71
+ deployment_info: {
72
+ user: 'test_user'
73
+ },
74
+ exit_status: 666,
75
+ stdout: 'Deployment test stdout',
76
+ stderr: 'Deployment test stderr'
77
+ }
78
+ end
79
+
80
+ end
81
+
82
+ end