swarm_cluster_cli_ope 0.1.6 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -1
- data/Gemfile.lock +6 -6
- data/README.md +87 -2
- data/lib/swarm_cluster_cli_ope/cli.rb +227 -120
- data/lib/swarm_cluster_cli_ope/commands/compose_container.rb +12 -0
- data/lib/swarm_cluster_cli_ope/commands/container.rb +7 -0
- data/lib/swarm_cluster_cli_ope/configuration.rb +106 -25
- data/lib/swarm_cluster_cli_ope/models/compose_container.rb +17 -0
- data/lib/swarm_cluster_cli_ope/models/container.rb +7 -1
- data/lib/swarm_cluster_cli_ope/models/service.rb +0 -1
- data/lib/swarm_cluster_cli_ope/sync_configs/base.rb +44 -0
- data/lib/swarm_cluster_cli_ope/sync_configs/copy.rb +31 -0
- data/lib/swarm_cluster_cli_ope/sync_configs/env_configs.rb +77 -0
- data/lib/swarm_cluster_cli_ope/sync_configs/mysql.rb +78 -0
- data/lib/swarm_cluster_cli_ope/sync_configs/rsync.rb +71 -0
- data/lib/swarm_cluster_cli_ope/sync_configs/sqlite3.rb +8 -0
- data/lib/swarm_cluster_cli_ope/version.rb +1 -1
- metadata +11 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3d344913376cd573bd0c65e8b1e13b21c22cea8da6765d5c96962bb8117a345b
|
4
|
+
data.tar.gz: aba83b091bb644491f7f2159c24ed5809d624713439037e368d874a7b702e2bf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 22e815330c638aead770d742b875961892650e73b68abed0b8fd897448d038ebbe4065a417073e9e4ce5039edaa40824eb617a43fa4200974cdb0363505fd83b
|
7
|
+
data.tar.gz: 63c7bff02ab029faf11f533a008f53b813381c0915524a501464ac75e52a24b3b930900af05c08d358945ea5587de1811eb93cdd2752cbe4bd3e22b1f8548962
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
## Changelog
|
2
2
|
|
3
|
+
# 0.3
|
4
|
+
- implementazione push pull con il comando **stacksync** di mysql
|
5
|
+
|
6
|
+
# 0.2
|
7
|
+
- implementazione comando **stacksync** con configurazioni nello stack per eseguire rsync di files e dump di sqlite3
|
8
|
+
|
3
9
|
# 0.1.0
|
4
10
|
- rsync dei files da/verso cluster su cartella condivisa
|
5
11
|
- copia files direttamente in container
|
6
12
|
- shell in servizio
|
7
13
|
- mc in servizio
|
8
14
|
- configurazioni globali
|
9
|
-
- configurazioni di progetto
|
15
|
+
- configurazioni di progetto
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
swarm_cluster_cli_ope (0.1
|
4
|
+
swarm_cluster_cli_ope (0.3.1)
|
5
5
|
activesupport
|
6
6
|
open4
|
7
7
|
thor (~> 1.0)
|
@@ -10,23 +10,23 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
activesupport (6.0.3)
|
13
|
+
activesupport (6.0.3.2)
|
14
14
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
15
|
i18n (>= 0.7, < 2)
|
16
16
|
minitest (~> 5.1)
|
17
17
|
tzinfo (~> 1.1)
|
18
18
|
zeitwerk (~> 2.2, >= 2.2.2)
|
19
|
-
concurrent-ruby (1.1.
|
20
|
-
i18n (1.8.
|
19
|
+
concurrent-ruby (1.1.7)
|
20
|
+
i18n (1.8.5)
|
21
21
|
concurrent-ruby (~> 1.0)
|
22
|
-
minitest (5.14.
|
22
|
+
minitest (5.14.2)
|
23
23
|
open4 (1.3.4)
|
24
24
|
rake (12.3.3)
|
25
25
|
thor (1.0.1)
|
26
26
|
thread_safe (0.3.6)
|
27
27
|
tzinfo (1.2.7)
|
28
28
|
thread_safe (~> 0.1)
|
29
|
-
zeitwerk (2.
|
29
|
+
zeitwerk (2.4.0)
|
30
30
|
|
31
31
|
PLATFORMS
|
32
32
|
ruby
|
data/README.md
CHANGED
@@ -36,6 +36,9 @@ FILE di configurazione base:
|
|
36
36
|
3 DEBUG
|
37
37
|
|
38
38
|
|
39
|
+
### ENV differenti
|
40
|
+
Tutti i comandi possono essere accompagnati con -e, per scopparli nel relativo ENVIRONMENT
|
41
|
+
|
39
42
|
### Configuratione di un progetto
|
40
43
|
Si occupa di generare nel progetto il file di configurazione in cui impostare impostazioni specifiche di progetto
|
41
44
|
quali stack_name (.swarm_cluster_project)
|
@@ -92,17 +95,99 @@ Utilizzare `rsync_binded_from` per scaricare e `rsync_binded_to` per caricare
|
|
92
95
|
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
|
93
96
|
```
|
94
97
|
|
98
|
+
### stacksync
|
99
|
+
Si occupa di scaricare|caricare,utilizzando le configurazioni presenti, i dati dallo stack remoto
|
100
|
+
|
101
|
+
Le configurazioni sono contenute nell'array: sync_configs.
|
102
|
+
|
103
|
+
ogni configurazione è composta da:
|
104
|
+
|
105
|
+
```json
|
106
|
+
{
|
107
|
+
service:""
|
108
|
+
how:""
|
109
|
+
configs:{ }
|
110
|
+
}
|
111
|
+
```
|
112
|
+
|
113
|
+
- service è il nome del servizio
|
114
|
+
- how è il come sincronizzare, definendo la tipologia:
|
115
|
+
- pg -> DB TODO
|
116
|
+
- mysql -> DB: dump del db con mysqldump
|
117
|
+
- sqlite3 -> DB: viene eseguita una copia del file
|
118
|
+
- rsync -> RSYNC
|
119
|
+
- configs: è un hash con le configurazioni per ogni tipo di sincronizzazione
|
120
|
+
|
121
|
+
Possibili CFGS per tipologia:
|
122
|
+
|
123
|
+
- rsync:
|
124
|
+
- local: -> path cartella locale
|
125
|
+
- remote: -> path cartella remota (contesto del container)
|
126
|
+
- sqlite3:
|
127
|
+
- local: -> path al file
|
128
|
+
- remote: -> path al file remoto (contesto del container)
|
129
|
+
- mysql:
|
130
|
+
- local: -> hash di configurazioni per il DB locale
|
131
|
+
- service: "db" -> nome del servizio nel compose locale, DEFAULT: quello definito sopra
|
132
|
+
- mysql_password_env: "MYSQL_PASSWORD" -> variabile ambiente interna al servizio contenente PASSWORD, DEFAULT: MYSQL_PASSWORD
|
133
|
+
- mysql_user_env: "MYSQL_USER" -> variabile ambiente interna al servizio contenente USERNAME, DEFAULT: MYSQL_USER
|
134
|
+
- database_name_env: "MYSQL_DATABASE" -> variabile ambiente interna al servizio contenente NOME DB, DEFAULT: MYSQL_DATABASE
|
135
|
+
- remote: -> hash di configurazioni per il DB remoto
|
136
|
+
- service: "db" -> nome del servizio nel compose locale, DEFAULT: quello definito sopra
|
137
|
+
- mysql_password_env: "MYSQL_PASSWORD" -> variabile ambiente interna al servizio contenente PASSWORD, DEFAULT: MYSQL_PASSWORD
|
138
|
+
- mysql_user_env: "MYSQL_USER" -> variabile ambiente interna al servizio contenente USERNAME, DEFAULT: MYSQL_USER
|
139
|
+
- database_name_env: "MYSQL_DATABASE" -> variabile ambiente interna al servizio contenente NOME DB, DEFAULT: MYSQL_DATABASE
|
140
|
+
|
141
|
+
#### EXAMPLE:
|
142
|
+
Esempio di sincronizzazione di un file sqlite3 e una cartella
|
143
|
+
|
144
|
+
```json
|
145
|
+
{
|
146
|
+
"stack_name": "test1",
|
147
|
+
"sync_configs": [
|
148
|
+
{
|
149
|
+
"service": "second",
|
150
|
+
"how": "rsync",
|
151
|
+
"configs": {
|
152
|
+
"remote": "/test_bind",
|
153
|
+
"local": "./uploads"
|
154
|
+
}
|
155
|
+
},
|
156
|
+
{
|
157
|
+
"service": "test_sqlite3",
|
158
|
+
"how": "sqlite3",
|
159
|
+
"configs": {
|
160
|
+
"remote": "/cartella_sqlite3/esempio.sqlite3",
|
161
|
+
"local": "./development.sqlite3"
|
162
|
+
}
|
163
|
+
}
|
164
|
+
]
|
165
|
+
}
|
166
|
+
```
|
167
|
+
|
168
|
+
|
95
169
|
## Development
|
96
170
|
|
97
171
|
nel file di configurazione creato nella home aggiungere la chiave "dev_mode":1 per collegarsi localmente
|
98
172
|
|
99
173
|
### Abbiamo due tasks swarm di simulazione
|
100
174
|
```shell script
|
101
|
-
docker stack deploy -c test_folder/test_1/
|
175
|
+
docker stack deploy -c test_folder/test_1/docker-compose.yml test_1_stack
|
176
|
+
docker stack deploy -c test_folder/test_1/docker-compose.yml test1_staging
|
102
177
|
docker stack deploy -c test_folder/test_2/docker_compose.yml test2
|
103
178
|
```
|
104
179
|
|
105
|
-
|
180
|
+
Per simulare una sincronizzazione fra locale e remoto di un mysql, lanciamo lo stesso stack anche come compose, in modo
|
181
|
+
da trovarci sulla stessa macchina con tutte e due le situazioni
|
182
|
+
```shell script
|
183
|
+
docker-compose up -f test_folder/test_1/docker-compose-local.yml -d
|
184
|
+
```
|
185
|
+
|
186
|
+
|
187
|
+
|
188
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version
|
189
|
+
number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git
|
190
|
+
commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
106
191
|
|
107
192
|
|
108
193
|
## License
|
@@ -11,6 +11,9 @@ module SwarmClusterCliOpe
|
|
11
11
|
true
|
12
12
|
end
|
13
13
|
|
14
|
+
class_option :environment, required: false, type: :string, aliases: [:e],
|
15
|
+
desc: "Esegue tutte le operazioni nell'env scelto, il file di configurazione dovrà avere il nome: #{Configuration.cfgs_project_file_name}.ENV"
|
16
|
+
|
14
17
|
desc "install", "Creazione della configurazione base della gemma"
|
15
18
|
|
16
19
|
def install
|
@@ -40,7 +43,9 @@ module SwarmClusterCliOpe
|
|
40
43
|
desc "config", "Visualizza le configurazioni mergiate (HOME + Project configuration[#{Configuration.cfgs_project_file_name}])"
|
41
44
|
|
42
45
|
def config
|
43
|
-
|
46
|
+
cfgs.env(options[:environment]) do
|
47
|
+
puts JSON.pretty_generate(cfgs.merged_configurations)
|
48
|
+
end
|
44
49
|
end
|
45
50
|
|
46
51
|
|
@@ -54,88 +59,93 @@ module SwarmClusterCliOpe
|
|
54
59
|
end
|
55
60
|
|
56
61
|
desc "services", "lista dei servizi per uno stack"
|
57
|
-
option :stack_name, required: false, type: :string
|
62
|
+
option :stack_name, required: false, type: :string
|
58
63
|
|
59
64
|
def services
|
60
|
-
|
61
|
-
|
65
|
+
cfgs.env(options[:environment]) do |cfgs|
|
66
|
+
stack_name = options[:stack_name] || cfgs.stack_name
|
67
|
+
Models::Service.all(stack_name: stack_name).each do |s|
|
68
|
+
puts s.name
|
69
|
+
end
|
62
70
|
end
|
63
71
|
end
|
64
72
|
|
65
73
|
desc "mc SERVICE_NAME", "Apre MC tra la cartella attuale e il container (potrebbe dar luogo a degli errori, ma funziona)"
|
66
|
-
option :stack_name, required: false, type: :string
|
74
|
+
option :stack_name, required: false, type: :string
|
67
75
|
|
68
76
|
def mc(service_name)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
begin
|
78
|
-
container = Models::Container.find_by_service_name(service_name, stack_name: options[:stack_name])
|
79
|
-
|
80
|
-
server = container.node.hostname
|
81
|
-
|
82
|
-
# Creo container ssh
|
83
|
-
# DOCKER_HOST=ssh://swarm_node_1 docker run --rm -d -p 12222:22 \
|
84
|
-
# --volumes-from sistemi-test_swarm_cluster_cli_wordpress.1.zbbz1xxh4vzzccndvs973jnuc \
|
85
|
-
# sickp/alpine-sshd:7.5
|
86
|
-
#
|
87
|
-
cmd = container.docker_command
|
88
|
-
cmd.base_suffix_command = ''
|
89
|
-
shell_operation = cmd.command do |c|
|
90
|
-
c.add("run --rm -d -p 42222:22 --volumes-from #{container.id} sickp/alpine-sshd:7.5")
|
77
|
+
cfgs.env(options[:environment]) do |cfgs|
|
78
|
+
stack_name = options[:stack_name] || cfgs.stack_name
|
79
|
+
# Disabilito output della libreria
|
80
|
+
MakeMakefile::Logging.instance_variable_set(:@logfile, File::NULL)
|
81
|
+
unless find_executable 'mc'
|
82
|
+
puts "Non hai installato MC"
|
83
|
+
exit 0
|
91
84
|
end
|
92
85
|
|
93
|
-
|
94
|
-
|
95
|
-
puts "Container generato con id:#{id_container}"
|
96
|
-
|
97
|
-
# eseguo tunnel verso nodo e container ssh
|
98
|
-
socket_ssh_path = "/tmp/socket_ssh_#{id_container}"
|
99
|
-
# ssh -f -N -T -M -S <path-to-socket> -L 13333:0.0.0.0:42222 <server>
|
100
|
-
cmd_tunnel = ["ssh", "-f -N -T -M", "-S #{socket_ssh_path}", "-L 13333:0.0.0.0:42222", server].join(" ")
|
101
|
-
puts "Apro tunnel"
|
102
|
-
puts cmd_tunnel
|
103
|
-
system(cmd_tunnel)
|
104
|
-
|
105
|
-
# apro MC
|
106
|
-
# mc . sftp://root:root@0.0.0.0:13333
|
107
|
-
mc_cmd = "mc . sftp://root:root@0.0.0.0:13333"
|
108
|
-
puts "Apro MC"
|
109
|
-
puts mc_cmd
|
110
|
-
system(mc_cmd)
|
111
|
-
ensure
|
112
|
-
if socket_ssh_path
|
113
|
-
# chiudo tunnel
|
114
|
-
# ssh -S <path-to-socket> -O exit <server>
|
115
|
-
close_tunnel_cmd = "ssh -S #{socket_ssh_path} -O exit #{server}"
|
116
|
-
puts "Chiudo tunnel"
|
117
|
-
# say close_tunnel_cmd
|
118
|
-
ShellCommandExecution.new(close_tunnel_cmd).execute
|
119
|
-
end
|
86
|
+
begin
|
87
|
+
container = Models::Container.find_by_service_name(service_name, stack_name: stack_name)
|
120
88
|
|
121
|
-
|
122
|
-
|
123
|
-
#
|
124
|
-
|
125
|
-
|
89
|
+
server = container.node.hostname
|
90
|
+
|
91
|
+
# Creo container ssh
|
92
|
+
# DOCKER_HOST=ssh://swarm_node_1 docker run --rm -d -p 12222:22 \
|
93
|
+
# --volumes-from sistemi-test_swarm_cluster_cli_wordpress.1.zbbz1xxh4vzzccndvs973jnuc \
|
94
|
+
# sickp/alpine-sshd:7.5
|
95
|
+
#
|
126
96
|
cmd = container.docker_command
|
127
97
|
cmd.base_suffix_command = ''
|
128
|
-
|
129
|
-
c.add("
|
98
|
+
shell_operation = cmd.command do |c|
|
99
|
+
c.add("run --rm -d -p 42222:22 --volumes-from #{container.id} sickp/alpine-sshd:7.5")
|
100
|
+
end
|
101
|
+
|
102
|
+
puts "Creazione container #{shell_operation.string_command}"
|
103
|
+
id_container = shell_operation.execute.raw_result[:stdout]
|
104
|
+
puts "Container generato con id:#{id_container}"
|
105
|
+
|
106
|
+
# eseguo tunnel verso nodo e container ssh
|
107
|
+
socket_ssh_path = "/tmp/socket_ssh_#{id_container}"
|
108
|
+
# ssh -f -N -T -M -S <path-to-socket> -L 13333:0.0.0.0:42222 <server>
|
109
|
+
cmd_tunnel = ["ssh", "-f -N -T -M", "-S #{socket_ssh_path}", "-L 13333:0.0.0.0:42222", server].join(" ")
|
110
|
+
puts "Apro tunnel"
|
111
|
+
puts cmd_tunnel
|
112
|
+
system(cmd_tunnel)
|
113
|
+
|
114
|
+
# apro MC
|
115
|
+
# mc . sftp://root:root@0.0.0.0:13333
|
116
|
+
mc_cmd = "mc . sftp://root:root@0.0.0.0:13333"
|
117
|
+
puts "Apro MC"
|
118
|
+
puts mc_cmd
|
119
|
+
system(mc_cmd)
|
120
|
+
ensure
|
121
|
+
if socket_ssh_path
|
122
|
+
# chiudo tunnel
|
123
|
+
# ssh -S <path-to-socket> -O exit <server>
|
124
|
+
close_tunnel_cmd = "ssh -S #{socket_ssh_path} -O exit #{server}"
|
125
|
+
puts "Chiudo tunnel"
|
126
|
+
# say close_tunnel_cmd
|
127
|
+
ShellCommandExecution.new(close_tunnel_cmd).execute
|
130
128
|
end
|
131
|
-
stop_ssh_container.execute
|
132
|
-
end
|
133
129
|
|
130
|
+
if id_container
|
131
|
+
# cancello container
|
132
|
+
# docker stop #{id_container}
|
133
|
+
puts "Spengo container di appoggio"
|
134
|
+
puts "docker stop #{id_container}"
|
135
|
+
cmd = container.docker_command
|
136
|
+
cmd.base_suffix_command = ''
|
137
|
+
stop_ssh_container = cmd.command do |c|
|
138
|
+
c.add("stop #{id_container}")
|
139
|
+
end
|
140
|
+
stop_ssh_container.execute
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
134
144
|
end
|
135
145
|
end
|
136
146
|
|
137
147
|
desc "cp SRC DEST", "Copia la sorgente in destinazione"
|
138
|
-
option :stack_name, required: false, type: :string
|
148
|
+
option :stack_name, required: false, type: :string
|
139
149
|
long_desc <<-LONGDESC
|
140
150
|
SRC e DEST possono essere un servizio, solo uno di essi può essere un servizio (TODO)
|
141
151
|
Per identificare che sia un servizio controllo se nella stringa è presete il :
|
@@ -144,46 +154,73 @@ module SwarmClusterCliOpe
|
|
144
154
|
LONGDESC
|
145
155
|
|
146
156
|
def cp(src, dest)
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
157
|
+
cfgs.env(options[:environment]) do |cfgs|
|
158
|
+
|
159
|
+
cfgs.stack_name = options[:stack_name] || cfgs.stack_name
|
160
|
+
|
161
|
+
#identifico quale dei due è il servizio e quale la path
|
162
|
+
if src.match(/^(.*)\:/)
|
163
|
+
service_name = Regexp.last_match[1]
|
164
|
+
remote = src.match(/\:(.*)$/)[1]
|
165
|
+
local = dest
|
166
|
+
execute = :pull
|
167
|
+
else
|
168
|
+
service_name = dest.match(/^(.*)\:/)[1]
|
169
|
+
remote = dest.match(/\:(.*)$/)[1]
|
170
|
+
local = src
|
171
|
+
execute = :push
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
cmd = SyncConfigs::Copy.new(cfgs, {
|
176
|
+
service: service_name,
|
177
|
+
how: 'copy',
|
178
|
+
configs: {
|
179
|
+
local: local,
|
180
|
+
remote: remote
|
181
|
+
}
|
182
|
+
})
|
183
|
+
|
184
|
+
puts "COMPLETATO" if cmd.send(execute)
|
185
|
+
|
154
186
|
end
|
155
|
-
puts "COMPLETATO" if ris
|
156
187
|
end
|
157
188
|
|
158
189
|
|
159
190
|
desc "configure_project STACK_NAME", "Genera il file di configurazione del progetto contenente il nome dello stack"
|
160
191
|
|
161
192
|
def configure_project(stack_name)
|
162
|
-
cfgs.
|
163
|
-
|
193
|
+
cfgs.env(options[:environment]) do |c|
|
194
|
+
c.stack_name = stack_name
|
195
|
+
c.save_project_cfgs
|
196
|
+
end
|
164
197
|
end
|
165
198
|
|
199
|
+
|
166
200
|
desc "service_shell SERVICE_NAME", "apre una shell [default bash] dentro al container"
|
167
|
-
option :stack_name, required: false, type: :string
|
201
|
+
option :stack_name, required: false, type: :string
|
168
202
|
option :shell, required: false, type: :string, default: 'bash'
|
169
203
|
|
170
204
|
def service_shell(service_name)
|
171
|
-
|
205
|
+
cfgs.env(options[:environment]) do |cfgs|
|
206
|
+
stack_name = options[:stack_name] || cfgs.stack_name
|
207
|
+
container = Models::Container.find_by_service_name(service_name, stack_name: stack_name)
|
172
208
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
209
|
+
cmd = container.docker_command
|
210
|
+
cmd.base_suffix_command = ''
|
211
|
+
shell_operation = cmd.command do |c|
|
212
|
+
c.add("exec -it #{container.id} #{options[:shell]}")
|
213
|
+
end
|
178
214
|
|
179
|
-
|
180
|
-
|
181
|
-
|
215
|
+
say "Stai entrando della shell in #{options[:shell]} del container #{stack_name}->#{container.name}[#{container.id}]"
|
216
|
+
system(shell_operation.string_command)
|
217
|
+
say "Shell chiusa"
|
218
|
+
end
|
182
219
|
end
|
183
220
|
|
184
221
|
|
185
222
|
desc "rsync_binded_from", "esegue un rsync dalla cartella bindata (viene sincronizzato il contenuto)"
|
186
|
-
option :stack_name, required: false, type: :string
|
223
|
+
option :stack_name, required: false, type: :string
|
187
224
|
option :service_name, required: true, type: :string
|
188
225
|
option :binded_container_folders, required: true, type: :string, desc: "path della cartella bindata all'interno del container da sincronizzare"
|
189
226
|
option :local_folder, required: true, type: :string, desc: "path della cartella dove sincronizzare il comando"
|
@@ -195,7 +232,7 @@ module SwarmClusterCliOpe
|
|
195
232
|
end
|
196
233
|
|
197
234
|
desc "rsync_binded_to", "esegue un rsync verso la cartella bindata"
|
198
|
-
option :stack_name, required: false, type: :string
|
235
|
+
option :stack_name, required: false, type: :string
|
199
236
|
option :service_name, required: true, type: :string
|
200
237
|
option :binded_container_folders, required: true, type: :string, desc: "path della cartella bindata all'interno del container da sincronizzare"
|
201
238
|
option :local_folder, required: true, type: :string, desc: "path della cartella dove sincronizzare il comando"
|
@@ -206,46 +243,116 @@ module SwarmClusterCliOpe
|
|
206
243
|
end
|
207
244
|
end
|
208
245
|
|
246
|
+
desc "stacksync [DIRECTION:pull|push]", "Si occupa di scaricare|caricare,utilizzando le configurazioni presenti, i dati dallo stack remoto"
|
247
|
+
long_desc <<-LONGDESC.gsub("\n", "\x5")
|
248
|
+
le configurazioni sono contenute nell'array: sync_configs.
|
249
|
+
ogni configurazione è composta da:
|
250
|
+
{
|
251
|
+
service:""
|
252
|
+
how:""
|
253
|
+
configs:{ }
|
254
|
+
}
|
255
|
+
- service è il nome del servizio
|
256
|
+
- how è il come sincronizzare, definendo la tipologia:
|
257
|
+
---- pg -> DB TODO
|
258
|
+
---- mysql -> DB dump con mysql
|
259
|
+
---- sqlite3 -> DB: viene eseguita una copia del file
|
260
|
+
---- rsync -> RSYNC
|
261
|
+
- configs: è un hash con le configurazioni per ogni tipo di sincronizzazione
|
262
|
+
|
263
|
+
Possibili CFGS per tipologia:
|
264
|
+
rsync:
|
265
|
+
--local: -> path cartella locale
|
266
|
+
--remote: -> path cartella remota (contesto del container)
|
267
|
+
|
268
|
+
sqlite3:
|
269
|
+
--local: -> path al file
|
270
|
+
--remote: -> path al file remoto (contesto del container)
|
271
|
+
|
272
|
+
mysql:
|
273
|
+
-- local: -> hash di configurazioni per il DB locale
|
274
|
+
"service": "db" -> nome del servizio nel compose locale, DEFAULT: quello definito sopra
|
275
|
+
"mysql_password_env": "MYSQL_PASSWORD" -> variabile ambiente interna al servizio contenente PASSWORD, DEFAULT: MYSQL_PASSWORD
|
276
|
+
"mysql_user_env": "MYSQL_USER" -> variabile ambiente interna al servizio contenente USERNAME, DEFAULT: MYSQL_USER
|
277
|
+
"database_name_env": "MYSQL_DATABASE" -> variabile ambiente interna al servizio contenente NOME DB, DEFAULT: MYSQL_DATABASE
|
278
|
+
-- remote: -> hash di configurazioni per il DB remoto
|
279
|
+
"service": "db" -> nome del servizio nel compose locale, DEFAULT: quello definito sopra
|
280
|
+
"mysql_password_env": "MYSQL_PASSWORD" -> variabile ambiente interna al servizio contenente PASSWORD, DEFAULT: MYSQL_PASSWORD
|
281
|
+
"mysql_user_env": "MYSQL_USER" -> variabile ambiente interna al servizio contenente USERNAME, DEFAULT: MYSQL_USER
|
282
|
+
"database_name_env": "MYSQL_DATABASE" -> variabile ambiente interna al servizio contenente NOME DB, DEFAULT: MYSQL_DATABASE
|
283
|
+
|
284
|
+
|
285
|
+
EXAMPLE:
|
286
|
+
Esempio di sincronizzazione di un file sqlite3 e una cartella
|
287
|
+
{
|
288
|
+
"stack_name": "test1",
|
289
|
+
"sync_configs": [
|
290
|
+
{
|
291
|
+
"service": "second",
|
292
|
+
"how": "rsync",
|
293
|
+
"configs": {
|
294
|
+
"remote": "/test_bind",
|
295
|
+
"local": "./uploads"
|
296
|
+
}
|
297
|
+
},
|
298
|
+
{
|
299
|
+
"service": "test_sqlite3",
|
300
|
+
"how": "sqlite3",
|
301
|
+
"configs": {
|
302
|
+
"remote": "/cartella_sqlite3/esempio.sqlite3",
|
303
|
+
"local": "./development.sqlite3"
|
304
|
+
}
|
305
|
+
}
|
306
|
+
]
|
307
|
+
}
|
308
|
+
LONGDESC
|
209
309
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
310
|
+
def stacksync(direction)
|
311
|
+
direction = case direction
|
312
|
+
when 'push'
|
313
|
+
:push
|
314
|
+
when 'pull'
|
315
|
+
:pull
|
316
|
+
else
|
317
|
+
raise "ONLY [push|pull] action accepted"
|
318
|
+
end
|
319
|
+
cfgs.env(options[:environment]) do |cfgs|
|
320
|
+
sync_cfgs = cfgs.sync_configurations
|
321
|
+
if sync_cfgs.empty?
|
322
|
+
say "Attenzione, configurazioni di sincronizzazione vuoto. Leggere la documentazione"
|
323
|
+
else
|
324
|
+
sync_cfgs.each do |sync|
|
325
|
+
say "----------->>>>>>"
|
326
|
+
say "[ #{sync.class.name} ]"
|
327
|
+
sync.send(direction)
|
328
|
+
say "<<<<<<-----------"
|
329
|
+
end
|
330
|
+
end
|
220
331
|
end
|
332
|
+
end
|
221
333
|
|
334
|
+
private
|
222
335
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
end
|
336
|
+
def rsync_binded(direction: :down, options: {})
|
337
|
+
cfgs.env(options[:environment]) do |cfgs|
|
338
|
+
cfgs.stack_name = options[:stack_name] || cfgs.stack_name
|
339
|
+
sync = SyncConfigs::Rsync.new(cfgs, {
|
340
|
+
service: options[:service_name],
|
341
|
+
how: 'rsync',
|
342
|
+
configs: {
|
343
|
+
local: options[:local_folder],
|
344
|
+
remote: options[:binded_container_folders]
|
345
|
+
}
|
346
|
+
})
|
347
|
+
|
348
|
+
if direction == :down
|
349
|
+
sync.pull
|
350
|
+
end
|
351
|
+
if direction == :up
|
352
|
+
sync.push
|
353
|
+
end
|
242
354
|
|
243
|
-
cmd = ShellCommandExecution.new(cmd)
|
244
355
|
|
245
|
-
say "Comando da eseguire:"
|
246
|
-
say " #{cmd.string_command}"
|
247
|
-
if yes?("Confermare il comando?[y,yes]")
|
248
|
-
cmd.execute
|
249
356
|
end
|
250
357
|
end
|
251
358
|
end
|
@@ -9,6 +9,13 @@ module SwarmClusterCliOpe
|
|
9
9
|
end.execute
|
10
10
|
end
|
11
11
|
|
12
|
+
def exec(container_id,cmd_str)
|
13
|
+
self.base_suffix_command = []
|
14
|
+
command do |cmd|
|
15
|
+
cmd.add("exec #{container_id} #{cmd_str}")
|
16
|
+
end.execute
|
17
|
+
end
|
18
|
+
|
12
19
|
##
|
13
20
|
# Esegue il ps sui container, possibile filtrare passando nome stack e/o nome servizio
|
14
21
|
# @param [String] service_name
|
@@ -15,6 +15,9 @@ module SwarmClusterCliOpe
|
|
15
15
|
#@return [String] nome dello stack con cui lavoriamo
|
16
16
|
attr_accessor :stack_name
|
17
17
|
|
18
|
+
#@return [String] in che enviroment siamo, altrimenti siamo nel default
|
19
|
+
attr_accessor :environment
|
20
|
+
|
18
21
|
NoBaseConfigurations = Class.new(Error)
|
19
22
|
|
20
23
|
##
|
@@ -25,6 +28,19 @@ module SwarmClusterCliOpe
|
|
25
28
|
@_managers = self.nodes.select { |n| read_managers_cache_list.include?(n.name) }.collect { |c| Manager.new(name: c.name.to_s, connection_uri: c.connection_uri) }
|
26
29
|
end
|
27
30
|
|
31
|
+
##
|
32
|
+
# Serve per entrare nell'env corretto.
|
33
|
+
# passando l'env, tutto quello eseguito nello yield sarà gestito in quell'env.
|
34
|
+
# Verrà controllato quindi che esista il relativo file di configurazion
|
35
|
+
def env(enviroment = nil)
|
36
|
+
unless enviroment.nil?
|
37
|
+
@environment = enviroment.to_s.to_sym
|
38
|
+
end
|
39
|
+
logger.info { "ENV: #{@environment ? @environment : "BASE"}" }
|
40
|
+
yield self
|
41
|
+
@environment = nil
|
42
|
+
end
|
43
|
+
|
28
44
|
##
|
29
45
|
# Esegue un refresh della lista dei manager, ciclando su tutti i nodi, e scrivendo in /tmp un file temporaneo con
|
30
46
|
# con la lista dei nomi dei managers
|
@@ -48,8 +64,10 @@ module SwarmClusterCliOpe
|
|
48
64
|
#
|
49
65
|
# @return [Array<SwarmClusterCliOpe::Node>]
|
50
66
|
def nodes
|
51
|
-
|
52
|
-
|
67
|
+
@_nodes ||= Hash.new do |hash, key|
|
68
|
+
hash[key] = self.merged_configurations[:connections_maps].collect { |m, c| Node.new(name: m.to_s, connection_uri: c) }
|
69
|
+
end
|
70
|
+
@_nodes[environment]
|
53
71
|
end
|
54
72
|
|
55
73
|
##
|
@@ -58,22 +76,31 @@ module SwarmClusterCliOpe
|
|
58
76
|
# @param [Array<SwarmClusterCliOpe::Node>]
|
59
77
|
# @return [Configuration]
|
60
78
|
def nodes=(objs)
|
61
|
-
|
79
|
+
nodes[environment] = objs
|
62
80
|
self
|
63
81
|
end
|
64
82
|
|
65
83
|
# @return [String,NilClass] nome dello stack del progetto se configurato
|
66
84
|
def stack_name
|
67
|
-
return @stack_name if @stack_name
|
68
85
|
return nil unless self.class.exist_base?
|
69
|
-
@stack_name
|
86
|
+
@stack_name ||= Hash.new do |hash, key|
|
87
|
+
hash[key] = merged_configurations[:stack_name] if merged_configurations.key?(:stack_name)
|
88
|
+
end
|
89
|
+
@stack_name[environment]
|
90
|
+
end
|
91
|
+
|
92
|
+
##
|
93
|
+
# Imposta il nome dello stack
|
94
|
+
def stack_name=(objs)
|
95
|
+
stack_name #lo richiamo per fargli generare la variabile di classe
|
96
|
+
@stack_name[environment] = objs
|
70
97
|
end
|
71
98
|
|
72
99
|
##
|
73
100
|
# Livello di logging
|
74
101
|
# @return [Integer]
|
75
102
|
def logger_level
|
76
|
-
|
103
|
+
merged_configurations[:log_level].to_s || "0"
|
77
104
|
rescue SwarmClusterCliOpe::Configuration::NoBaseConfigurations
|
78
105
|
# quando andiamo in errore durante l'installazione per avere le informazioni per il logger.
|
79
106
|
# Usiamo lo standard
|
@@ -85,7 +112,7 @@ module SwarmClusterCliOpe
|
|
85
112
|
# @return [TrueClass, FalseClass]
|
86
113
|
def development_mode?
|
87
114
|
return false unless self.class.exist_base?
|
88
|
-
|
115
|
+
merged_configurations.key?(:dev_mode)
|
89
116
|
end
|
90
117
|
|
91
118
|
##
|
@@ -110,8 +137,8 @@ module SwarmClusterCliOpe
|
|
110
137
|
##
|
111
138
|
# Si occupa del salvataggio delle configurazioni di progetto, se abbiamo lo stack_name
|
112
139
|
def save_project_cfgs
|
113
|
-
if
|
114
|
-
File.open(File.join(FileUtils.pwd, self.class.cfgs_project_file_name), "wb") do |f|
|
140
|
+
if stack_name
|
141
|
+
File.open(File.join(FileUtils.pwd, self.class.cfgs_project_file_name(with_env: @environment)), "wb") do |f|
|
115
142
|
f.write({
|
116
143
|
stack_name: stack_name
|
117
144
|
}.to_json)
|
@@ -136,13 +163,46 @@ module SwarmClusterCliOpe
|
|
136
163
|
nodes.find { |c| c.id == node_id }
|
137
164
|
end
|
138
165
|
|
166
|
+
##
|
167
|
+
# Indica il nome del progetto locale compose, quella parte di nome che viene attaccata in fronte
|
168
|
+
# ad ogni nome di servizio locale, e che come default è il nome della cartella in cui risiede
|
169
|
+
# il docker-compose.yml file
|
170
|
+
# @return [String]
|
171
|
+
def local_compose_project_name
|
172
|
+
File.basename(FileUtils.pwd)
|
173
|
+
end
|
174
|
+
|
175
|
+
##
|
176
|
+
# Elenco di tutte le configurazioni di sincronizzazione
|
177
|
+
# @return [Array]
|
178
|
+
def sync_configurations
|
179
|
+
cfgs = merged_configurations[:sync_configs]
|
180
|
+
return [] if cfgs.nil? or !cfgs.is_a?(Array)
|
181
|
+
cfgs.collect do |c|
|
182
|
+
|
183
|
+
case c[:how]
|
184
|
+
when 'sqlite3'
|
185
|
+
SyncConfigs::Sqlite3.new(self, c)
|
186
|
+
when 'rsync'
|
187
|
+
SyncConfigs::Rsync.new(self, c)
|
188
|
+
when 'mysql'
|
189
|
+
SyncConfigs::Mysql.new(self, c)
|
190
|
+
else
|
191
|
+
logger.error { "CONFIGURAIONE NON PREVISTA: #{c[:how]}" }
|
192
|
+
nil
|
193
|
+
end
|
194
|
+
|
195
|
+
end.compact
|
196
|
+
end
|
197
|
+
|
139
198
|
private
|
140
199
|
|
141
200
|
##
|
142
201
|
# nome del file in cui salvare le configurazioni di progetto
|
143
202
|
# @return [String]
|
144
|
-
|
145
|
-
|
203
|
+
# @param [nil|String] with_env nome dell'env da cercare
|
204
|
+
def self.cfgs_project_file_name(with_env: nil)
|
205
|
+
".swarm_cluster_project#{with_env ? ".#{with_env}" : ""}"
|
146
206
|
end
|
147
207
|
|
148
208
|
##
|
@@ -150,7 +210,7 @@ module SwarmClusterCliOpe
|
|
150
210
|
# quindi ogni ora si autoripulisce e con un md5 delle configurazioni di base
|
151
211
|
# @return [String]
|
152
212
|
def swarm_manager_cache_path
|
153
|
-
md5 = Digest::MD5.hexdigest(self.
|
213
|
+
md5 = Digest::MD5.hexdigest(self.merged_configurations.to_json)
|
154
214
|
file_name = Time.now.strftime(".swarm_cluster_cli_manager_cache-%Y%m%d%H-#{md5}")
|
155
215
|
File.join("/tmp", file_name)
|
156
216
|
end
|
@@ -164,29 +224,50 @@ module SwarmClusterCliOpe
|
|
164
224
|
JSON.parse(File.read(self.base_cfg_path)).deep_symbolize_keys
|
165
225
|
end
|
166
226
|
|
227
|
+
public
|
228
|
+
|
167
229
|
## Cerca le configurazioni di progetto e le mergia se sono presenti
|
168
230
|
# @return [Hash]
|
169
|
-
def
|
170
|
-
return @_merged_configurations if @_merged_configurations
|
231
|
+
def merged_configurations
|
232
|
+
return @_merged_configurations[@environment] if @_merged_configurations
|
233
|
+
|
234
|
+
@_merged_configurations = Hash.new do |hash, key|
|
235
|
+
folder = FileUtils.pwd
|
236
|
+
default_file = looped_file(folder, self.class.cfgs_project_file_name)
|
237
|
+
enviroment_file = looped_file(folder, self.class.cfgs_project_file_name(with_env: key))
|
238
|
+
|
239
|
+
project_cfgs = {}
|
240
|
+
unless default_file.nil?
|
241
|
+
project_cfgs = JSON.parse(File.read(default_file)).deep_symbolize_keys
|
242
|
+
end
|
243
|
+
|
244
|
+
unless enviroment_file.nil?
|
245
|
+
project_cfgs.merge!(JSON.parse(File.read(enviroment_file)).deep_symbolize_keys)
|
246
|
+
end
|
247
|
+
|
248
|
+
hash[key] = self.class.read_base.merge(project_cfgs)
|
249
|
+
end
|
250
|
+
|
251
|
+
@_merged_configurations[@environment]
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
private
|
256
|
+
|
257
|
+
def looped_file(start_folder, file)
|
171
258
|
project_file = nil
|
172
|
-
folder = FileUtils.pwd
|
173
259
|
loop do
|
174
260
|
|
175
|
-
if File.exist?(File.join(
|
176
|
-
project_file = File.join(
|
261
|
+
if File.exist?(File.join(start_folder, file))
|
262
|
+
project_file = File.join(start_folder, file)
|
177
263
|
end
|
178
264
|
|
179
265
|
break unless project_file.nil?
|
180
|
-
break if
|
181
|
-
|
182
|
-
end
|
183
|
-
|
184
|
-
project_cfgs = {}
|
185
|
-
unless project_file.nil?
|
186
|
-
project_cfgs = JSON.parse(File.read(project_file)).deep_symbolize_keys
|
266
|
+
break if start_folder == '/'
|
267
|
+
start_folder = File.expand_path("..", start_folder)
|
187
268
|
end
|
188
269
|
|
189
|
-
|
270
|
+
project_file
|
190
271
|
end
|
191
272
|
|
192
273
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module SwarmClusterCliOpe
|
2
|
+
module Models
|
3
|
+
class ComposeContainer < Container
|
4
|
+
|
5
|
+
# @return [SwarmClusterCliOpe::Models::ComposeContainer]
|
6
|
+
def self.find_by_service_name(service_name, stack_name: '')
|
7
|
+
res = ShellCommandExecution.new("docker inspect #{[stack_name, service_name, "1"].compact.join("_".strip)}").execute
|
8
|
+
self.new(JSON.parse(res.raw_result[:stdout]).first)
|
9
|
+
end
|
10
|
+
|
11
|
+
def mapped_uri_connection
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -4,7 +4,7 @@ module SwarmClusterCliOpe
|
|
4
4
|
|
5
5
|
#@return [String]
|
6
6
|
attr_accessor :name
|
7
|
-
#@return [String]
|
7
|
+
#@return [String] id del container
|
8
8
|
attr_accessor :id
|
9
9
|
#@return [String] nome dell'immagine
|
10
10
|
attr_accessor :image
|
@@ -51,6 +51,12 @@ module SwarmClusterCliOpe
|
|
51
51
|
docker_command.cp("#{id}:#{src}", dest).success?
|
52
52
|
end
|
53
53
|
|
54
|
+
##
|
55
|
+
# Esegue il comando passato
|
56
|
+
def exec(cmd)
|
57
|
+
docker_command.exec(id, cmd)
|
58
|
+
end
|
59
|
+
|
54
60
|
##
|
55
61
|
# Ritorna il connection_uri del nodo che ospita il container
|
56
62
|
# @return [String]
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module SwarmClusterCliOpe
|
2
|
+
module SyncConfigs
|
3
|
+
class Base < Thor::Shell::Basic
|
4
|
+
include LoggerConcern
|
5
|
+
#@return [String] nome del servizio dello stack
|
6
|
+
attr_accessor :service
|
7
|
+
|
8
|
+
#@return [Hash] configurazioni di sincro
|
9
|
+
attr_accessor :configs
|
10
|
+
|
11
|
+
# @param [Hash] configs
|
12
|
+
# @param [Continuation] stack_cfgs
|
13
|
+
def initialize(stack_cfgs, configs)
|
14
|
+
super()
|
15
|
+
@configs = configs
|
16
|
+
|
17
|
+
@service = configs[:service]
|
18
|
+
@stack_cfgs = stack_cfgs
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
delegate :stack_name, to: :@stack_cfgs
|
23
|
+
|
24
|
+
##
|
25
|
+
# Funzione che dobbiamo sovrascrivere per identificare cosa fare quando scarichiamo i dati
|
26
|
+
def pull
|
27
|
+
raise "TO OVERRIDE"
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# Funzione che dobbiamo sovrascrivere per identificare cosa fare quando carichiamo i dati
|
32
|
+
def push
|
33
|
+
raise "TO OVERRIDE"
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
# @return [SwarmClusterCliOpe::Models::Container]
|
38
|
+
def container
|
39
|
+
Models::Container.find_by_service_name(service, stack_name: stack_name)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module SwarmClusterCliOpe
|
2
|
+
module SyncConfigs
|
3
|
+
class Copy < Base
|
4
|
+
|
5
|
+
# @return [String]
|
6
|
+
def local_folder
|
7
|
+
@configs[:configs][:local]
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [String]
|
11
|
+
def remote_folder
|
12
|
+
@configs[:configs][:remote]
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [TrueClass, FalseClass]
|
16
|
+
def push
|
17
|
+
say "#{local_folder} -->> #{remote_folder}" if container.copy_in(local_folder,remote_folder)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [TrueClass, FalseClass]
|
21
|
+
def pull
|
22
|
+
say "#{remote_folder} -->> #{local_folder}" if container.copy_out(remote_folder,local_folder)
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module SwarmClusterCliOpe
|
2
|
+
module SyncConfigs
|
3
|
+
##
|
4
|
+
# Classe per la gestione dell'ambiente differente fra local e remote
|
5
|
+
# sono presenti le variabili di classe per definire una minima DSL per poter definire le variabili
|
6
|
+
# disponibili e i default da utilizzare
|
7
|
+
class EnvConfigs
|
8
|
+
# @param [Hash] configs
|
9
|
+
# @param [SwarmClusterCliOpe::SyncConfigs::Base] sync_configs
|
10
|
+
# @param [Lambda] lambda che ritorna il container Istanza container su cui la
|
11
|
+
def initialize(sync_configs, configs, container)
|
12
|
+
@configs = configs
|
13
|
+
@sync_configs = sync_configs
|
14
|
+
@lambda_container = container
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Metodo che richiama la lambda della generazione del container al momento che ne
|
19
|
+
# è proprio necessario
|
20
|
+
def container
|
21
|
+
@container ||= @lambda_container.call
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String]
|
25
|
+
def service_name
|
26
|
+
@configs[:service] || @sync_configs.service
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
##
|
31
|
+
# Costruisce i metodi che restituiscono i valori delle configurazioni
|
32
|
+
#
|
33
|
+
# @param [String,Symbol] name -> nome della stringa con cui viene generato il metodo
|
34
|
+
# @param [String,Symbol] default_env -> nome env default nel caso non sia passato
|
35
|
+
# @param [String,Symbol] configuration_name -> nome della configurazione da utilizzare per estrapolare la configurazione
|
36
|
+
# in automatico viene tenuto conto se cercare per la versione
|
37
|
+
# con _env o senza....precedenza SENZA
|
38
|
+
def self.define_cfgs(name, default_env:, configuration_name:)
|
39
|
+
configuration_name ||= name
|
40
|
+
|
41
|
+
define_method(name) do
|
42
|
+
return self.instance_variable_get("@#{name}") if self.instance_variable_defined?("@#{name}")
|
43
|
+
|
44
|
+
#valore restituito direttamente dalla configurazione
|
45
|
+
if @configs.key?(configuration_name)
|
46
|
+
value = @configs["#{configuration_name}".to_sym]
|
47
|
+
else
|
48
|
+
env_var = @configs["#{configuration_name}_env".to_sym] || default_env
|
49
|
+
value = find_env_file_variable(env_var)
|
50
|
+
end
|
51
|
+
self.instance_variable_set("@#{name}", value)
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
##
|
60
|
+
# Estrae l'env dal container e ne tiene in memoria una copia, in modo da non fare multiple chiamate
|
61
|
+
def env
|
62
|
+
@env ||= container.exec("env").raw_result[:stdout].split("\n").collect { |v| v.split('=') }.to_h
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_env_file_variable(env_var)
|
66
|
+
if env_var.match?(/_FILE$/)
|
67
|
+
# dobbiamo controllare la presenza del file e salvarci il contenuto
|
68
|
+
nome_file = env[env_var.to_s]
|
69
|
+
container.exec("cat #{nome_file}").raw_result[:stdout]
|
70
|
+
else
|
71
|
+
# env normale, dobbiamo ricavarlo dal container
|
72
|
+
env[env_var.to_s]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module SwarmClusterCliOpe
|
2
|
+
module SyncConfigs
|
3
|
+
class Mysql < Base
|
4
|
+
|
5
|
+
# @return [TrueClass, FalseClass]
|
6
|
+
def pull
|
7
|
+
resume('pull')
|
8
|
+
if yes?("Confermare il comando?[y,yes]")
|
9
|
+
tmp_file = "/tmp/#{Time.now.to_i}.sql.gz"
|
10
|
+
container.exec("bash -c 'mysqldump -u #{remote.mysql_user} --password=#{remote.mysql_password} #{remote.database_name} | gzip -c -f' > #{tmp_file}")
|
11
|
+
local_container.copy_in(tmp_file, tmp_file)
|
12
|
+
local_container.exec("bash -c 'zcat #{tmp_file} | mysql -u #{local.mysql_user} --password=#{local.mysql_password} #{local.database_name}'")
|
13
|
+
end
|
14
|
+
true
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [TrueClass, FalseClass]
|
18
|
+
def push
|
19
|
+
resume('PUSH')
|
20
|
+
if yes?("ATTENZIONE !!!!!!PUSH!!!!! - Confermare il comando?[y,yes]")
|
21
|
+
tmp_file = "/tmp/#{Time.now.to_i}.sql.gz"
|
22
|
+
local_container.exec("bash -c 'mysqldump -u #{local.mysql_user} --password=#{local.mysql_password} #{local.database_name} | gzip -c -f' > #{tmp_file}")
|
23
|
+
container.copy_in(tmp_file, tmp_file)
|
24
|
+
container.exec("bash -c 'zcat #{tmp_file} | mysql -u #{remote.mysql_user} --password=#{remote.mysql_password} #{remote.database_name}'")
|
25
|
+
end
|
26
|
+
true
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [SwarmClusterCliOpe::SyncConfigs::Mysql::EnvConfigs]
|
30
|
+
def remote
|
31
|
+
EnvConfigs.new(self, @configs[:configs][:remote] || {}, -> { container })
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [SwarmClusterCliOpe::SyncConfigs::Mysql::EnvConfigs]
|
35
|
+
def local
|
36
|
+
EnvConfigs.new(self, @configs[:configs][:local] || {}, -> { local_container })
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
##
|
41
|
+
# Classe interna che rappresenta le configurazioni del DB
|
42
|
+
class EnvConfigs < SwarmClusterCliOpe::SyncConfigs::EnvConfigs
|
43
|
+
|
44
|
+
define_cfgs :database_name, default_env: "MYSQL_DATABASE", configuration_name: :database_name
|
45
|
+
define_cfgs :mysql_user, default_env: "MYSQL_USER", configuration_name: :mysql_user
|
46
|
+
define_cfgs :mysql_password, default_env: "MYSQL_PASSWORD", configuration_name: :mysql_password
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
##
|
52
|
+
# Funzione che ricapitola le informazioni utilizzate per eseguire l'operazione
|
53
|
+
def resume(direction)
|
54
|
+
puts "RESUME - #{direction}
|
55
|
+
service: #{service}
|
56
|
+
local:
|
57
|
+
service_name: #{local.service_name}
|
58
|
+
database_name: #{local.database_name}
|
59
|
+
mysql_user: #{local.mysql_user}
|
60
|
+
mysql_password: #{local.mysql_password}
|
61
|
+
remote:
|
62
|
+
service_name: #{remote.service_name}
|
63
|
+
database_name: #{remote.database_name}
|
64
|
+
mysql_user: #{remote.mysql_user}
|
65
|
+
mysql_password: #{remote.mysql_password}"
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def local_container
|
72
|
+
# il nome dello stack del compose usiamo come standard il nome della cartella, come lo fà già composer di default
|
73
|
+
Models::ComposeContainer.find_by_service_name(local.service_name, stack_name: @stack_cfgs.local_compose_project_name)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module SwarmClusterCliOpe
|
2
|
+
module SyncConfigs
|
3
|
+
class Rsync < Base
|
4
|
+
|
5
|
+
|
6
|
+
# @return [String]
|
7
|
+
def local_folder
|
8
|
+
@configs[:configs][:local]
|
9
|
+
end
|
10
|
+
|
11
|
+
# @return [String]
|
12
|
+
def remote_folder
|
13
|
+
@configs[:configs][:remote]
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
# @return [SwarmClusterCliOpe::ShellCommandResponse]
|
18
|
+
def push
|
19
|
+
execute(direction: :up)
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [SwarmClusterCliOpe::ShellCommandResponse]
|
23
|
+
def pull
|
24
|
+
execute(direction: :down)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
private
|
29
|
+
def execute(direction: :down)
|
30
|
+
|
31
|
+
if container.nil?
|
32
|
+
say "Container non trovato con #{stack_name}@##{service}"
|
33
|
+
exit 0
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
# trovo la cartella bindata e la relativa cartella sul nodo
|
38
|
+
volume = container.mapped_volumes.find { |v| v.destination == remote_folder and v.is_binded? }
|
39
|
+
if volume.nil?
|
40
|
+
say "Non ho trovato il volume bindato con questa destinazione all'interno del container #{remote_folder}"
|
41
|
+
exit 0
|
42
|
+
end
|
43
|
+
|
44
|
+
#costruisco il comando rsync fra cartella del nodo e cartella sul pc
|
45
|
+
cmd = ["rsync", "-zr", "--delete"]
|
46
|
+
if direction == :down
|
47
|
+
cmd << "#{volume.ssh_connection_path}/."
|
48
|
+
# creo la cartella in locale se non esiste
|
49
|
+
FileUtils.mkdir_p(local_folder)
|
50
|
+
cmd << local_folder
|
51
|
+
end
|
52
|
+
if direction == :up
|
53
|
+
cmd << "#{local_folder}/."
|
54
|
+
cmd << volume.ssh_connection_path
|
55
|
+
end
|
56
|
+
|
57
|
+
cmd = ShellCommandExecution.new(cmd)
|
58
|
+
|
59
|
+
say "Comando da eseguire:"
|
60
|
+
say " #{cmd.string_command}"
|
61
|
+
if yes?("Confermare il comando?[y,yes]")
|
62
|
+
cmd.execute
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: swarm_cluster_cli_ope
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marino Bonetti
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-09-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- lib/swarm_cluster_cli_ope.rb
|
91
91
|
- lib/swarm_cluster_cli_ope/cli.rb
|
92
92
|
- lib/swarm_cluster_cli_ope/commands/base.rb
|
93
|
+
- lib/swarm_cluster_cli_ope/commands/compose_container.rb
|
93
94
|
- lib/swarm_cluster_cli_ope/commands/container.rb
|
94
95
|
- lib/swarm_cluster_cli_ope/commands/service.rb
|
95
96
|
- lib/swarm_cluster_cli_ope/commands/swarm.rb
|
@@ -99,6 +100,7 @@ files:
|
|
99
100
|
- lib/swarm_cluster_cli_ope/logger_concern.rb
|
100
101
|
- lib/swarm_cluster_cli_ope/manager.rb
|
101
102
|
- lib/swarm_cluster_cli_ope/models/base.rb
|
103
|
+
- lib/swarm_cluster_cli_ope/models/compose_container.rb
|
102
104
|
- lib/swarm_cluster_cli_ope/models/container.rb
|
103
105
|
- lib/swarm_cluster_cli_ope/models/mapped_volume.rb
|
104
106
|
- lib/swarm_cluster_cli_ope/models/service.rb
|
@@ -107,6 +109,12 @@ files:
|
|
107
109
|
- lib/swarm_cluster_cli_ope/node.rb
|
108
110
|
- lib/swarm_cluster_cli_ope/shell_command_execution.rb
|
109
111
|
- lib/swarm_cluster_cli_ope/shell_command_response.rb
|
112
|
+
- lib/swarm_cluster_cli_ope/sync_configs/base.rb
|
113
|
+
- lib/swarm_cluster_cli_ope/sync_configs/copy.rb
|
114
|
+
- lib/swarm_cluster_cli_ope/sync_configs/env_configs.rb
|
115
|
+
- lib/swarm_cluster_cli_ope/sync_configs/mysql.rb
|
116
|
+
- lib/swarm_cluster_cli_ope/sync_configs/rsync.rb
|
117
|
+
- lib/swarm_cluster_cli_ope/sync_configs/sqlite3.rb
|
110
118
|
- lib/swarm_cluster_cli_ope/version.rb
|
111
119
|
- lib/swarm_cluster_cli_ope/worker.rb
|
112
120
|
- swarm_cluster_cli_ope.gemspec
|
@@ -133,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
133
141
|
- !ruby/object:Gem::Version
|
134
142
|
version: '0'
|
135
143
|
requirements: []
|
136
|
-
rubygems_version: 3.0.
|
144
|
+
rubygems_version: 3.0.8
|
137
145
|
signing_key:
|
138
146
|
specification_version: 4
|
139
147
|
summary: WIP Gemma per la gestione del cluster swarm
|