swarm_cluster_cli_ope 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +9 -0
  6. data/Gemfile +6 -0
  7. data/Gemfile.lock +39 -0
  8. data/LICENSE.txt +21 -0
  9. data/README.md +121 -0
  10. data/Rakefile +2 -0
  11. data/exe/swarm_cli_ope +4 -0
  12. data/lib/swarm_cluster_cli_ope.rb +8 -0
  13. data/lib/swarm_cluster_cli_ope/cli.rb +251 -0
  14. data/lib/swarm_cluster_cli_ope/commands/base.rb +70 -0
  15. data/lib/swarm_cluster_cli_ope/commands/container.rb +24 -0
  16. data/lib/swarm_cluster_cli_ope/commands/service.rb +42 -0
  17. data/lib/swarm_cluster_cli_ope/commands/swarm.rb +14 -0
  18. data/lib/swarm_cluster_cli_ope/commands/task.rb +11 -0
  19. data/lib/swarm_cluster_cli_ope/configuration.rb +189 -0
  20. data/lib/swarm_cluster_cli_ope/configuration_concern.rb +24 -0
  21. data/lib/swarm_cluster_cli_ope/logger_concern.rb +26 -0
  22. data/lib/swarm_cluster_cli_ope/manager.rb +9 -0
  23. data/lib/swarm_cluster_cli_ope/models/base.rb +42 -0
  24. data/lib/swarm_cluster_cli_ope/models/container.rb +78 -0
  25. data/lib/swarm_cluster_cli_ope/models/mapped_volume.rb +43 -0
  26. data/lib/swarm_cluster_cli_ope/models/service.rb +38 -0
  27. data/lib/swarm_cluster_cli_ope/models/stack.rb +18 -0
  28. data/lib/swarm_cluster_cli_ope/models/task.rb +27 -0
  29. data/lib/swarm_cluster_cli_ope/node.rb +80 -0
  30. data/lib/swarm_cluster_cli_ope/shell_command_execution.rb +68 -0
  31. data/lib/swarm_cluster_cli_ope/shell_command_response.rb +68 -0
  32. data/lib/swarm_cluster_cli_ope/version.rb +3 -0
  33. data/lib/swarm_cluster_cli_ope/worker.rb +7 -0
  34. data/swarm_cluster_cli_ope.gemspec +36 -0
  35. metadata +138 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '09565df25f695d7e64c5034d7daaa833ba640c61b2b326ad046601355f13f705'
