hybrid_platforms_conductor 32.12.0 → 32.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +1103 -0
  3. data/LICENSE.md +31 -0
  4. data/README.md +395 -0
  5. data/bin/setup +1 -1
  6. data/docs/api.md +349 -0
  7. data/docs/config_dsl.md +315 -0
  8. data/docs/executables.md +226 -0
  9. data/docs/executables/check-node.md +155 -0
  10. data/docs/executables/deploy.md +198 -0
  11. data/docs/executables/dump_nodes_json.md +110 -0
  12. data/docs/executables/free_ips.md +93 -0
  13. data/docs/executables/free_veids.md +73 -0
  14. data/docs/executables/get_impacted_nodes.md +94 -0
  15. data/docs/executables/last_deploys.md +114 -0
  16. data/docs/executables/nodes_to_deploy.md +139 -0
  17. data/docs/executables/report.md +159 -0
  18. data/docs/executables/run.md +126 -0
  19. data/docs/executables/setup.md +92 -0
  20. data/docs/executables/ssh_config.md +151 -0
  21. data/docs/executables/test.md +213 -0
  22. data/docs/executables/topograph.md +139 -0
  23. data/docs/gen/mermaid/README.md-0.png +0 -0
  24. data/docs/gen/mermaid/docs/executables/check-node.md-0.png +0 -0
  25. data/docs/gen/mermaid/docs/executables/deploy.md-0.png +0 -0
  26. data/docs/gen/mermaid/docs/executables/free_ips.md-0.png +0 -0
  27. data/docs/gen/mermaid/docs/executables/free_veids.md-0.png +0 -0
  28. data/docs/gen/mermaid/docs/executables/get_impacted_nodes.md-0.png +0 -0
  29. data/docs/gen/mermaid/docs/executables/last_deploys.md-0.png +0 -0
  30. data/docs/gen/mermaid/docs/executables/nodes_to_deploy.md-0.png +0 -0
  31. data/docs/gen/mermaid/docs/executables/report.md-0.png +0 -0
  32. data/docs/gen/mermaid/docs/executables/run.md-0.png +0 -0
  33. data/docs/gen/mermaid/docs/executables/setup.md-0.png +0 -0
  34. data/docs/gen/mermaid/docs/executables/ssh_config.md-0.png +0 -0
  35. data/docs/gen/mermaid/docs/executables/test.md-0.png +0 -0
  36. data/docs/install.md +161 -0
  37. data/docs/plugins.md +215 -0
  38. data/docs/plugins/action/bash.md +37 -0
  39. data/docs/plugins/action/interactive.md +37 -0
  40. data/docs/plugins/action/remote_bash.md +67 -0
  41. data/docs/plugins/action/ruby.md +69 -0
  42. data/docs/plugins/action/scp.md +61 -0
  43. data/docs/plugins/cmdb/config.md +46 -0
  44. data/docs/plugins/cmdb/host_ip.md +33 -0
  45. data/docs/plugins/cmdb/host_keys.md +33 -0
  46. data/docs/plugins/cmdb/platform_handlers.md +33 -0
  47. data/docs/plugins/connector/local.md +28 -0
  48. data/docs/plugins/connector/ssh.md +95 -0
  49. data/docs/plugins/platform_handler/yaml_inventory.md +105 -0
  50. data/docs/plugins/provisioner/docker.md +27 -0
  51. data/docs/plugins/provisioner/podman.md +27 -0
  52. data/docs/plugins/provisioner/proxmox.md +115 -0
  53. data/docs/plugins/report/confluence.md +49 -0
  54. data/docs/plugins/report/mediawiki.md +28 -0
  55. data/docs/plugins/report/stdout.md +32 -0
  56. data/docs/plugins/test/bitbucket_conf.md +97 -0
  57. data/docs/plugins/test/can_be_checked.md +27 -0
  58. data/docs/plugins/test/check_deploy_and_idempotence.md +61 -0
  59. data/docs/plugins/test/check_from_scratch.md +28 -0
  60. data/docs/plugins/test/connection.md +27 -0
  61. data/docs/plugins/test/deploy_freshness.md +27 -0
  62. data/docs/plugins/test/deploy_from_scratch.md +28 -0
  63. data/docs/plugins/test/deploy_removes_root_access.md +29 -0
  64. data/docs/plugins/test/divergence.md +41 -0
  65. data/docs/plugins/test/executables.md +26 -0
  66. data/docs/plugins/test/file_system.md +49 -0
  67. data/docs/plugins/test/file_system_hdfs.md +65 -0
  68. data/docs/plugins/test/hostname.md +27 -0
  69. data/docs/plugins/test/idempotence.md +56 -0
  70. data/docs/plugins/test/ip.md +28 -0
  71. data/docs/plugins/test/jenkins_ci_conf.md +54 -0
  72. data/docs/plugins/test/jenkins_ci_masters_ok.md +54 -0
  73. data/docs/plugins/test/linear_strategy.md +26 -0
  74. data/docs/plugins/test/local_users.md +48 -0
  75. data/docs/plugins/test/mounts.md +55 -0
  76. data/docs/plugins/test/orphan_files.md +38 -0
  77. data/docs/plugins/test/ports.md +50 -0
  78. data/docs/plugins/test/private_ips.md +27 -0
  79. data/docs/plugins/test/public_ips.md +27 -0
  80. data/docs/plugins/test/spectre.md +26 -0
  81. data/docs/plugins/test/veids.md +27 -0
  82. data/docs/plugins/test/vulnerabilities.md +65 -0
  83. data/docs/plugins/test_report/confluence.md +43 -0
  84. data/docs/plugins/test_report/stdout.md +26 -0
  85. data/docs/plugins_create.md +135 -0
  86. data/docs/tutorial.md +57 -0
  87. data/docs/tutorial/01_installation.md +129 -0
  88. data/docs/tutorial/02_first_node.md +466 -0
  89. data/docs/tutorial/03_scale.md +876 -0
  90. data/docs/tutorial/04_test.md +965 -0
  91. data/docs/tutorial/05_extend_with_plugins.md +1132 -0
  92. data/examples/bare/Gemfile +4 -0
  93. data/examples/bare/hpc_config.rb +2 -0
  94. data/examples/localhost/Gemfile +4 -0
  95. data/examples/localhost/hpc_config.rb +2 -0
  96. data/examples/localhost/inventory.yaml +4 -0
  97. data/lib/hybrid_platforms_conductor/actions_executor.rb +1 -0
  98. data/lib/hybrid_platforms_conductor/deployer.rb +3 -2
  99. data/lib/hybrid_platforms_conductor/hpc_plugins/action/remote_bash.rb +29 -13
  100. data/lib/hybrid_platforms_conductor/hpc_plugins/action/scp.rb +1 -1
  101. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/local.rb +98 -0
  102. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/my_connector.rb.sample +2 -2
  103. data/lib/hybrid_platforms_conductor/hpc_plugins/connector/ssh.rb +7 -3
  104. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/platform_handler_plugin.rb.sample +5 -5
  105. data/lib/hybrid_platforms_conductor/hpc_plugins/platform_handler/yaml_inventory.rb +140 -0
  106. data/lib/hybrid_platforms_conductor/hpc_plugins/provisioner/proxmox.rb +5 -2
  107. data/lib/hybrid_platforms_conductor/hpc_plugins/test/bitbucket_conf.rb +4 -4
  108. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_freshness.rb +1 -1
  109. data/lib/hybrid_platforms_conductor/hpc_plugins/test/deploy_removes_root_access.rb +19 -17
  110. data/lib/hybrid_platforms_conductor/hpc_plugins/test/divergence.rb +3 -0
  111. data/lib/hybrid_platforms_conductor/hpc_plugins/test/hostname.rb +2 -1
  112. data/lib/hybrid_platforms_conductor/hpc_plugins/test/ip.rb +2 -1
  113. data/lib/hybrid_platforms_conductor/hpc_plugins/test/local_users.rb +2 -1
  114. data/lib/hybrid_platforms_conductor/hpc_plugins/test/mounts.rb +4 -3
  115. data/lib/hybrid_platforms_conductor/hpc_plugins/test/orphan_files.rb +2 -1
  116. data/lib/hybrid_platforms_conductor/hpc_plugins/test/spectre.rb +1 -1
  117. data/lib/hybrid_platforms_conductor/hpc_plugins/test/vulnerabilities.rb +8 -7
  118. data/lib/hybrid_platforms_conductor/hpc_plugins/test_report/confluence.rb +1 -1
  119. data/lib/hybrid_platforms_conductor/json_dumper.rb +1 -1
  120. data/lib/hybrid_platforms_conductor/platform_handler.rb +1 -1
  121. data/lib/hybrid_platforms_conductor/services_handler.rb +18 -16
  122. data/lib/hybrid_platforms_conductor/tests_runner.rb +0 -1
  123. data/lib/hybrid_platforms_conductor/topographer.rb +0 -1
  124. data/lib/hybrid_platforms_conductor/version.rb +1 -1
  125. data/spec/hybrid_platforms_conductor_test/api/actions_executor/actions/remote_bash_spec.rb +16 -0
  126. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/local/connectable_nodes_spec.rb +30 -0
  127. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/local/remote_actions_spec.rb +113 -0
  128. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/cli_options_spec.rb +6 -2
  129. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/global_helpers_spec.rb +38 -1
  130. data/spec/hybrid_platforms_conductor_test/api/actions_executor/connectors/ssh/remote_actions_spec.rb +8 -8
  131. data/spec/hybrid_platforms_conductor_test/docs_spec.rb +10 -0
  132. data/tools/check_md +89 -0
  133. data/tools/generate_mermaid +75 -0
  134. metadata +207 -12
