hybrid_platforms_conductor 32.16.3 → 33.0.0

Sign up to get free protection for your applications and to get access to all the features.
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