4
+ data.tar.gz: c997f3969018ae3335e86987595b7c5e1bba6792477c6c343f27e291a1430f47
5
+ SHA512:
6
+ metadata.gz: b1f2e55552084f16fd1b0f2bc9955113771212b52d5f9d508aac86a578e0bf1d95f2a513fa9b171e31cb7016d9899002331957d38fdc1e71afa0c1a677f95b59
7
+ data.tar.gz: a0daa2f6d6b4187d038eea485d65c88d5aa670760f99935d8115e4c8cccf6196f991b7e8f71a17881a44117f40a7d60cdde94a7d91707dc7eb154fb9ad70d4c1
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .idea
10
+ pkg
@@ -0,0 +1 @@
1
+ swarm_cluster_cli
@@ -0,0 +1 @@
1
+ ruby-2.5.3
@@ -0,0 +1,9 @@
1
+ ## Changelog
2
+
3
+ # 0.1.0
4
+ - rsync dei files da/verso cluster su cartella condivisa
5
+ - copia files direttamente in container
6
+ - shell in servizio
7
+ - mc in servizio
8
+ - configurazioni globali
9
+ - configurazioni di progetto
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in swarm_cluster_cli_ope.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
@@ -0,0 +1,39 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ swarm_cluster_cli_ope (0.1.2)
5
+ activesupport
6
+ open4
7
+ thor (~> 1.0)
8
+ zeitwerk (~> 2.3)
9
+
10
+ GEM
11
+ remote: https://rubygems.org/
12
+ specs:
13
+ activesupport (6.0.2.2)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (>= 0.7, < 2)
16
+ minitest (~> 5.1)
17
+ tzinfo (~> 1.1)
18
+ zeitwerk (~> 2.2)
19
+ concurrent-ruby (1.1.6)
20
+ i18n (1.8.2)
21
+ concurrent-ruby (~> 1.0)
22
+ minitest (5.14.0)
23
+ open4 (1.3.4)
24
+ rake (12.3.3)
25
+ thor (1.0.1)
26
+ thread_safe (0.3.6)
27
+ tzinfo (1.2.7)
28
+ thread_safe (~> 0.1)
29
+ zeitwerk (2.3.0)
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ rake (~> 12.0)
36
+ swarm_cluster_cli_ope!
37
+
38
+ BUNDLED WITH
39
+ 1.17.3
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2020 Marino Bonetti
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,121 @@
1
+ # SwarmClusterCliOpe
2
+ WIP to translate
3
+ Gemma per la gestione semplificata degli operatori con un cluster swarm
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'swarm_cluster_cli_ope'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install swarm_cluster_cli_ope
20
+
21
+ ## Usage
22
+
23
+ Una volta installato lanciare il comando
24
+
25
+ ```swarm_cluster_cli_ope install``` che si occuperà di configurare le varie impostazioni dell'ambiente
26
+
27
+ FILE di configurazione base:
28
+ ```json
29
+ {"version":"0.1.0","dev_mode":1,"log_level": "3","connections_maps":{"swm1": "swarm_node_1","swm2": "swarm_node_2","swm3": "swarm_node_3"}}
30
+ ```
31
+
32
+ ### LogLevel:
33
+ 0 ERROR
34
+ 1 WARN
35
+ 2 INFO
36
+ 3 DEBUG
37
+
38
+
39
+ ### Configuratione di un progetto
40
+ Si occupa di generare nel progetto il file di configurazione in cui impostare impostazioni specifiche di progetto
41
+ quali stack_name
42
+ ```shell script
43
+ swarm_cli_ope configure_project STACK_NAME
44
+ ```
45
+
46
+ ### Configurazioni applicate nel progetto:
47
+ ```shell script
48
+ swarm_cli_ope config
49
+ ```
50
+
51
+ ### Elenco di tutti gli stack disponibili:
52
+ ```shell script
53
+ swarm_cli_ope stacks
54
+ ```
55
+
56
+
57
+ ### MC:
58
+ Apre MC collegato al container del servizio specificato
59
+ ```shell script
60
+ swarm_cli_ope mc SERVICE_NAME --stack-name=NOME_STACK
61
+ ```
62
+
63
+ ### SHELL:
64
+ Apre una shell (default bash) collegato al container del servizio specificato
65
+ ```shell script
66
+ swarm_cli_ope shell SERVICE_NAME --stack-name=NOME_STACK
67
+ ```
68
+
69
+ ### Elenco di tutti i servizi
70
+ Se siamo nel progetto con il file di progetto vedremo comunque i servizi filtrati
71
+ ```shell script
72
+ swarm_cli_ope services
73
+ ```
74
+
75
+ filtrando per stack:
76
+
77
+ ```shell script
78
+ swarm_cli_ope services --stack-name=NOME_STACK
79
+ ```
80
+
81
+ ### Copia di files da/verso container attraverso il docker cp
82
+ ```shell script
83
+ swarm_cli_ope cp --stack-name=NOME_STACK PATH_FILE_LOCALE NOME_SERVIZIO:DESTINAZIONE_NEL_CONTAINER
84
+ ```
85
+ ES:
86
+ ```shell script
87
+ swarm_cli_ope cp --stack-name=webapps-examinerapp-staging ./test_folder/test_1/cartella_bindata/test jeapp:/tmp/.
88
+ ```
89
+
90
+ ### Rsync da/a container a/da locale
91
+
92
+ Utilizzare `rsync_binded_from` per scaricare e `rsync_binded_to` per caricare
93
+
94
+
95
+ ```shell script
96
+ swarm_cli_ope rsync_binded_from --stack-name=STACK_NAME --service_name NOME_SERVIZIO_SENZA_STACK --binded-container-folders CARTELLA_CONTAINER --local-folder CARTELLA_DESTINAZIONE
97
+ ```
98
+
99
+ ES:
100
+ ```shell script
101
+ swarm_cli_ope rsync_binded_from --stack-name=web-site-ranchilbosco-production --service_name wordpress --binded-container-folders /var/www/html/wp-content/uploads --destination ./uploads
102
+ ```
103
+
104
+
105
+ ## Development
106
+
107
+ nel file di configurazione creato nella home aggiungere la chiave "dev_mode":1 per collegarsi localmente
108
+
109
+ ### Abbiamo due tasks swarm di simulazione
110
+ ```shell script
111
+ docker stack deploy -c test_folder/test_1/docker_compose.yml test1
112
+ docker stack deploy -c test_folder/test_2/docker_compose.yml test2
113
+ ```
114
+
115
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
116
+
117
+
118
+ ## License
119
+
120
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
121
+
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../lib/swarm_cluster_cli_ope"
3
+
4
+ SwarmClusterCliOpe::Cli.start
@@ -0,0 +1,8 @@
1
+ require "zeitwerk"
2
+ loader = Zeitwerk::Loader.for_gem
3
+ loader.setup # ready!
4
+
5
+ module SwarmClusterCliOpe
6
+ class Error < StandardError; end
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,251 @@
1
+ require 'thor'
2
+ require 'mkmf'
3
+ module SwarmClusterCliOpe
4
+
5
+ class Cli < Thor
6
+ include LoggerConcern
7
+ include ConfigurationConcern
8
+ include Thor::Actions
9
+
10
+ def self.exit_on_failure?
11
+ true
12
+ end
13
+
14
+ desc "install", "Creazione della configurazione base della gemma"
15
+
16
+ def install
17
+ #contolliamo se presente la configurazione base nella home
18
+ if Configuration.exist_base?
19
+ say "Configurazione già presente"
20
+ else
21
+ #se non presente allora chiediamo le varie configurazioni
22
+ lista = []
23
+ loop do
24
+ connection_name = ask("Aggiungi un server alla lista dei server Manager(inserire uri: ssh://server | unix:///socket/path:")
25
+ result = Node.info(connection_name)
26
+ node = Node.new(name: result.Name, connection_uri: connection_name)
27
+ say "Aggiungo #{node.name} che si connette con DOCKER_HOST=#{node.connection_uri}"
28
+ lista << node
29
+ break if no? "Vuoi inserire al server?[n,no]"
30
+ end
31
+ #scriviamo le varie configurazioni
32
+ cfg = cfgs
33
+ cfg.nodes = lista
34
+ cfg.save_base_cfgs
35
+ end
36
+
37
+ end
38
+
39
+ desc "config", "Visualizza le configurazioni mergiate (HOME + Project)"
40
+
41
+ def config
42
+ puts JSON.pretty_generate(cfgs.class.merged_configurations)
43
+ end
44
+
45
+
46
+ # DOCKER_HOST=ssh://swarm_node_1 docker stack ls --format="{{json .}}"
47
+ desc "stacks", "Lista degli stacks nel cluster"
48
+
49
+ def stacks
50
+ Models::Stack.all.each do |s|
51
+ puts s.name
52
+ end
53
+ end
54
+
55
+ desc "services", "lista dei servizi per uno stack"
56
+ option :stack_name, required: false, type: :string, default: cfgs.stack_name
57
+
58
+ def services
59
+ Models::Service.all(stack_name: options[:stack_name]).each do |s|
60
+ puts s.name
61
+ end
62
+ end
63
+
64
+ desc "mc SERVICE_NAME", "Apre MC tra la cartella attuale e il container (potrebbe dar luogo a degli errori, ma funziona)"
65
+ option :stack_name, required: false, type: :string, default: cfgs.stack_name
66
+
67
+ def mc(service_name)
68
+
69
+ # Disabilito output della libreria
70
+ MakeMakefile::Logging.instance_variable_set(:@logfile, File::NULL)
71
+ unless find_executable 'mc'
72
+ puts "Non hai installato MC"
73
+ exit 0
74
+ end
75
+
76
+ begin
77
+ container = Models::Container.find_by_service_name(service_name, stack_name: options[:stack_name])
78
+
79
+ server = container.node.hostname
80
+
81
+ # Creo container ssh
82
+ # DOCKER_HOST=ssh://swarm_node_1 docker run --rm -d -p 12222:22 \
83
+ # --volumes-from sistemi-test_swarm_cluster_cli_wordpress.1.zbbz1xxh4vzzccndvs973jnuc \
84
+ # sickp/alpine-sshd:7.5
85
+ #
86
+ cmd = container.docker_command
87
+ cmd.base_suffix_command = ''
88
+ shell_operation = cmd.command do |c|
89
+ c.add("run --rm -d -p 42222:22 --volumes-from #{container.id} sickp/alpine-sshd:7.5")
90
+ end
91
+
92
+ puts "Creazione container #{shell_operation.string_command}"
93
+ id_container = shell_operation.execute.raw_result[:stdout]
94
+ puts "Container generato con id:#{id_container}"
95
+
96
+ # eseguo tunnel verso nodo e container ssh
97
+ socket_ssh_path = "/tmp/socket_ssh_#{id_container}"
98
+ # ssh -f -N -T -M -S <path-to-socket> -L 13333:0.0.0.0:42222 <server>
99
+ cmd_tunnel = ["ssh", "-f -N -T -M", "-S #{socket_ssh_path}", "-L 13333:0.0.0.0:42222", server].join(" ")
100
+ puts "Apro tunnel"
101
+ puts cmd_tunnel
102
+ system(cmd_tunnel)
103
+
104
+ # apro MC
105
+ # mc . sftp://root:root@0.0.0.0:13333
106
+ mc_cmd = "mc . sftp://root:root@0.0.0.0:13333"
107
+ puts "Apro MC"
108
+ puts mc_cmd
109
+ system(mc_cmd)
110
+ ensure
111
+ if socket_ssh_path
112
+ # chiudo tunnel
113
+ # ssh -S <path-to-socket> -O exit <server>
114
+ close_tunnel_cmd = "ssh -S #{socket_ssh_path} -O exit #{server}"
115
+ puts "Chiudo tunnel"
116
+ # say close_tunnel_cmd
117
+ ShellCommandExecution.new(close_tunnel_cmd).execute
118
+ end
119
+
120
+ if id_container
121
+ # cancello container
122
+ # docker stop #{id_container}
123
+ puts "Spengo container di appoggio"
124
+ puts "docker stop #{id_container}"
125
+ cmd = container.docker_command
126
+ cmd.base_suffix_command = ''
127
+ stop_ssh_container = cmd.command do |c|
128
+ c.add("stop #{id_container}")
129
+ end
130
+ stop_ssh_container.execute
131
+ end
132
+
133
+ end
134
+ end
135
+
136
+ desc "cp SRC DEST", "Copia la sorgente in destinazione"
137
+ option :stack_name, required: false, type: :string, default: cfgs.stack_name
138
+ long_desc <<-LONGDESC
139
+ SRC e DEST possono essere un servizio, solo uno di essi può essere un servizio (TODO)
140
+ Per identificare che sia un servizio controllo se nella stringa è presete il :
141
+ il quale mi identifica l'inizio della PATH assoluta all'interno del primo container del servizio
142
+ dove copiare i files
143
+ LONGDESC
144
+
145
+ def cp(src, dest)
146
+ #identifico quale dei due è il servizio e quale la path
147
+ if src.match(/^(.*)\:/)
148
+ container = Models::Container.find_by_service_name(Regexp.last_match[1], stack_name: options[:stack_name])
149
+ ris = container.copy_out(src.match(/\:(.*)$/)[1], dest)
150
+ else
151
+ container = Models::Container.find_by_service_name(dest.match(/^(.*)\:/)[1], stack_name: options[:stack_name])
152
+ ris = container.copy_in(src, dest.match(/\:(.*)$/)[1])
153
+ end
154
+ puts "COMPLETATO" if ris
155
+ end
156
+
157
+
158
+ desc "configure_project STACK_NAME", "Genera il file di configurazione del progetto contenente il nome dello stack"
159
+
160
+ def configure_project(stack_name)
161
+ cfgs.stack_name = stack_name
162
+ cfgs.save_project_cfgs
163
+ end
164
+
165
+ desc "service_shell SERVICE_NAME", "apre una shell [default bash] dentro al container"
166
+ option :stack_name, required: false, type: :string, default: cfgs.stack_name
167
+ option :shell, required: false, type: :string, default: 'bash'
168
+
169
+ def service_shell(service_name)
170
+ container = Models::Container.find_by_service_name(service_name, stack_name: options[:stack_name])
171
+
172
+ cmd = container.docker_command
173
+ cmd.base_suffix_command = ''
174
+ shell_operation = cmd.command do |c|
175
+ c.add("exec -it #{container.id} #{options[:shell]}")
176
+ end
177
+
178
+ say "Stai entrando della shell in #{options[:shell]} del container #{options[:stack_name]}->#{container.name}[#{container.id}]"
179
+ system(shell_operation.string_command)
180
+ say "Shell chiusa"
181
+ end
182
+
183
+
184
+ desc "rsync_binded_from", "esegue un rsync dalla cartella bindata (viene sincronizzato il contenuto)"
185
+ option :stack_name, required: false, type: :string, default: cfgs.stack_name
186
+ option :service_name, required: true, type: :string
187
+ option :binded_container_folders, required: true, type: :string, desc: "path della cartella bindata all'interno del container da sincronizzare"
188
+ option :local_folder, required: false, type: :string, desc: "path della cartella dove sincronizzare il comando"
189
+
190
+ def rsync_binded_from
191
+ if yes? "Attenzione, i dati locali verranno sovrascritti/cancellati?[y,yes]"
192
+ rsync_binded(direction: :down, options: options)
193
+ end
194
+ end
195
+
196
+ desc "rsync_binded_to", "esegue un rsync verso la cartella bindata"
197
+ option :stack_name, required: false, type: :string, default: cfgs.stack_name
198
+ option :service_name, required: true, type: :string
199
+ option :binded_container_folders, required: true, type: :string, desc: "path della cartella bindata all'interno del container da sincronizzare"
200
+ option :local_folder, required: false, type: :string, desc: "path della cartella dove sincronizzare il comando"
201
+
202
+ def rsync_binded_to
203
+ if yes? "ATTENZIONE, i dati remoti verranno sovrascritti/cancellati da quelli locali?[y,yes]"
204
+ rsync_binded(direction: :up, options: options)
205
+ end
206
+ end
207
+
208
+
209
+ private
210
+
211
+ def rsync_binded(direction: :down, options: {})
212
+
213
+ # trovo il container del servizio
214
+ container = Models::Container.find_by_service_name(options[:service_name], stack_name: options[:stack_name])
215
+
216
+ if container.nil?
217
+ say "Container non trovato con #{options[:stack_name]}@##{options[:service_name]}"
218
+ exit 0
219
+ end
220
+
221
+
222
+ # trovo la cartella bindata e la relativa cartella sul nodo
223
+ volume = container.mapped_volumes.find { |v| v.destination == options[:binded_container_folders] and v.is_binded? }
224
+ if volume.nil?
225
+ say "Non ho trovato il volume bindato con questa destinazione all'interno del container #{options[:binded_container_folders]}"
226
+ exit 0
227
+ end
228
+
229
+ #costruisco il comando rsync fra cartella del nodo e cartella sul pc
230
+ cmd = ["rsync", "-zr", "--delete"]
231
+ if direction == :down
232
+ cmd << "#{volume.ssh_connection_path}/."
233
+ # creo la cartella in locale se non esiste
234
+ FileUtils.mkdir_p(options[:local_folder])
235
+ cmd << options[:local_folder]
236
+ end
237
+ if direction == :up
238
+ cmd << "#{options[:local_folder]}/."
239
+ cmd << volume.ssh_connection_path
240
+ end
241
+
242
+ cmd = ShellCommandExecution.new(cmd)
243
+
244
+ say "Comando da eseguire:"
245
+ say " #{cmd.string_command}"
246
+ if yes?("Confermare il comando?[y,yes]")
247
+ cmd.execute
248
+ end
249
+ end
250
+ end
251
+ end