@@ -0,0 +1,1132 @@
1
+
2
+ ---
3
+ **<p style="text-align: center;">Tutorial navigation</p>**
4
+
5
+ | <sub>[Introduction](/docs/tutorial.md)</sub> | <sub>[1. Installation and first-time setup](/docs/tutorial/01_installation.md)</sub> | <sub>[2. Deploy and check a first node](/docs/tutorial/02_first_node.md)</sub> | <sub>[3. Scale your processes](/docs/tutorial/03_scale.md)</sub> | <sub>[4. Testing your processes and platforms](/docs/tutorial/04_test.md)</sub> | <nobr><sub><sub>&#128071;You are here&#128071;</sub></sub></nobr><br><sub>[5. Extend Hybrid Platforms Conductor with your own requirements](/docs/tutorial/05_extend_with_plugins.md)</sub> |
6
+ | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
7
+ | <sub><sub>**[Use-case](/docs/tutorial.md#use-case)**</sub></sub> | <sub><sub>**[Dependencies installation](/docs/tutorial/01_installation.md#hpc-dependencies)**</sub></sub> | <sub><sub>**[Add your first node and its platform repository](/docs/tutorial/02_first_node.md#add-first-node)**</sub></sub> | <sub><sub>**[Provision our web services platform](/docs/tutorial/03_scale.md#provision)**</sub></sub> | <sub><sub>**[Hello test framework](/docs/tutorial/04_test.md#framework)**</sub></sub> | <sub><sub>**[Create your plugins' repository](/docs/tutorial/05_extend_with_plugins.md#plugins-repo)**</sub></sub> |
8
+ | <sub><sub>**[Prerequisites](/docs/tutorial.md#prerequisites)**</sub></sub> | <sub><sub>**[Our platforms' main repository](/docs/tutorial/01_installation.md#main-repo)**</sub></sub> | <sub><sub>**[Check and deploy services on this node](/docs/tutorial/02_first_node.md#check-deploy)**</sub></sub> | <sub><sub>**[Run commands on our new web services](/docs/tutorial/03_scale.md#run)**</sub></sub> | <sub><sub>**[Testing your nodes](/docs/tutorial/04_test.md#nodes-tests)**</sub></sub> | <sub><sub>**[Your own platform handler](/docs/tutorial/05_extend_with_plugins.md#platform-handler)**</sub></sub> |
9
+ | <sub><sub>**[Tutorial setup](/docs/tutorial.md#tutorial-setup)**</sub></sub> | | <sub><sub>**[Updating the configuration](/docs/tutorial/02_first_node.md#update)**</sub></sub> | <sub><sub>**[Check and deploy our web services on several nodes at once](/docs/tutorial/03_scale.md#check-deploy)**</sub></sub> | <sub><sub>**[Testing your platforms' configuration](/docs/tutorial/04_test.md#platforms-tests)**</sub></sub> | <sub><sub>**[Write your own tests](/docs/tutorial/05_extend_with_plugins.md#test)**</sub></sub> |
10
+ | | | | | <sub><sub>**[Other kinds of tests](/docs/tutorial/04_test.md#other-tests)**</sub></sub> | <sub><sub>**[Enough of stdout, we want to report to other tools](/docs/tutorial/05_extend_with_plugins.md#report)**</sub></sub> |
11
+ | | | | | | <sub><sub>**[What next?](/docs/tutorial/05_extend_with_plugins.md#what-next)**</sub></sub> |
12
+
13
+ # 5. Extend Hybrid Platforms Conductor with your own requirements
14
+
15
+ The plugins provided by default with Hybrid Platforms Conductor can help a lot in starting out, but every organization, every project has its own conventions, frameworks, tools.
16
+
17
+ **You should not change your current conventions and tools to adapt to Hybrid Platforms Conductor.
18
+ Hybrid Platforms Conductor has to adapt to your conventions, tools, platforms...**
19
+
20
+ It is with this mindset that all Hybrid Platform Conductor's processes have been designed.
21
+ To achieve this, [plugins](/docs/plugins.md) are used extensively in every part of the processes.
22
+ During this tutorial we already used a lot of them, but now we are going to see how to add new ones to match **your** requirements.
23
+
24
+ <a name="plugins-repo"></a>
25
+ ## Create your plugins' repository
26
+
27
+ Plugins can be defined in any [Rubygem](https://guides.rubygems.org/what-is-a-gem/) that will have files named `lib/<gem_name>/hpc_plugins/<plugin_type>/<plugin_name>.rb`.
28
+ Then you just need to add your plugins' Rubygem your project and Hybrid Platforms Conductor will automatically discover all your plugins from there.
29
+
30
+ You can of course organize your plugins among several Rubygems the way you want, depending on the reusability of those plugins across your organization or even publish them as open source on [Rubygems.org](https://rubygems.org).
31
+
32
+ Let's start by creating your repository for plugins, structured as a Rubygem, and reference it in our main configuration project.
33
+ We'll call it `my_hpc_plugins`.
34
+
35
+ ```bash
36
+ # Create an empty Rubygem repository named my_hpc_plugins
37
+ mkdir -p ~/hpc_tutorial/my_hpc_plugins
38
+ cat <<EOF >~/hpc_tutorial/my_hpc_plugins/my_hpc_plugins.gemspec
39
+ Gem::Specification.new do |s|
40
+ s.name = 'my_hpc_plugins'
41
+ s.version = '0.0.1'
42
+ s.date = '2021-04-29'
43
+ s.authors = ['Me myself!']
44
+ s.email = ['me-myself@my-domain.com']
45
+ s.summary = 'My awesome plugins for Hybrid Platforms Conductor'
46
+ s.files = Dir['{bin,lib,spec}/**/*']
47
+ Dir['bin/**/*'].each do |exec_name|
48
+ s.executables << File.basename(exec_name)
49
+ end
50
+ # Dependencies
51
+ # Make sure we use a compatible version of hybrid_platforms_conductor
52
+ s.add_dependency 'hybrid_platforms_conductor', '~> 32.12'
53
+ end
54
+ EOF
55
+
56
+ # Reference it in our configuration repository, in the Gemfile
57
+ cat <<EOF >>Gemfile
58
+ gem 'my_hpc_plugins', path: "#{Dir.home}/hpc_tutorial/my_hpc_plugins"
59
+ EOF
60
+
61
+ # Install dependencies now that we have added a new gem into our project
62
+ bundle install
63
+ # =>
64
+ # [...]
65
+ # Using pastel 0.8.0
66
+ # Using tty-command 0.10.1
67
+ # Using hybrid_platforms_conductor 32.12.0
68
+ # Using my_hpc_plugins 0.0.1 from source at `/root/hpc_tutorial/my_hpc_plugins`
69
+ # Bundle complete! 2 Gemfile dependencies, 46 gems now installed.
70
+ # Bundled gems are installed into `./vendor/bundle`
71
+ ```
72
+
73
+ Now we can add the plugins we want in it.
74
+
75
+ <a name="platform-handler"></a>
76
+ ## Your own platform handler
77
+
78
+ The most common use case is that you already have configuration repositories using Chef, Ansible, Puppet or even simple bash scripts.
79
+ Now you want to integrate those in Hybrid Platforms Conductor to benefit from all the simple interfaces and integration within well-defined DevOps processes.
80
+
81
+ So let's start with a new platform repository storing some configuration for hosts you are already handling.
82
+
83
+ We'll create a platform repository that you already use without Hybrid Platforms Conductor and works this way:
84
+ * It has a list of JSON files in a `nodes/` directory defining hostnames to configure and pointing to bash scripts installing services.
85
+ * It has a list of bash scripts that are installing services on a give host in a `services/` directory.
86
+ * Each service bash script takes 2 parameters: the hostname to configure and an optional `check` parameter that checks if the service is installed. You use those scripts directly from you command-line to check and install services on your nodes.
87
+
88
+ Let's say you use those scripts to configure development servers that need some tooling installed for your team (like gcc, cmake...) and that your team connects to them using ssh.
89
+
90
+ ### Provision your dev servers that are configured by your platform repository
91
+
92
+ First, let's provision those development servers using some Docker containers from bare Debian images, and a `root` ssh key to connect to them.
93
+ The corresponding hostnames will be `devN.hpc_tutorial.org`:
94
+ ```bash
95
+ mkdir -p ~/hpc_tutorial/dev_docker_image
96
+
97
+ # Generate root admin RSA keys
98
+ yes y | ssh-keygen -t rsa -b 2048 -C "admin@example.com" -f ~/hpc_tutorial/dev_docker_image/hpc_root.key -N ""
99
+
100
+ # The Dockerfile
101
+ cat <<EOF >~/hpc_tutorial/dev_docker_image/Dockerfile
102
+ # syntax=docker/dockerfile:1
103
+ # Pull the image containing Go
104
+ FROM debian:buster
105
+
106
+ # Install sshd
107
+ RUN apt-get update && apt-get install -y openssh-server
108
+ RUN mkdir /var/run/sshd
109
+ # Activate root login
110
+ RUN sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/' /etc/ssh/sshd_config
111
+ # Speed-up considerably ssh performance and avoid huge lags and timeouts without DNS
112
+ RUN sed -i 's/#UseDNS yes/UseDNS no/' /etc/ssh/sshd_config
113
+ EXPOSE 22
114
+
115
+ # Upload our root key for key authentication of root
116
+ COPY hpc_root.key.pub /root/.ssh/authorized_keys
117
+ RUN chmod 700 /root/.ssh
118
+ RUN chmod 400 /root/.ssh/authorized_keys
119
+
120
+ # Startup command
121
+ CMD ["/usr/sbin/sshd", "-D"]
122
+ EOF
123
+
124
+ # Build the Docker image named hpc_tutorial_dev
125
+ DOCKER_BUILDKIT=1 docker build -t hpc_tutorial_dev ~/hpc_tutorial/dev_docker_image
126
+
127
+ # Provision 10 dev servers named devN and add their hostnames to /etc/hosts
128
+ for ((i=1;i<=10;i++));
129
+ do
130
+ docker run --hostname "dev$i.hpc_tutorial.org" --name "dev$i" -P -d hpc_tutorial_dev
131
+ echo "$(docker container inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' dev$i) dev$i.hpc_tutorial.org" >>/etc/hosts
132
+ done
133
+
134
+ # Add the root SSH key to our agent
135
+ ssh-add ~/hpc_tutorial/dev_docker_image/hpc_root.key
136
+ ```
137
+
138
+ We can check that our platform is provisioned with a simple test script:
139
+ ```bash
140
+ for ((i=1;i<=10;i++));
141
+ do
142
+ ssh -o StrictHostKeyChecking=no root@dev$i.hpc_tutorial.org 'echo Hello $(hostname)!' 2>/dev/null
143
+ done
144
+ # =>
145
+ # Hello dev1.hpc_tutorial.org!
146
+ # Hello dev2.hpc_tutorial.org!
147
+ # Hello dev3.hpc_tutorial.org!
148
+ # Hello dev4.hpc_tutorial.org!
149
+ # Hello dev5.hpc_tutorial.org!
150
+ # Hello dev6.hpc_tutorial.org!
151
+ # Hello dev7.hpc_tutorial.org!
152
+ # Hello dev8.hpc_tutorial.org!
153
+ # Hello dev9.hpc_tutorial.org!
154
+ # Hello dev10.hpc_tutorial.org!
155
+ ```
156
+
157
+ Please note that if we exit your Docker tutorial container and restart it, you will need to restart your dev containers and regenerate their hostname/ip in `/etc/hosts`.
158
+ This will be done this way (to be done each time you will restart your tutorial or dev containers):
159
+ ```bash
160
+ for ((i=1;i<=10;i++));
161
+ do
162
+ docker container start dev$i
163
+ echo "$(docker container inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' dev$i) dev$i.hpc_tutorial.org" >>/etc/hosts
164
+ done
165
+ ```
166
+
167
+ For info, here are what your docker containers and `/etc/hosts` should look like currently:
168
+ ```bash
169
+ docker container list --all
170
+ # =>
171
+ # CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
172
+ # 9fd42bf48092 hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49194->22/tcp dev10
173
+ # f88aa890875d hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49193->22/tcp dev9
174
+ # a1c4967c9e75 hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49192->22/tcp dev8
175
+ # d1d361e43913 hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49191->22/tcp dev7
176
+ # 83ee06f500a8 hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49190->22/tcp dev6
177
+ # cc27dda93985 hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49189->22/tcp dev5
178
+ # d5bc37e91408 hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49188->22/tcp dev4
179
+ # 538d5b3503d5 hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49187->22/tcp dev3
180
+ # 039cbb03734e hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49186->22/tcp dev2
181
+ # 8dbc7f911454 hpc_tutorial_dev "/usr/sbin/sshd -D" 2 minutes ago Up 2 minutes 0.0.0.0:49185->22/tcp dev1
182
+ # 87e6a31c21ea hpc_image_debian_10 "/usr/sbin/sshd -D" 25 hours ago Exited (0) 25 hours ago hpc_docker_container_web1_root_check_from_scratch
183
+ # fd6fe2331b86 hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49172->22/tcp, 0.0.0.0:49171->80/tcp web10
184
+ # af538c1db9ba hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49170->22/tcp, 0.0.0.0:49169->80/tcp web9
185
+ # 0fc004f8fafb hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49168->22/tcp, 0.0.0.0:49167->80/tcp web8
186
+ # cda9dfa98062 hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49166->22/tcp, 0.0.0.0:49165->80/tcp web7
187
+ # bea9d491774b hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49164->22/tcp, 0.0.0.0:49163->80/tcp web6
188
+ # 3869a1262c5a hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49162->22/tcp, 0.0.0.0:49161->80/tcp web5
189
+ # e886cc392725 hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49160->22/tcp, 0.0.0.0:49159->80/tcp web4
190
+ # aff2c221b724 hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49158->22/tcp, 0.0.0.0:49157->80/tcp web3
191
+ # 192d4f8e01af hpc_tutorial_web "/start.sh" 47 hours ago Up 42 minutes 0.0.0.0:49156->22/tcp, 0.0.0.0:49155->80/tcp web2
192
+ # b283d646c3fa hpc_tutorial_web "/start.sh" 47 hours ago Up 3 minutes 0.0.0.0:49184->22/tcp, 0.0.0.0:49183->80/tcp web1
193
+ # e8dddeb2ba25 debian:buster "/bin/bash" 3 days ago Up 45 minutes hpc_tutorial
194
+
195
+ cat /etc/hosts
196
+ # =>
197
+ # 127.0.0.1 localhost
198
+ # ::1 localhost ip6-localhost ip6-loopback
199
+ # fe00::0 ip6-localnet
200
+ # ff00::0 ip6-mcastprefix
201
+ # ff02::1 ip6-allnodes
202
+ # ff02::2 ip6-allrouters
203
+ # 172.17.0.2 e8dddeb2ba25
204
+ # 172.17.0.3 web1.hpc_tutorial.org
205
+ # 172.17.0.4 web2.hpc_tutorial.org
206
+ # 172.17.0.5 web3.hpc_tutorial.org
207
+ # 172.17.0.6 web4.hpc_tutorial.org
208
+ # 172.17.0.7 web5.hpc_tutorial.org
209
+ # 172.17.0.8 web6.hpc_tutorial.org
210
+ # 172.17.0.9 web7.hpc_tutorial.org
211
+ # 172.17.0.10 web8.hpc_tutorial.org
212
+ # 172.17.0.11 web9.hpc_tutorial.org
213
+ # 172.17.0.12 web10.hpc_tutorial.org
214
+ # 172.17.0.13 dev1.hpc_tutorial.org
215
+ # 172.17.0.14 dev2.hpc_tutorial.org
216
+ # 172.17.0.15 dev3.hpc_tutorial.org
217
+ # 172.17.0.16 dev4.hpc_tutorial.org
218
+ # 172.17.0.17 dev5.hpc_tutorial.org
219
+ # 172.17.0.18 dev6.hpc_tutorial.org
220
+ # 172.17.0.19 dev7.hpc_tutorial.org
221
+ # 172.17.0.20 dev8.hpc_tutorial.org
222
+ # 172.17.0.21 dev9.hpc_tutorial.org
223
+ # 172.17.0.22 dev10.hpc_tutorial.org
224
+ ```
225
+
226
+ Now that we have provisioned a dev platform, let's create our platform repository, that should work without Hybrid Platforms Conductor's processes for now.
227
+
228
+ ### Create your existing platform repository with your own processes
229
+
230
+ Let's say we have 2 kind of dev servers in our platform:
231
+ * `dev1` to `dev5` used for Python development.
232
+ * `dev6` to `dev10` used for C++ development.
233
+
234
+ We are using bash scripts that check and install requirements for those both environments:
235
+ ```bash
236
+ mkdir -p ~/hpc_tutorial/dev-servers-conf-repo
237
+
238
+ # Bash script checking and installing Python on a hostname via ssh
239
+ cat <<EOF >~/hpc_tutorial/dev-servers-conf-repo/install-python.bash
240
+ hostname=\${1}
241
+ check_flag=\${2:-deploy}
242
+ if [ "\${check_flag}" = "check" ]; then
243
+ # Check if python3 is installed
244
+ if ssh -o StrictHostKeyChecking=no root@\${hostname} 'python3 --version' 2>/dev/null; then
245
+ echo 'OK'
246
+ else
247
+ echo 'Missing'
248
+ fi
249
+ else
250
+ # Install python3
251
+ ssh -o StrictHostKeyChecking=no root@\${hostname} 'apt install -y python3-pip' 2>/dev/null
252
+ echo 'Installed'
253
+ fi
254
+ EOF
255
+ chmod a+x ~/hpc_tutorial/dev-servers-conf-repo/install-python.bash
256
+
257
+ # Bash script checking and installing Python on a hostname via ssh
258
+ cat <<EOF >~/hpc_tutorial/dev-servers-conf-repo/install-gcc.bash
259
+ hostname=\${1}
260
+ check_flag=\${2:-deploy}
261
+ if [ "\${check_flag}" = "check" ]; then
262
+ # Check if gcc is installed
263
+ if ssh -o StrictHostKeyChecking=no root@\${hostname} 'gcc --version' 2>/dev/null; then
264
+ echo 'OK'
265
+ else
266
+ echo 'Missing'
267
+ fi
268
+ else
269
+ # Install gcc
270
+ ssh -o StrictHostKeyChecking=no root@\${hostname} 'apt install -y gcc' 2>/dev/null
271
+ echo 'Installed'
272
+ fi
273
+ EOF
274
+ chmod a+x ~/hpc_tutorial/dev-servers-conf-repo/install-gcc.bash
275
+ ```
276
+
277
+ We can already check that our bash scripts work as expected by using them manually:
278
+ ```bash
279
+ # Check that Python is not installed by default
280
+ ~/hpc_tutorial/dev-servers-conf-repo/install-python.bash dev1.hpc_tutorial.org check
281
+ # => Missing
282
+
283
+ # Install Python
284
+ ~/hpc_tutorial/dev-servers-conf-repo/install-python.bash dev1.hpc_tutorial.org
285
+ # =>
286
+ # [...]
287
+ # Setting up python3-dev (3.7.3-1) ...
288
+ # Setting up python3-keyring (17.1.1-1) ...
289
+ # Processing triggers for libc-bin (2.28-10) ...
290
+ # Processing triggers for ca-certificates (20200601~deb10u2) ...
291
+ # Updating certificates in /etc/ssl/certs...
292
+ # 0 added, 0 removed; done.
293
+ # Running hooks in /etc/ca-certificates/update.d...
294
+ # done.
295
+ # Installed
296
+
297
+ # Check that Python is reported as installed
298
+ ~/hpc_tutorial/dev-servers-conf-repo/install-python.bash dev1.hpc_tutorial.org check
299
+ # =>
300
+ # Python 3.7.3
301
+ # OK
302
+
303
+ # Check that gcc is not installed by default
304
+ ~/hpc_tutorial/dev-servers-conf-repo/install-gcc.bash dev6.hpc_tutorial.org check
305
+ # => Missing
306
+
307
+ # Install gcc
308
+ ~/hpc_tutorial/dev-servers-conf-repo/install-gcc.bash dev6.hpc_tutorial.org
309
+ # =>
310
+ # [...]
311
+ # Setting up libgcc-8-dev:amd64 (8.3.0-6) ...
312
+ # Setting up cpp (4:8.3.0-1) ...
313
+ # Setting up libc6-dev:amd64 (2.28-10) ...
314
+ # Setting up gcc-8 (8.3.0-6) ...
315
+ # Setting up gcc (4:8.3.0-1) ...
316
+ # Processing triggers for libc-bin (2.28-10) ...
317
+ # Installed
318
+
319
+ # Check that gcc is reported as installed
320
+ ~/hpc_tutorial/dev-servers-conf-repo/install-gcc.bash dev6.hpc_tutorial.org check
321
+ # =>
322
+ # gcc (Debian 8.3.0-6) 8.3.0
323
+ # Copyright (C) 2018 Free Software Foundation, Inc.
324
+ # This is free software; see the source for copying conditions. There is NO
325
+ # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
326
+ #
327
+ # OK
328
+ ```
329
+
330
+ Now let's create our small inventory JSON file that tells which hostname has which service:
331
+ ```bash
332
+ cat <<EOF >~/hpc_tutorial/dev-servers-conf-repo/hosts.json
333
+ {
334
+ "dev1.hpc_tutorial.org": "python",
335
+ "dev2.hpc_tutorial.org": "python",
336
+ "dev3.hpc_tutorial.org": "python",
337
+ "dev4.hpc_tutorial.org": "python",
338
+ "dev5.hpc_tutorial.org": "python",
339
+ "dev6.hpc_tutorial.org": "gcc",
340
+ "dev7.hpc_tutorial.org": "gcc",
341
+ "dev8.hpc_tutorial.org": "gcc",
342
+ "dev9.hpc_tutorial.org": "gcc",
343
+ "dev10.hpc_tutorial.org": "gcc"
344
+ }
345
+ EOF
346
+ ```
347
+
348
+ So here we are: a full platform repository containing some inventory and bash scripts that we can use to check and deploy services on this platform, following some existing tooling and conventions in your team.
349
+
350
+ Let's see what does it take to integrate this new platform repository into Hybrid Platforms Conductor by writing your own [`platform_handler` plugin](/docs/plugins.md#platform_handler).
351
+
352
+ ### Write a simple platform handler that can handle your existing repository
353
+
354
+ A [`platform_handler` plugin](/docs/plugins.md#platform_handler) handles a given kind of platform repository, and has basically 2 roles:
355
+ * Provide inventory information (nodes defined, their metadata, the services they are hosting...).
356
+ * Provide services information (how to check/deploy services on a node).
357
+
358
+ So let's write a new plugin handling your repository.
359
+ Like any plugin, we create a file named `lib/<gem_name>/hpc_plugins/<plugin_type>/<plugin_name>.rb` that define a simple class inherting from a plugin's class.
360
+ Here is the code of our plugin:
361
+ ```ruby
362
+ require 'json'
363
+ require 'hybrid_platforms_conductor/platform_handler'
364
+
365
+ module MyHpcPlugins
366
+
367
+ module HpcPlugins
368
+
369
+ module PlatformHandler
370
+
371
+ # A nice platform handler to handle platforms of our team, using json inventory and bash scripts.
372
+ class JsonBash < HybridPlatformsConductor::PlatformHandler
373
+
374
+ # Get the list of known nodes.
375
+ # [API] - This method is mandatory.
376
+ #
377
+ # Result::
378
+ # * Array<String>: List of node names
379
+ def known_nodes
380
+ # This method is used to get the list of nodes that are handled by the platform
381
+ # In our case we read our json file to get this information, and use just the first part of the hostname as the node's name.
382
+ JSON.parse(File.read("#{repository_path}/hosts.json")).keys.map { |hostname| hostname.split('.').first }
383
+ end
384
+
385
+ # Get the metadata of a given node.
386
+ # [API] - This method is mandatory.
387
+ #
388
+ # Parameters::
389
+ # * *node* (String): Node to read metadata from
390
+ # Result::
391
+ # * Hash<Symbol,Object>: The corresponding metadata
392
+ def metadata_for(node)
393
+ # All nodes handled by this platform are running a debian buster image and we derive their name from their hostname.
394
+ {
395
+ hostname: "#{node}.hpc_tutorial.org",
396
+ image: 'debian_10'
397
+ }
398
+ end
399
+
400
+ # Return the services for a given node
401
+ # [API] - This method is mandatory.
402
+ #
403
+ # Parameters::
404
+ # * *node* (String): node to read configuration from
405
+ # Result::
406
+ # * Array<String>: The corresponding services
407
+ def services_for(node)
408
+ # This info is taken from our JSON inventory file
409
+ [JSON.parse(File.read("#{repository_path}/hosts.json"))["#{node}.hpc_tutorial.org"]]
410
+ end
411
+
412
+ # Get the list of services we can deploy
413
+ # [API] - This method is mandatory.
414
+ #
415
+ # Result::
416
+ # * Array<String>: The corresponding services
417
+ def deployable_services
418
+ # This info is taken by listing existing bash scripts
419
+ Dir.glob("#{repository_path}/install-*.bash").map { |file| File.basename(file).match(/install-(.*)\.bash/)[1] }
420
+ end
421
+
422
+ # Get the list of actions to perform to deploy on a given node.
423
+ # Those actions can be executed in parallel with other deployments on other nodes. They must be thread safe.
424
+ # [API] - This method is mandatory.
425
+ # [API] - @cmd_runner is accessible.
426
+ # [API] - @actions_executor is accessible.
427
+ #
428
+ # Parameters::
429
+ # * *node* (String): Node to deploy on
430
+ # * *service* (String): Service to be deployed
431
+ # * *use_why_run* (Boolean): Do we use a why-run mode? [default = true]
432
+ # Result::
433
+ # * Array< Hash<Symbol,Object> >: List of actions to be done
434
+ def actions_to_deploy_on(node, service, use_why_run: true)
435
+ # This method returns all the actions to execute to deploy on a node.
436
+ # The use_why_run switch is on if the deployment should just be simulated.
437
+ # Those actions (bash commands, scp of files, ruby code...) should be thread safe as they can be executed in parallel with other deployment actions for other nodes in case of a concurrent deployment on several nodes.
438
+ # In our case it's very simple: we just call our bash script on the node's hostname.
439
+ [{ bash: "#{repository_path}/install-#{service}.bash #{@nodes_handler.get_hostname_of(node)} #{use_why_run ? 'check' : ''}" }]
440
+ end
441
+
442
+ # Parse stdout and stderr of a given deploy run and get the list of tasks with their status
443
+ # [API] - This method is mandatory.
444
+ #
445
+ # Parameters::
446
+ # * *stdout* (String): stdout to be parsed
447
+ # * *stderr* (String): stderr to be parsed
448
+ # Result::
449
+ # * Array< Hash<Symbol,Object> >: List of task properties. The following properties should be returned, among free ones:
450
+ # * *name* (String): Task name
451
+ # * *status* (Symbol): Task status. Should be one of:
452
+ # * *:changed*: The task has been changed
453
+ # * *:identical*: The task has not been changed
454
+ # * *diffs* (String): Differences, if any
455
+ def parse_deploy_output(stdout, stderr)
456
+ # In our case our bash scripts return the last line as a status, so use it.
457
+ [{
458
+ name: 'Install tool',
459
+ status:
460
+ case stdout.split("\n").last
461
+ when 'OK'
462
+ :identical
463
+ else
464
+ :changed
465
+ end,
466
+ diffs: stdout
467
+ }]
468
+ end
469
+
470
+ end
471
+
472
+ end
473
+
474
+ end
475
+
476
+ end
477
+ ```
478
+
479
+ Let's write it in our Rubygem:
480
+ ```bash
481
+ mkdir -p ~/hpc_tutorial/my_hpc_plugins/lib/my_hpc_plugins/hpc_plugins/platform_handler
482
+ cat <<EOF >~/hpc_tutorial/my_hpc_plugins/lib/my_hpc_plugins/hpc_plugins/platform_handler/json_bash.rb
483
+ # --- Copy-paste the previous Ruby code here ---
484
+ EOF
485
+ ```
486
+
487
+ And now we can reference our platform repository `~/hpc_tutorial/dev-servers-conf-repo` as a platform of type `json_bash`.
488
+ Let's do it in the main configuration `hpc_config.rb`:
489
+ ```bash
490
+ cat <<EOF >>hpc_config.rb
491
+ json_bash_platform path: "#{Dir.home}/hpc_tutorial/dev-servers-conf-repo"
492
+ EOF
493
+ ```
494
+
495
+ And that's it!
496
+ Nothing else is needed to have all the Hybrid Platforms Conductor processes use your new platform.
497
+
498
+ Let's check this with the processes we already know, applied to all our platforms (local, web services and now dev servers):
499
+ ```bash
500
+ # Check the whole inventory
501
+ ./bin/report
502
+ # =>
503
+ # +-------+-----------------------+------------------------+-------------+-----------+-----------+-----------------------+-----------------------+
504
+ # | Node | Platform | Host name | IP | Physical? | OS | Description | Services |
505
+ # +-------+-----------------------+------------------------+-------------+-----------+-----------+-----------------------+-----------------------+
506
+ # | dev1 | dev-servers-conf-repo | dev1.hpc_tutorial.org | 172.17.0.13 | No | debian_10 | | python |
507
+ # | dev10 | dev-servers-conf-repo | dev10.hpc_tutorial.org | 172.17.0.22 | No | debian_10 | | gcc |
508
+ # | dev2 | dev-servers-conf-repo | dev2.hpc_tutorial.org | 172.17.0.14 | No | debian_10 | | python |
509
+ # | dev3 | dev-servers-conf-repo | dev3.hpc_tutorial.org | 172.17.0.15 | No | debian_10 | | python |
510
+ # | dev4 | dev-servers-conf-repo | dev4.hpc_tutorial.org | 172.17.0.16 | No | debian_10 | | python |
511
+ # | dev5 | dev-servers-conf-repo | dev5.hpc_tutorial.org | 172.17.0.17 | No | debian_10 | | python |
512
+ # | dev6 | dev-servers-conf-repo | dev6.hpc_tutorial.org | 172.17.0.18 | No | debian_10 | | gcc |
513
+ # | dev7 | dev-servers-conf-repo | dev7.hpc_tutorial.org | 172.17.0.19 | No | debian_10 | | gcc |
514
+ # | dev8 | dev-servers-conf-repo | dev8.hpc_tutorial.org | 172.17.0.20 | No | debian_10 | | gcc |
515
+ # | dev9 | dev-servers-conf-repo | dev9.hpc_tutorial.org | 172.17.0.21 | No | debian_10 | | gcc |
516
+ # | local | my-service-conf-repo | | | No | | The local environment | my-service |
517
+ # | web1 | my-service-conf-repo | web1.hpc_tutorial.org | 172.17.0.3 | No | debian_10 | Web service nbr 1 | my-service, web-hello |
518
+ # | web10 | my-service-conf-repo | web10.hpc_tutorial.org | 172.17.0.12 | No | debian_10 | Web service nbr 10 | web-hello |
519
+ # | web2 | my-service-conf-repo | web2.hpc_tutorial.org | 172.17.0.4 | No | debian_10 | Web service nbr 2 | my-service, web-hello |
520
+ # | web3 | my-service-conf-repo | web3.hpc_tutorial.org | 172.17.0.5 | No | debian_10 | Web service nbr 3 | my-service, web-hello |
521
+ # | web4 | my-service-conf-repo | web4.hpc_tutorial.org | 172.17.0.6 | No | debian_10 | Web service nbr 4 | my-service, web-hello |
522
+ # | web5 | my-service-conf-repo | web5.hpc_tutorial.org | 172.17.0.7 | No | debian_10 | Web service nbr 5 | my-service, web-hello |
523
+ # | web6 | my-service-conf-repo | web6.hpc_tutorial.org | 172.17.0.8 | No | debian_10 | Web service nbr 6 | web-hello |
524
+ # | web7 | my-service-conf-repo | web7.hpc_tutorial.org | 172.17.0.9 | No | debian_10 | Web service nbr 7 | web-hello |
525
+ # | web8 | my-service-conf-repo | web8.hpc_tutorial.org | 172.17.0.10 | No | debian_10 | Web service nbr 8 | web-hello |
526
+ # | web9 | my-service-conf-repo | web9.hpc_tutorial.org | 172.17.0.11 | No | debian_10 | Web service nbr 9 | web-hello |
527
+ # +-------+-----------------------+------------------------+-------------+-----------+-----------+-----------------------+-----------------------+
528
+
529
+ # Can we connect and run commands everywhere?
530
+ ./bin/run --all --command 'echo Hello from $(hostname)'
531
+ # =>
532
+ # Hello from dev1.hpc_tutorial.org
533
+ # Hello from dev10.hpc_tutorial.org
534
+ # Hello from dev2.hpc_tutorial.org
535
+ # Hello from dev3.hpc_tutorial.org
536
+ # Hello from dev4.hpc_tutorial.org
537
+ # Hello from dev5.hpc_tutorial.org
538
+ # Hello from dev6.hpc_tutorial.org
539
+ # Hello from dev7.hpc_tutorial.org
540
+ # Hello from dev8.hpc_tutorial.org
541
+ # Hello from dev9.hpc_tutorial.org
542
+ # Hello from e8dddeb2ba25
543
+ # Hello from web1.hpc_tutorial.org
544
+ # Hello from web10.hpc_tutorial.org
545
+ # Hello from web2.hpc_tutorial.org
546
+ # Hello from web3.hpc_tutorial.org
547
+ # Hello from web4.hpc_tutorial.org
548
+ # Hello from web5.hpc_tutorial.org
549
+ # Hello from web6.hpc_tutorial.org
550
+ # Hello from web7.hpc_tutorial.org
551
+ # Hello from web8.hpc_tutorial.org
552
+ # Hello from web9.hpc_tutorial.org
553
+
554
+ # Can we check a dev server?
555
+ ./bin/check-node --node dev1
556
+ # =>
557
+ # ===== Packaging deployment ==== Begin...
558
+ # ===== Packaging deployment ==== ...End
559
+ #
560
+ # ===== Checking on 1 nodes ==== Begin...
561
+ # ===== [ dev1 / python ] - HPC Service Check ===== Begin
562
+ # ===== [ dev1 / python ] - HPC Service Check ===== Begin
563
+ # Python 3.7.3
564
+ # OK
565
+ # ===== [ dev1 / python ] - HPC Service Check ===== End
566
+ # ===== [ dev1 / python ] - HPC Service Check ===== End
567
+ # Executing actions [100%] - | C| - [ Queue: 0 - Processing: 0 - Done: 1 - Total: 1 ]
568
+ # ===== Checking on 1 nodes ==== ...End
569
+
570
+ # Can we test our dev servers for spectre vulnerabilities?
571
+ ./bin/test --node /dev/ --test spectre
572
+ # =>
573
+ # ===== Run 10 connected tests ==== Begin...
574
+ # ===== Run test commands on 10 connected nodes (timeout to 50 secs) ==== Begin...
575
+ # Executing actions [100%] - | C| - [ Queue: 0 - Processing: 0 - Done: 10 - Total: 10 ]
576
+ # ===== Run test commands on 10 connected nodes (timeout to 50 secs) ==== ...End
577
+ #
578
+ # [ 2021-04-30 13:32:23 ] - [ Node dev1 ] - [ spectre ] - Start test...
579
+ # [ 2021-04-30 13:32:23 ] - [ Node dev1 ] - [ spectre ] - Test finished in 0.001014909 seconds.
580
+ # [ 2021-04-30 13:32:23 ] - [ Node dev10 ] - [ spectre ] - Start test...
581
+ # [ 2021-04-30 13:32:23 ] - [ Node dev10 ] - [ spectre ] - Test finished in 0.000775197 seconds.
582
+ # [ 2021-04-30 13:32:23 ] - [ Node dev2 ] - [ spectre ] - Start test...
583
+ # [ 2021-04-30 13:32:23 ] - [ Node dev2 ] - [ spectre ] - Test finished in 0.000576852 seconds.
584
+ # [ 2021-04-30 13:32:23 ] - [ Node dev3 ] - [ spectre ] - Start test...
585
+ # [ 2021-04-30 13:32:23 ] - [ Node dev3 ] - [ spectre ] - Test finished in 0.00043014 seconds.
586
+ # [ 2021-04-30 13:32:23 ] - [ Node dev4 ] - [ spectre ] - Start test...
587
+ # [ 2021-04-30 13:32:23 ] - [ Node dev4 ] - [ spectre ] - Test finished in 0.000708113 seconds.
588
+ # [ 2021-04-30 13:32:23 ] - [ Node dev5 ] - [ spectre ] - Start test...
589
+ # [ 2021-04-30 13:32:23 ] - [ Node dev5 ] - [ spectre ] - Test finished in 0.000220576 seconds.
590
+ # [ 2021-04-30 13:32:23 ] - [ Node dev6 ] - [ spectre ] - Start test...
591
+ # [ 2021-04-30 13:32:23 ] - [ Node dev6 ] - [ spectre ] - Test finished in 0.000458778 seconds.
592
+ # [ 2021-04-30 13:32:23 ] - [ Node dev7 ] - [ spectre ] - Start test...
593
+ # [ 2021-04-30 13:32:23 ] - [ Node dev7 ] - [ spectre ] - Test finished in 0.000219419 seconds.
594
+ # [ 2021-04-30 13:32:23 ] - [ Node dev8 ] - [ spectre ] - Start test...
595
+ # [ 2021-04-30 13:32:23 ] - [ Node dev8 ] - [ spectre ] - Test finished in 0.000209414 seconds.
596
+ # [ 2021-04-30 13:32:23 ] - [ Node dev9 ] - [ spectre ] - Start test...
597
+ # [ 2021-04-30 13:32:23 ] - [ Node dev9 ] - [ spectre ] - Test finished in 0.000406352 seconds.
598
+ # ===== Run 10 connected tests ==== ...End
599
+ #
600
+ #
601
+ # ========== Error report of 10 tests run on 10 nodes
602
+ #
603
+ # ======= 0 unexpected failing global tests:
604
+ #
605
+ #
606
+ # ======= 0 unexpected failing platform tests:
607
+ #
608
+ #
609
+ # ======= 0 unexpected failing node tests:
610
+ #
611
+ #
612
+ # ======= 0 unexpected failing platforms:
613
+ #
614
+ #
615
+ # ======= 0 unexpected failing nodes:
616
+ #
617
+ #
618
+ # ========== Stats by nodes list:
619
+ #
620
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
621
+ # | List name | # nodes | % tested | % expected success | % success | [Expected] [Error] [Success] [Non tested] |
622
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
623
+ # | No list | 21 | 47 % | 100 % | 100 % | ========================================= |
624
+ # | All | 21 | 47 % | 100 % | 100 % | ========================================= |
625
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
626
+ #
627
+ # ===== No unexpected errors =====
628
+
629
+ # Can we deploy some dev servers?
630
+ ./bin/deploy --node /dev\[4-7\]/
631
+ # =>
632
+ # ===== Packaging deployment ==== Begin...
633
+ # ===== Packaging deployment ==== ...End
634
+ #
635
+ # ===== Deploying on 4 nodes ==== Begin...
636
+ # ===== [ dev4 / python ] - HPC Service Deploy ===== Begin
637
+ # ===== [ dev4 / python ] - HPC Service Deploy ===== Begin
638
+ # [...]
639
+ # ===== [ dev7 / gcc ] - HPC Service Deploy ===== End
640
+ # ===== [ dev7 / gcc ] - HPC Service Deploy ===== End
641
+ # Executing actions [100%] - | C| - [ Queue: 0 - Processing: 0 - Done: 4 - Total: 4 ]
642
+ # ===== Saving deployment logs for 4 nodes ==== Begin...
643
+ # Executing actions [100%] - | C| - [ Queue: 0 - Processing: 0 - Done: 4 - Total: 4 ]
644
+ # ===== Saving deployment logs for 4 nodes ==== ...End
645
+ #
646
+ # ===== Deploying on 4 nodes ==== ...End
647
+
648
+ # Can we check last deployments everywhere?
649
+ ./bin/last_deploys
650
+ # =>
651
+ # +-------+---------------------+-------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------+
652
+ # | Node | Date | Admin | Services | Error |
653
+ # +-------+---------------------+-------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------+
654
+ # | dev1 | | | | Error: failed_command |
655
+ # | | | | | /bin/bash: line 1: cd: /var/log/deployments: No such file or directory |
656
+ # | | | | | Command '/tmp/hpc_ssh/platforms_ssh_5222020210430-2889-lctc2/ssh hpc.dev1 /bin/bash <<'HPC_EOF'' returned error code 1 (expected 0). |
657
+ # | dev10 | | | | Error: failed_command |
658
+ # | | | | | /bin/bash: line 1: cd: /var/log/deployments: No such file or directory |
659
+ # | | | | | Command '/tmp/hpc_ssh/platforms_ssh_5222020210430-2889-lctc2/ssh hpc.dev10 /bin/bash <<'HPC_EOF'' returned error code 1 (expected 0). |
660
+ # | dev2 | | | | Error: failed_command |
661
+ # | | | | | /bin/bash: line 1: cd: /var/log/deployments: No such file or directory |
662
+ # | | | | | Command '/tmp/hpc_ssh/platforms_ssh_5222020210430-2889-lctc2/ssh hpc.dev2 /bin/bash <<'HPC_EOF'' returned error code 1 (expected 0). |
663
+ # | dev3 | | | | Error: failed_command |
664
+ # | | | | | /bin/bash: line 1: cd: /var/log/deployments: No such file or directory |
665
+ # | | | | | Command '/tmp/hpc_ssh/platforms_ssh_5222020210430-2889-lctc2/ssh hpc.dev3 /bin/bash <<'HPC_EOF'' returned error code 1 (expected 0). |
666
+ # | dev8 | | | | Error: failed_command |
667
+ # | | | | | /bin/bash: line 1: cd: /var/log/deployments: No such file or directory |
668
+ # | | | | | Command '/tmp/hpc_ssh/platforms_ssh_5222020210430-2889-lctc2/ssh hpc.dev8 /bin/bash <<'HPC_EOF'' returned error code 1 (expected 0). |
669
+ # | dev9 | | | | Error: failed_command |
670
+ # | | | | | /bin/bash: line 1: cd: /var/log/deployments: No such file or directory |
671
+ # | | | | | Command '/tmp/hpc_ssh/platforms_ssh_5222020210430-2889-lctc2/ssh hpc.dev9 /bin/bash <<'HPC_EOF'' returned error code 1 (expected 0). |
672
+ # | dev4 | 2021-04-30 13:36:21 | root | python | |
673
+ # | dev5 | 2021-04-30 13:36:21 | root | python | |
674
+ # | dev6 | 2021-04-30 13:36:21 | root | gcc | |
675
+ # | dev7 | 2021-04-30 13:36:21 | root | gcc | |
676
+ # | local | 2021-04-28 17:34:17 | root | my-service | |
677
+ # | web1 | 2021-04-28 17:34:17 | root | web-hello, my-service | |
678
+ # | web10 | 2021-04-28 17:34:17 | root | web-hello | |
679
+ # | web2 | 2021-04-28 17:34:17 | root | web-hello, my-service | |
680
+ # | web3 | 2021-04-28 17:34:17 | root | web-hello, my-service | |
681
+ # | web4 | 2021-04-28 17:34:17 | root | web-hello, my-service | |
682
+ # | web5 | 2021-04-28 17:34:17 | root | web-hello, my-service | |
683
+ # | web6 | 2021-04-28 17:34:17 | root | web-hello | |
684
+ # | web7 | 2021-04-28 17:34:17 | root | web-hello | |
685
+ # | web8 | 2021-04-28 17:34:17 | root | web-hello | |
686
+ # | web9 | 2021-04-28 17:34:17 | root | web-hello | |
687
+ # +-------+---------------------+-------+-----------------------+---------------------------------------------------------------------------------------------------------------------------------------+
688
+ ```
689
+
690
+ That's a lot of processes that are now made available to every node handled by our platform repository, with just 1 single plugin and without having to modify anything on your team's repository!
691
+
692
+ As a bonus, your platform handler plugin also reported ways to parse the check or deploy logs to analyze them in terms of tasks (see the `parse_deploy_output` last method from the plugin we just wrote).
693
+ This opens up a new process in Hybrid Platforms Conductor: the checks for divergence or idempotence.
694
+ By knowing tasks' statuses from a deployment or a check, we can report if the nodes need changes or not.
695
+ The [`divergence` test plugin](/docs/plugins/test/divergence.md) is using this information to report nodes that are not aligned.
696
+
697
+ See it in action:
698
+ ```bash
699
+ ./bin/test --test divergence --node /dev/
700
+ # ===== Run 10 check-node tests ==== Begin...
701
+ # ===== Packaging deployment ==== Begin...
702
+ # ===== Packaging deployment ==== ...End
703
+ #
704
+ # ===== Checking on 10 nodes ==== Begin...
705
+ # Executing actions [100%] - | C| - [ Queue: 0 - Processing: 0 - Done: 10 - Total: 10 ]
706
+ # Executing actions [100%] - | C| - [ Queue: 0 - Processing: 0 - Done: 10 - Total: 10 ]
707
+ # ===== Checking on 10 nodes ==== ...End
708
+ #
709
+ # [ 2021-04-30 13:43:32 ] - [ Node dev1 ] - [ divergence ] - Start test...
710
+ # [ 2021-04-30 13:43:32 ] - [ Node dev1 ] - [ divergence ] - Test finished in 0.000292363 seconds.
711
+ # [ 2021-04-30 13:43:32 ] - [ Node dev10 ] - [ divergence ] - Start test...
712
+ # [2021-04-30 13:43:32 (PID 3316 / TID 62000)] ERROR - [ Divergence ] - [ #< Test divergence - Node dev10 > ] - Task Install tool has diverged
713
+ # ----- Changes:
714
+ # Missing
715
+ # -----
716
+ # [ 2021-04-30 13:43:32 ] - [ Node dev10 ] - [ divergence ] - Test finished in 0.000465428 seconds.
717
+ # [ 2021-04-30 13:43:32 ] - [ Node dev2 ] - [ divergence ] - Start test...
718
+ # [2021-04-30 13:43:32 (PID 3316 / TID 62000)] ERROR - [ Divergence ] - [ #< Test divergence - Node dev2 > ] - Task Install tool has diverged
719
+ # ----- Changes:
720
+ # Missing
721
+ # -----
722
+ # [ 2021-04-30 13:43:32 ] - [ Node dev2 ] - [ divergence ] - Test finished in 0.000382199 seconds.
723
+ # [ 2021-04-30 13:43:32 ] - [ Node dev3 ] - [ divergence ] - Start test...
724
+ # [2021-04-30 13:43:32 (PID 3316 / TID 62000)] ERROR - [ Divergence ] - [ #< Test divergence - Node dev3 > ] - Task Install tool has diverged
725
+ # ----- Changes:
726
+ # Missing
727
+ # -----
728
+ # [ 2021-04-30 13:43:32 ] - [ Node dev3 ] - [ divergence ] - Test finished in 0.000380728 seconds.
729
+ # [ 2021-04-30 13:43:32 ] - [ Node dev4 ] - [ divergence ] - Start test...
730
+ # [ 2021-04-30 13:43:32 ] - [ Node dev4 ] - [ divergence ] - Test finished in 0.000169298 seconds.
731
+ # [ 2021-04-30 13:43:32 ] - [ Node dev5 ] - [ divergence ] - Start test...
732
+ # [ 2021-04-30 13:43:32 ] - [ Node dev5 ] - [ divergence ] - Test finished in 0.00020049 seconds.
733
+ # [ 2021-04-30 13:43:32 ] - [ Node dev6 ] - [ divergence ] - Start test...
734
+ # [ 2021-04-30 13:43:32 ] - [ Node dev6 ] - [ divergence ] - Test finished in 0.000195422 seconds.
735
+ # [ 2021-04-30 13:43:32 ] - [ Node dev7 ] - [ divergence ] - Start test...
736
+ # [ 2021-04-30 13:43:32 ] - [ Node dev7 ] - [ divergence ] - Test finished in 0.000218584 seconds.
737
+ # [ 2021-04-30 13:43:32 ] - [ Node dev8 ] - [ divergence ] - Start test...
738
+ # [2021-04-30 13:43:32 (PID 3316 / TID 62000)] ERROR - [ Divergence ] - [ #< Test divergence - Node dev8 > ] - Task Install tool has diverged
739
+ # ----- Changes:
740
+ # Missing
741
+ # -----
742
+ # [ 2021-04-30 13:43:32 ] - [ Node dev8 ] - [ divergence ] - Test finished in 0.000323749 seconds.
743
+ # [ 2021-04-30 13:43:32 ] - [ Node dev9 ] - [ divergence ] - Start test...
744
+ # [2021-04-30 13:43:32 (PID 3316 / TID 62000)] ERROR - [ Divergence ] - [ #< Test divergence - Node dev9 > ] - Task Install tool has diverged
745
+ # ----- Changes:
746
+ # Missing
747
+ # -----
748
+ # [ 2021-04-30 13:43:32 ] - [ Node dev9 ] - [ divergence ] - Test finished in 0.000242289 seconds.
749
+ # ===== Run 10 check-node tests ==== ...End
750
+ #
751
+ #
752
+ # ========== Error report of 10 tests run on 10 nodes
753
+ #
754
+ # ======= 0 unexpected failing global tests:
755
+ #
756
+ #
757
+ # ======= 0 unexpected failing platform tests:
758
+ #
759
+ #
760
+ # ======= 1 unexpected failing node tests:
761
+ #
762
+ # ===== divergence found 5 nodes having errors:
763
+ # * [ dev10 ] - 1 errors:
764
+ # - Task Install tool has diverged
765
+ # * [ dev2 ] - 1 errors:
766
+ # - Task Install tool has diverged
767
+ # * [ dev3 ] - 1 errors:
768
+ # - Task Install tool has diverged
769
+ # * [ dev8 ] - 1 errors:
770
+ # - Task Install tool has diverged
771
+ # * [ dev9 ] - 1 errors:
772
+ # - Task Install tool has diverged
773
+ #
774
+ #
775
+ # ======= 0 unexpected failing platforms:
776
+ #
777
+ #
778
+ # ======= 5 unexpected failing nodes:
779
+ #
780
+ # ===== dev10 has 1 failing tests:
781
+ # * [ divergence ] - 1 errors:
782
+ # - Task Install tool has diverged
783
+ #
784
+ # ===== dev2 has 1 failing tests:
785
+ # * [ divergence ] - 1 errors:
786
+ # - Task Install tool has diverged
787
+ #
788
+ # ===== dev3 has 1 failing tests:
789
+ # * [ divergence ] - 1 errors:
790
+ # - Task Install tool has diverged
791
+ #
792
+ # ===== dev8 has 1 failing tests:
793
+ # * [ divergence ] - 1 errors:
794
+ # - Task Install tool has diverged
795
+ #
796
+ # ===== dev9 has 1 failing tests:
797
+ # * [ divergence ] - 1 errors:
798
+ # - Task Install tool has diverged
799
+ #
800
+ #
801
+ # ========== Stats by nodes list:
802
+ #
803
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
804
+ # | List name | # nodes | % tested | % expected success | % success | [Expected] [Error] [Success] [Non tested] |
805
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
806
+ # | No list | 21 | 47 % | 100 % | 50 % | ========================================= |
807
+ # | All | 21 | 47 % | 100 % | 50 % | ========================================= |
808
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
809
+ #
810
+ # ===== Some errors were found. Check output. =====
811
+ ```
812
+
813
+ Here we see that nodes `dev2`, `dev3`, `dev8`, `dev9` and `dev10` all have a diverging task named `Install tool`.
814
+ Logs above show us more details about the divergence, and we see that the reason is the `Missing` reported message, which is expected as we didn't deploy those nodes yet.
815
+
816
+ So now you are ready to write as many platform handlers as you have kinds of platform repositories.
817
+
818
+ Let's see other kinds of plugins.
819
+
820
+ <a name="test"></a>
821
+ ## Write your own tests
822
+
823
+ Another common plugin type you'll want to write are [tests](/docs/plugins.md#test).
824
+ Nothing is easier: a test plugin basically defines 1 test method and uses assertion methods in there to check and report errors.
825
+ Depending on the scope of your test (on your nodes, your platforms or global), the method name will be different (`test_on_node`, `test_on_platform` or `test`).
826
+
827
+ Let's add a test on our nodes that checks for the size used in the `/root` folder of our nodes.
828
+ We don't want this folder to store too many data, so we'll report errors if it uses more than 1MB of files.
829
+ We'll use the command [`du`](https://man7.org/linux/man-pages/man1/du.1.html) for that and parse easily its output.
830
+
831
+ Here is the code of our test plugin:
832
+ ```ruby
833
+ module MyHpcPlugins
834
+
835
+ module HpcPlugins
836
+
837
+ module Test
838
+
839
+ # Check root space
840
+ class RootSpace < HybridPlatformsConductor::Test
841
+
842
+ # Run test using SSH commands on the node.
843
+ # Instead of executing the SSH commands directly on each node for each test, this method returns the list of commands to run and the test framework then groups them in 1 SSH connection.
844
+ # [API] - @node can be used to adapt the command with the node.
845
+ #
846
+ # Result::
847
+ # * Hash<String,Object>: For each command to execute, information regarding the assertion.
848
+ # * Values can be:
849
+ # * Proc: The code block making the test given the stdout of the command. Here is the Proc description:
850
+ # * Parameters::
851
+ # * *stdout* (Array<String>): List of lines of the stdout of the command.
852
+ # * *stderr* (Array<String>): List of lines of the stderr of the command.
853
+ # * *return_code* (Integer): The return code of the command.
854
+ # * Hash<Symbol,Object>: More complete information, that can contain the following keys:
855
+ # * *validator* (Proc): The proc containing the assertions to perform (as described above). This key is mandatory.
856
+ # * *timeout* (Integer): Timeout to wait for this command to execute.
857
+ def test_on_node
858
+ # If this method is defined, it will be used to execute SSH commands on each node that is being tested.
859
+ # For each SSH command, a validator code block will be called with the stdout of the command run remotely on the node.
860
+ # In place of a simple validator code block, a more complex structure can be used to give more info (for example timeout).
861
+ {
862
+ 'du -sk /root' => proc do |stdout|
863
+ # stdout contains the output of our du command
864
+ used_kb = stdout.first.split.first.to_i
865
+ error "Root space used is #{used_kb}KB - too much!" if used_kb > 1024
866
+ end
867
+ }
868
+ end
869
+
870
+ end
871
+
872
+ end
873
+
874
+ end
875
+
876
+ end
877
+ ```
878
+
879
+ Let's write it in our Rubygem:
880
+ ```bash
881
+ mkdir -p ~/hpc_tutorial/my_hpc_plugins/lib/my_hpc_plugins/hpc_plugins/test
882
+ cat <<EOF >~/hpc_tutorial/my_hpc_plugins/lib/my_hpc_plugins/hpc_plugins/test/root_space.rb
883
+ # --- Copy-paste the previous Ruby code here ---
884
+ EOF
885
+ ```
886
+
887
+ And now let's put some big files in some of our `devN` nodes' `root` account to simulate space filling up:
888
+ ```bash
889
+ ./bin/run --node /dev\[5-7\]/ --command 'dd if=/dev/zero of=/root/big_file bs=1024 count=2048'
890
+ # =>
891
+ # 2048+0 records in
892
+ # 2048+0 records out
893
+ # 2097152 bytes (2.1 MB, 2.0 MiB) copied, 0.0138115 s, 152 MB/s
894
+ # 2048+0 records in
895
+ # 2048+0 records out
896
+ # 2097152 bytes (2.1 MB, 2.0 MiB) copied, 0.00515761 s, 407 MB/s
897
+ # 2048+0 records in
898
+ # 2048+0 records out
899
+ # 2097152 bytes (2.1 MB, 2.0 MiB) copied, 0.0044817 s, 468 MB/s
900
+ ```
901
+
902
+ Time to check that our test plugin works out-of-the-box :D
903
+ ```bash
904
+ ./bin/test --node /dev/ --test root_space
905
+ # =>
906
+ # ===== Run 10 connected tests ==== Begin...
907
+ # ===== Run test commands on 10 connected nodes (timeout to 25 secs) ==== Begin...
908
+ # Executing actions [100%] - | C| - [ Queue: 0 - Processing: 0 - Done: 10 - Total: 10 ]
909
+ # ===== Run test commands on 10 connected nodes (timeout to 25 secs) ==== ...End
910
+ #
911
+ # [ 2021-04-30 14:15:51 ] - [ Node dev1 ] - [ root_space ] - Start test...
912
+ # [ 2021-04-30 14:15:51 ] - [ Node dev1 ] - [ root_space ] - Test finished in 0.000240216 seconds.
913
+ # [ 2021-04-30 14:15:51 ] - [ Node dev10 ] - [ root_space ] - Start test...
914
+ # [ 2021-04-30 14:15:51 ] - [ Node dev10 ] - [ root_space ] - Test finished in 0.000139912 seconds.
915
+ # [ 2021-04-30 14:15:51 ] - [ Node dev2 ] - [ root_space ] - Start test...
916
+ # [ 2021-04-30 14:15:51 ] - [ Node dev2 ] - [ root_space ] - Test finished in 0.00011111 seconds.
917
+ # [ 2021-04-30 14:15:51 ] - [ Node dev3 ] - [ root_space ] - Start test...
918
+ # [ 2021-04-30 14:15:51 ] - [ Node dev3 ] - [ root_space ] - Test finished in 4.0237e-05 seconds.
919
+ # [ 2021-04-30 14:15:51 ] - [ Node dev4 ] - [ root_space ] - Start test...
920
+ # [ 2021-04-30 14:15:51 ] - [ Node dev4 ] - [ root_space ] - Test finished in 4.4058e-05 seconds.
921
+ # [ 2021-04-30 14:15:51 ] - [ Node dev5 ] - [ root_space ] - Start test...
922
+ # [2021-04-30 14:15:51 (PID 4077 / TID 56180)] ERROR - [ RootSpace ] - [ #< Test root_space - Node dev5 > ] - Root space used is 2076KB - too much!
923
+ # [ 2021-04-30 14:15:51 ] - [ Node dev5 ] - [ root_space ] - Test finished in 0.002698342 seconds.
924
+ # [ 2021-04-30 14:15:51 ] - [ Node dev6 ] - [ root_space ] - Start test...
925
+ # [2021-04-30 14:15:51 (PID 4077 / TID 56180)] ERROR - [ RootSpace ] - [ #< Test root_space - Node dev6 > ] - Root space used is 2076KB - too much!
926
+ # [ 2021-04-30 14:15:51 ] - [ Node dev6 ] - [ root_space ] - Test finished in 0.000527592 seconds.
927
+ # [ 2021-04-30 14:15:51 ] - [ Node dev7 ] - [ root_space ] - Start test...
928
+ # [2021-04-30 14:15:51 (PID 4077 / TID 56180)] ERROR - [ RootSpace ] - [ #< Test root_space - Node dev7 > ] - Root space used is 2076KB - too much!
929
+ # [ 2021-04-30 14:15:51 ] - [ Node dev7 ] - [ root_space ] - Test finished in 0.000327025 seconds.
930
+ # [ 2021-04-30 14:15:51 ] - [ Node dev8 ] - [ root_space ] - Start test...
931
+ # [ 2021-04-30 14:15:51 ] - [ Node dev8 ] - [ root_space ] - Test finished in 3.0503e-05 seconds.
932
+ # [ 2021-04-30 14:15:51 ] - [ Node dev9 ] - [ root_space ] - Start test...
933
+ # [ 2021-04-30 14:15:51 ] - [ Node dev9 ] - [ root_space ] - Test finished in 0.000231408 seconds.
934
+ # ===== Run 10 connected tests ==== ...End
935
+ #
936
+ #
937
+ # ========== Error report of 10 tests run on 10 nodes
938
+ #
939
+ # ======= 0 unexpected failing global tests:
940
+ #
941
+ #
942
+ # ======= 0 unexpected failing platform tests:
943
+ #
944
+ #
945
+ # ======= 1 unexpected failing node tests:
946
+ #
947
+ # ===== root_space found 3 nodes having errors:
948
+ # * [ dev5 ] - 1 errors:
949
+ # - Root space used is 2076KB - too much!
950
+ # * [ dev6 ] - 1 errors:
951
+ # - Root space used is 2076KB - too much!
952
+ # * [ dev7 ] - 1 errors:
953
+ # - Root space used is 2076KB - too much!
954
+ #
955
+ #
956
+ # ======= 0 unexpected failing platforms:
957
+ #
958
+ #
959
+ # ======= 3 unexpected failing nodes:
960
+ #
961
+ # ===== dev5 has 1 failing tests:
962
+ # * [ root_space ] - 1 errors:
963
+ # - Root space used is 2076KB - too much!
964
+ #
965
+ # ===== dev6 has 1 failing tests:
966
+ # * [ root_space ] - 1 errors:
967
+ # - Root space used is 2076KB - too much!
968
+ #
969
+ # ===== dev7 has 1 failing tests:
970
+ # * [ root_space ] - 1 errors:
971
+ # - Root space used is 2076KB - too much!
972
+ #
973
+ #
974
+ # ========== Stats by nodes list:
975
+ #
976
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
977
+ # | List name | # nodes | % tested | % expected success | % success | [Expected] [Error] [Success] [Non tested] |
978
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
979
+ # | No list | 21 | 47 % | 100 % | 70 % | ========================================= |
980
+ # | All | 21 | 47 % | 100 % | 70 % | ========================================= |
981
+ # +-----------+---------+----------+--------------------+-----------+-------------------------------------------+
982
+ #
983
+ # ===== Some errors were found. Check output. =====
984
+ ```
985
+ Indeed we see that `dev5`, `dev6` and `dev7` are failing the test.
986
+
987
+ <a name="report"></a>
988
+ ## Enough of stdout, we want to report to other tools
989
+
990
+ Being able to have all your processes at your terminal's fingertips is great, but what if you want to integrate to other reporting, monitoring or auditing tools?
991
+
992
+ A simple way to do is to write your own [`report` plugin](/docs/plugins.md#report) for inventory reporting, or [`test_report` plugin](/docs/plugins.md#test_report) for tests results reporting.
993
+ From such plugins you could push your reports to external APIs, and therefore populate data from other tools, CMDBs, monitoring, without duplicating the source of your inventory.
994
+
995
+ So let's say one of our web services (`web10`) is in fact a disguised reporting tool that should display our inventory ;-)
996
+ Remember how those web services were just displaying the content of the file `/root/hello_world.txt`?
997
+ Now we want `web10` to be a reporting tool that has to display our inventory.
998
+ For that we'll create a report plugin that will publish to our `web10` instance.
999
+
1000
+ Here is the code of our report plugin:
1001
+ ```ruby
1002
+ # This file is an example of a Reports plugin that can be used to dump information about the platforms.
1003
+ # The MyReportPlugin example contains example of code that could be used to write a plugin for a new kind of report.
1004
+ require 'hybrid_platforms_conductor/report'
1005
+
1006
+ module MyHpcPlugins
1007
+
1008
+ module HpcPlugins
1009
+
1010
+ module Report
1011
+
1012
+ # Publish reports to our web reporting tool
1013
+ class WebReport < HybridPlatformsConductor::Report
1014
+
1015
+ # Give the list of supported locales by this report generator
1016
+ # [API] - This method is mandatory.
1017
+ #
1018
+ # Result::
1019
+ # * Array<Symbol>: List of supported locales
1020
+ def self.supported_locales
1021
+ # This method has to publish the list of translations it accepts.
1022
+ [:en]
1023
+ end
1024
+
1025
+ # Create a report for a list of nodes, in a given locale
1026
+ # [API] - This method is mandatory.
1027
+ #
1028
+ # Parameters::
1029
+ # * *nodes* (Array<String>): List of nodes
1030
+ # * *locale_code* (Symbol): The locale code
1031
+ def report_for(nodes, locale_code)
1032
+ # This method simply provides a report for a given list of nodes in the desired locale.
1033
+ # The locale will be one of the supported ones.
1034
+ # Generate the report in a file to be uploaded on web10.
1035
+ File.write(
1036
+ '/tmp/web_report.txt',
1037
+ @platforms_handler.known_platforms.map do |platform|
1038
+ "= Inventory for platform #{platform.repository_path} of type #{platform.platform_type}:\n" +
1039
+ platform.known_nodes.map do |node|
1040
+ "* Node #{node} (IP: #{@nodes_handler.get_host_ip_of(node)}, Hostname: #{@nodes_handler.get_hostname_of(node)})."
1041
+ end.join("\n")
1042
+ end.join("\n")
1043
+ )
1044
+ # Upload the file on our web10 instance
1045
+ system 'scp -o StrictHostKeyChecking=no /tmp/web_report.txt web10.hpc_tutorial.org:/root/hello_world.txt'
1046
+ out 'Upload successful'
1047
+ end
1048
+
1049
+ end
1050
+
1051
+ end
1052
+
1053
+ end
1054
+
1055
+ end
1056
+ ```
1057
+
1058
+ Let's write it in our Rubygem:
1059
+ ```bash
1060
+ mkdir -p ~/hpc_tutorial/my_hpc_plugins/lib/my_hpc_plugins/hpc_plugins/report
1061
+ cat <<EOF >~/hpc_tutorial/my_hpc_plugins/lib/my_hpc_plugins/hpc_plugins/report/web_report.rb
1062
+ # --- Copy-paste the previous Ruby code here ---
1063
+ EOF
1064
+ ```
1065
+
1066
+ And now we can use our new report plugin to publish to our web reporting tool:
1067
+ ```bash
1068
+ ./bin/report --format web_report
1069
+ # =>
1070
+ # web_report.txt 100% 1483 3.1MB/s 00:00
1071
+ # Upload successful
1072
+ ```
1073
+
1074
+ And we can check our new web reporting tool :D
1075
+ ```bash
1076
+ curl http://web10.hpc_tutorial.org
1077
+ # =>
1078
+ # = Inventory for platform /root/hpc_tutorial/my-service-conf-repo of type yaml_inventory:
1079
+ # * Node local (IP: , Hostname: ).
1080
+ # * Node web1 (IP: 172.17.0.3, Hostname: web1.hpc_tutorial.org).
1081
+ # * Node web2 (IP: 172.17.0.4, Hostname: web2.hpc_tutorial.org).
1082
+ # * Node web3 (IP: 172.17.0.5, Hostname: web3.hpc_tutorial.org).
1083
+ # * Node web4 (IP: 172.17.0.6, Hostname: web4.hpc_tutorial.org).
1084
+ # * Node web5 (IP: 172.17.0.7, Hostname: web5.hpc_tutorial.org).
1085
+ # * Node web6 (IP: 172.17.0.8, Hostname: web6.hpc_tutorial.org).
1086
+ # * Node web7 (IP: 172.17.0.9, Hostname: web7.hpc_tutorial.org).
1087
+ # * Node web8 (IP: 172.17.0.10, Hostname: web8.hpc_tutorial.org).
1088
+ # * Node web9 (IP: 172.17.0.11, Hostname: web9.hpc_tutorial.org).
1089
+ # * Node web10 (IP: 172.17.0.12, Hostname: web10.hpc_tutorial.org).
1090
+ # = Inventory for platform /root/hpc_tutorial/dev-servers-conf-repo of type json_bash:
1091
+ # * Node dev1 (IP: 172.17.0.13, Hostname: dev1.hpc_tutorial.org).
1092
+ # * Node dev2 (IP: 172.17.0.14, Hostname: dev2.hpc_tutorial.org).
1093
+ # * Node dev3 (IP: 172.17.0.15, Hostname: dev3.hpc_tutorial.org).
1094
+ # * Node dev4 (IP: 172.17.0.16, Hostname: dev4.hpc_tutorial.org).
1095
+ # * Node dev5 (IP: 172.17.0.17, Hostname: dev5.hpc_tutorial.org).
1096
+ # * Node dev6 (IP: 172.17.0.18, Hostname: dev6.hpc_tutorial.org).
1097
+ # * Node dev7 (IP: 172.17.0.19, Hostname: dev7.hpc_tutorial.org).
1098
+ # * Node dev8 (IP: 172.17.0.20, Hostname: dev8.hpc_tutorial.org).
1099
+ # * Node dev9 (IP: 172.17.0.21, Hostname: dev9.hpc_tutorial.org).
1100
+ # * Node dev10 (IP: 172.17.0.22, Hostname: dev10.hpc_tutorial.org).
1101
+ ```
1102
+
1103
+ It works like a charm!
1104
+
1105
+ **Now you have plenty of ways to integrate your processes with Hybrid Platforms Conductor, and integrate Hybrid Platforms Conductor with other processes as well.**
1106
+
1107
+ The goal is for you to be agile and handle your inventory and platforms without duplicating information and efforts, and still keeping your heterogenous environments.
1108
+ Then you can apply simple and normalized DevOps processes that can encompass all your platforms so that you operate and test them uniformely.
1109
+
1110
+ <a name="what-next"></a>
1111
+ ## What next?
1112
+
1113
+ This concludes this simple tutorial.
1114
+ We hope it gave you a good glimpse of the power of Hybrid Platforms Conductor and how it helps you easily integrate heterogenous technologies into simple, agile and robust DevOps processes.
1115
+
1116
+ From now one, you are ready to dive deeper into the details:
1117
+ * The various [executables](/docs/executables.md) available will cover much more than what we've seen in this tutorial. Their processes is documented there, as well their dependencies.
1118
+ * The various [plugins](/docs/plugins.md) available can already fill some of your needs, and otherwise they can serve as examples for you to write your own, so looking into them is really insightful.
1119
+ * The [API](/docs/api.md) itself can be used from inside your plugins (in fact you already did it in the plugins you wrote in this tutorial), and also from any Ruby project. Having a good understanding of the API's organization will help you a lot.
1120
+
1121
+ We would love to reference your plugins as well here if you make them publicly available. Please don't refrain: if it's useful to you it will certainly be useful to others.
1122
+
1123
+ ---
1124
+ **<p style="text-align: center;">Tutorial navigation</p>**
1125
+
1126
+ | <sub>[Introduction](/docs/tutorial.md)</sub> | <sub>[1. Installation and first-time setup](/docs/tutorial/01_installation.md)</sub> | <sub>[2. Deploy and check a first node](/docs/tutorial/02_first_node.md)</sub> | <sub>[3. Scale your processes](/docs/tutorial/03_scale.md)</sub> | <sub>[4. Testing your processes and platforms](/docs/tutorial/04_test.md)</sub> | <nobr><sub><sub>&#128071;You are here&#128071;</sub></sub></nobr><br><sub>[5. Extend Hybrid Platforms Conductor with your own requirements](/docs/tutorial/05_extend_with_plugins.md)</sub> |
1127
+ | ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
1128
+ | <sub><sub>**[Use-case](/docs/tutorial.md#use-case)**</sub></sub> | <sub><sub>**[Dependencies installation](/docs/tutorial/01_installation.md#hpc-dependencies)**</sub></sub> | <sub><sub>**[Add your first node and its platform repository](/docs/tutorial/02_first_node.md#add-first-node)**</sub></sub> | <sub><sub>**[Provision our web services platform](/docs/tutorial/03_scale.md#provision)**</sub></sub> | <sub><sub>**[Hello test framework](/docs/tutorial/04_test.md#framework)**</sub></sub> | <sub><sub>**[Create your plugins' repository](/docs/tutorial/05_extend_with_plugins.md#plugins-repo)**</sub></sub> |
1129
+ | <sub><sub>**[Prerequisites](/docs/tutorial.md#prerequisites)**</sub></sub> | <sub><sub>**[Our platforms' main repository](/docs/tutorial/01_installation.md#main-repo)**</sub></sub> | <sub><sub>**[Check and deploy services on this node](/docs/tutorial/02_first_node.md#check-deploy)**</sub></sub> | <sub><sub>**[Run commands on our new web services](/docs/tutorial/03_scale.md#run)**</sub></sub> | <sub><sub>**[Testing your nodes](/docs/tutorial/04_test.md#nodes-tests)**</sub></sub> | <sub><sub>**[Your own platform handler](/docs/tutorial/05_extend_with_plugins.md#platform-handler)**</sub></sub> |
1130
+ | <sub><sub>**[Tutorial setup](/docs/tutorial.md#tutorial-setup)**</sub></sub> | | <sub><sub>**[Updating the configuration](/docs/tutorial/02_first_node.md#update)**</sub></sub> | <sub><sub>**[Check and deploy our web services on several nodes at once](/docs/tutorial/03_scale.md#check-deploy)**</sub></sub> | <sub><sub>**[Testing your platforms' configuration](/docs/tutorial/04_test.md#platforms-tests)**</sub></sub> | <sub><sub>**[Write your own tests](/docs/tutorial/05_extend_with_plugins.md#test)**</sub></sub> |
1131
+ | | | | | <sub><sub>**[Other kinds of tests](/docs/tutorial/04_test.md#other-tests)**</sub></sub> | <sub><sub>**[Enough of stdout, we want to report to other tools](/docs/tutorial/05_extend_with_plugins.md#report)**</sub></sub> |
1132
+ | | | | | | <sub><sub>**[What next?](/docs/tutorial/05_extend_with_plugins.md#what-next)**</sub></sub> |