swarm_cluster_cli_ope 0.5.0.pre.2 → 0.5.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.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -45
  3. data/README.md +11 -2
  4. data/lib/swarm_cluster_cli_ope.rb +9 -1
  5. data/lib/swarm_cluster_cli_ope/base_configuration.rb +226 -0
  6. data/lib/swarm_cluster_cli_ope/cli.rb +2 -129
  7. data/lib/swarm_cluster_cli_ope/configuration.rb +10 -186
  8. data/lib/swarm_cluster_cli_ope/configuration_concern.rb +10 -9
  9. data/lib/swarm_cluster_cli_ope/k8s.rb +59 -83
  10. data/lib/swarm_cluster_cli_ope/kubernetes/configuration.rb +75 -0
  11. data/lib/swarm_cluster_cli_ope/kubernetes/pod.rb +144 -0
  12. data/lib/swarm_cluster_cli_ope/{k8s_rsync → kubernetes/rsync_cfgs}/password +0 -0
  13. data/lib/swarm_cluster_cli_ope/{k8s_rsync → kubernetes/rsync_cfgs}/rsyncd.conf +0 -0
  14. data/lib/swarm_cluster_cli_ope/{k8s_rsync → kubernetes/rsync_cfgs}/rsyncd.secrets +0 -0
  15. data/lib/swarm_cluster_cli_ope/kubernetes/sync_configs/base_decorator.rb +28 -0
  16. data/lib/swarm_cluster_cli_ope/kubernetes/sync_configs/mysql.rb +10 -0
  17. data/lib/swarm_cluster_cli_ope/kubernetes/sync_configs/post_gres.rb +11 -0
  18. data/lib/swarm_cluster_cli_ope/kubernetes/sync_configs/rsync.rb +125 -0
  19. data/lib/swarm_cluster_cli_ope/kubernetes/sync_configs/sqlite3.rb +9 -0
  20. data/lib/swarm_cluster_cli_ope/logger_concern.rb +1 -1
  21. data/lib/swarm_cluster_cli_ope/shell_command_response.rb +18 -5
  22. data/lib/swarm_cluster_cli_ope/stack_sync_concern.rb +135 -0
  23. data/lib/swarm_cluster_cli_ope/sync_configs/base.rb +1 -1
  24. data/lib/swarm_cluster_cli_ope/sync_configs/mysql.rb +17 -2
  25. data/lib/swarm_cluster_cli_ope/sync_configs/post_gres.rb +1 -1
  26. data/lib/swarm_cluster_cli_ope/thor_configuration_concern.rb +29 -0
  27. data/lib/swarm_cluster_cli_ope/version.rb +1 -1
  28. data/swarm_cluster_cli_ope.gemspec +0 -1
  29. metadata +17 -21
@@ -8,17 +8,8 @@ module SwarmClusterCliOpe
8
8
  # Classe per la gestione delle configurazioni, unisce le configurazioni di base alle configurazioni di progetto;
9
9
  # le quali sono salvate nel file di configurazione del progetto .swarm_cluster_project sottoforma di json
10
10
  # che vengono mergiate sulle configurazioni base
11
- class Configuration
12
- include Singleton
13
- include LoggerConcern
11
+ class Configuration < BaseConfiguration
14
12
 
15
- #@return [String] nome dello stack con cui lavoriamo
16
- attr_accessor :stack_name
17
-
18
- #@return [String] in che enviroment siamo, altrimenti siamo nel default
19
- attr_accessor :environment
20
-
21
- NoBaseConfigurations = Class.new(Error)
22
13
 
23
14
  ##
24
15
  # Lista di nodi su cui lavorare
@@ -28,19 +19,6 @@ module SwarmClusterCliOpe
28
19
  @_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) }
29
20
  end
30
21
 
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
-
44
22
  ##
45
23
  # Esegue un refresh della lista dei manager, ciclando su tutti i nodi, e scrivendo in /tmp un file temporaneo con
46
24
  # con la lista dei nomi dei managers
@@ -80,77 +58,14 @@ module SwarmClusterCliOpe
80
58
  self
81
59
  end
82
60
 
83
- # @return [String,NilClass] nome dello stack del progetto se configurato
84
- def stack_name
85
- return nil unless self.class.exist_base?
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
97
- end
98
-
99
- ##
100
- # Livello di logging
101
- # @return [Integer]
102
- def logger_level
103
- merged_configurations[:log_level].to_s || "0"
104
- rescue SwarmClusterCliOpe::Configuration::NoBaseConfigurations
105
- # quando andiamo in errore durante l'installazione per avere le informazioni per il logger.
106
- # Usiamo lo standard
107
- "0"
108
- end
109
-
110
- ##
111
- # Siamo in sviluppo?
112
- # @return [TrueClass, FalseClass]
113
- def development_mode?
114
- return false unless self.class.exist_base?
115
- merged_configurations.key?(:dev_mode)
116
- end
117
-
118
- ##
119
- # Controlla se esiste il file di configurazione base, nella home dell'utente
120
- def self.exist_base?
121
- File.exist?(base_cfg_path)
122
- end
123
-
124
-
125
61
  ##
126
62
  # Salva le configurazioni base in HOME
127
63
  def save_base_cfgs
128
- FileUtils.mkdir_p(File.dirname(self.class.base_cfg_path))
129
- File.open(self.class.base_cfg_path, "wb") do |f|
130
- f.write({
131
- version: SwarmClusterCliOpe::VERSION,
132
- connections_maps: nodes.collect { |k| [k.name, k.connection_uri] }.to_h
133
- }.to_json)
64
+ super do |obj|
65
+ obj.merge({connections_maps: nodes.collect { |k| [k.name, k.connection_uri] }.to_h})
134
66
  end
135
67
  end
136
68
 
137
- ##
138
- # Si occupa del salvataggio delle configurazioni di progetto, se abbiamo lo stack_name
139
- def save_project_cfgs
140
- if stack_name
141
- File.open(File.join(FileUtils.pwd, self.class.cfgs_project_file_name(with_env: @environment)), "wb") do |f|
142
- f.write({
143
- stack_name: stack_name,
144
- version: VERSION
145
- }.to_json)
146
- end
147
- end
148
- end
149
-
150
- # @return [String] path to base home configurations
151
- def self.base_cfg_path
152
- File.join(ENV['HOME'], '.swarm_cluster', 'config.json')
153
- end
154
69
 
155
70
  # @return [SwarmClusterCliOpe::Node]
156
71
  # @param [String] node nome del nodo
@@ -164,50 +79,20 @@ module SwarmClusterCliOpe
164
79
  nodes.find { |c| c.id == node_id }
165
80
  end
166
81
 
167
- ##
168
- # Indica il nome del progetto locale compose, quella parte di nome che viene attaccata in fronte
169
- # ad ogni nome di servizio locale, e che come default è il nome della cartella in cui risiede
170
- # il docker-compose.yml file
171
- # @return [String]
172
- def local_compose_project_name
173
- File.basename(FileUtils.pwd).downcase
174
- end
175
82
 
176
- ##
177
- # Elenco di tutte le configurazioni di sincronizzazione
178
- # @return [Array]
179
- def sync_configurations
180
- cfgs = merged_configurations[:sync_configs]
181
- return [] if cfgs.nil? or !cfgs.is_a?(Array)
182
- cfgs.collect do |c|
83
+ private
183
84
 
184
- case c[:how]
185
- when 'sqlite3'
186
- SyncConfigs::Sqlite3.new(self, c)
187
- when 'rsync'
188
- SyncConfigs::Rsync.new(self, c)
189
- when 'mysql'
190
- SyncConfigs::Mysql.new(self, c)
191
- when 'pg'
192
- SyncConfigs::PostGres.new(self, c)
193
- else
194
- logger.error { "CONFIGURAIONE NON PREVISTA: #{c[:how]}" }
195
- nil
196
- end
197
85
 
198
- end.compact
199
- end
86
+ def evaluate_correct_command_usage(configuration)
200
87
 
201
- private
88
+ if configuration[:connections_maps].keys.include?(:context)
89
+ puts "ATTENZIONE, I COMANDI DEVONO ESSERE LANCIATI DAL SUB COMANDO K8S"
90
+ exit
91
+ end
202
92
 
203
- ##
204
- # nome del file in cui salvare le configurazioni di progetto
205
- # @return [String]
206
- # @param [nil|String] with_env nome dell'env da cercare
207
- def self.cfgs_project_file_name(with_env: nil)
208
- ".swarm_cluster_project#{with_env ? ".#{with_env}" : ""}"
209
93
  end
210
94
 
95
+
211
96
  ##
212
97
  # Path al file dove salviamo la cache dei managers, ha un TTL legato all'orario (anno-mese-giorno-ora)
213
98
  # quindi ogni ora si autoripulisce e con un md5 delle configurazioni di base
@@ -218,67 +103,6 @@ module SwarmClusterCliOpe
218
103
  File.join("/tmp", file_name)
219
104
  end
220
105
 
221
- ##
222
- # Legge le configurazioni base
223
- #
224
- # @return [Hash]
225
- def self.read_base
226
- raise NoBaseConfigurations unless exist_base?
227
- JSON.parse(File.read(self.base_cfg_path)).deep_symbolize_keys
228
- end
229
-
230
- public
231
-
232
- ## Cerca le configurazioni di progetto e le mergia se sono presenti
233
- # @return [Hash]
234
- def merged_configurations
235
- return @_merged_configurations[@environment] if @_merged_configurations
236
-
237
- @_merged_configurations = Hash.new do |hash, key|
238
- folder = FileUtils.pwd
239
- default_file = looped_file(folder, self.class.cfgs_project_file_name)
240
- enviroment_file = looped_file(folder, self.class.cfgs_project_file_name(with_env: key))
241
-
242
- project_cfgs = {}
243
- unless default_file.nil?
244
- project_cfgs = JSON.parse(File.read(default_file)).deep_symbolize_keys
245
- end
246
-
247
- unless enviroment_file.nil?
248
- project_cfgs.merge!(JSON.parse(File.read(enviroment_file)).deep_symbolize_keys)
249
- end
250
-
251
- hash[key] = self.class.read_base.merge(project_cfgs)
252
- end
253
-
254
- configuration_version = @_merged_configurations[@environment][:version]
255
- if Gem::Version.new(configuration_version) > Gem::Version.new(VERSION)
256
- puts "WARNING: Versione del file di configurazione [#{configuration_version}] più aggiornata della gemma [#{VERSION}], eseguire upgrade
257
- gem update swarm_cluster_cli_ope"
258
- exit
259
- end
260
-
261
- @_merged_configurations[@environment]
262
-
263
- end
264
-
265
- private
266
-
267
- def looped_file(start_folder, file)
268
- project_file = nil
269
- loop do
270
-
271
- if File.exist?(File.join(start_folder, file))
272
- project_file = File.join(start_folder, file)
273
- end
274
-
275
- break unless project_file.nil?
276
- break if start_folder == '/'
277
- start_folder = File.expand_path("..", start_folder)
278
- end
279
-
280
- project_file
281
- end
282
106
 
283
107
  end
284
108
  end
@@ -1,8 +1,16 @@
1
+ require 'active_support/concern'
2
+
1
3
  module SwarmClusterCliOpe
2
4
  module ConfigurationConcern
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+
9
+ # @return [SwarmClusterCliOpe::Configuration]
10
+ def cfgs
11
+ SwarmClusterCliOpe.current_configuration ||= self.class.cfgs
12
+ end
3
13
 
4
- def self.included(klass)
5
- klass.extend(ClassMethods)
6
14
  end
7
15
 
8
16
  module ClassMethods
@@ -13,12 +21,5 @@ module SwarmClusterCliOpe
13
21
  Configuration.instance
14
22
  end
15
23
  end
16
-
17
-
18
- # @return [SwarmClusterCliOpe::Configuration]
19
- def cfgs
20
- self.class.cfgs
21
- end
22
-
23
24
  end
24
25
  end
@@ -1,110 +1,86 @@
1
- require 'kubeclient'
2
1
  module SwarmClusterCliOpe
3
2
  class K8s < Thor
4
3
  include LoggerConcern
5
4
  include ConfigurationConcern
5
+ include ThorConfigurationConcern
6
6
  include Thor::Actions
7
+ include StackSyncConcern
7
8
 
8
9
  def self.exit_on_failure?
9
10
  true
10
11
  end
11
12
 
13
+ def self.cfgs
14
+ SwarmClusterCliOpe::Kubernetes::Configuration.instance
15
+ end
12
16
 
13
- desc "rsync <src> <dst>", "esegue un rsync dalla cartella (viene sincronizzato il contenuto)"
14
-
15
-
16
- def rsync(src, dst)
17
- if yes? "Attenzione, i dati locali o remoti verranno sovrascritti/cancellati?[y,yes]"
18
-
19
- reg_exp = /(?<pod_name>.*)\:(?<path>.*)/
20
- if File.exist?(src)
21
- # il src é la cartella, quindi la destizione è il pod
22
- direction = :upload
23
- local_path = src
24
- podname = dst.match(reg_exp)[:pod_name]
25
- podpath = dst.match(reg_exp)[:path]
17
+ desc "install", "Creazione della configurazione base della gemma"
18
+
19
+ def install
20
+ #contolliamo se presente la configurazione base nella home
21
+ if Configuration.exist_base?
22
+ say "Configurazione già presente"
23
+ else
24
+ #se non presente allora chiediamo le varie configurazioni
25
+ if yes? "Sei nel contesto corretto di kubectl?"
26
+ #scriviamo le varie configurazioni
27
+ cfg = cfgs
28
+ cfg.save_base_cfgs
26
29
  else
27
- direction = :download
28
- podname = src.match(reg_exp)[:pod_name]
29
- podpath = src.match(reg_exp)[:path]
30
- local_path = dst
30
+ say "Cambia prima contesto, sarà quello usato per l'installazione"
31
31
  end
32
+ end
32
33
 
33
- puts "#{src} #{direction} #{dst}"
34
-
35
- cfgs.env(options[:environment]) do |cfgs|
36
- config = Kubeclient::Config.read(ENV['KUBECONFIG'] || "#{Dir.home}/.kube/config")
37
-
38
- context = config.context # attuale contesto
39
-
40
- puts "Stiamo utilizzando il contesto: #{context.api_endpoint}"
41
-
42
- base_cmd = ["kubectl", "-n #{cfgs.stack_name}"]
43
-
44
- cmd = ShellCommandExecution.new([*base_cmd, "exec #{podname}", "--", 'bash -c "apt update && apt install -yq rsync psmisc"'])
45
- if cmd.execute.failed?
46
- puts "Problemi nell'installazione di rsync nel pod"
47
- else
48
- cmd = ShellCommandExecution.new([*base_cmd, "cp", File.expand_path("../k8s_rsync/rsyncd.conf", __FILE__), "#{podname}:/tmp/."])
49
- copy_1 = cmd.execute.failed?
50
- cmd = ShellCommandExecution.new([*base_cmd, "cp", File.expand_path("../k8s_rsync/rsyncd.secrets", __FILE__), "#{podname}:/tmp/."])
51
- copy_2 = cmd.execute.failed?
52
- cmd = ShellCommandExecution.new([*base_cmd, "exec #{podname}", "--", 'bash -c "chmod 600 /tmp/rsyncd.secrets && chown root /tmp/*"'])
53
- chmod = cmd.execute.failed?
54
- if copy_1 or copy_2 or chmod
55
- puts "problema nella copia dei file di configurazione nel pod"
56
- else
57
-
58
-
59
- cmd = ShellCommandExecution.new([*base_cmd, "exec -i #{podname}", "--", 'bash -c "rsync --daemon --config=/tmp/rsyncd.conf --verbose --log-file=/tmp/rsync.log"'])
60
- if cmd.execute.failed?
61
- puts "Rsync non startato"
62
- else
63
- local_port = rand(30000..40000)
64
-
65
- p = IO.popen([*base_cmd, "port-forward #{podname} #{local_port}:873"].join(" "))
66
- pid = p.pid
67
- puts "PID in execuzione port forward:#{pid}"
68
-
69
- sleep 1
70
-
71
- # lanciamo il comando quindi per far rsync
72
- rsync_command = [
73
- "rsync -az --no-o --no-g",
74
- "--delete",
75
- "--password-file=#{ File.expand_path("../k8s_rsync/password", __FILE__)}"
76
- ]
77
-
78
- if direction == :upload
79
- rsync_command << local_path
80
- rsync_command << "rsync://root@0.0.0.0:#{local_port}/archives#{podpath}"
81
- else
82
- rsync_command << "rsync://root@0.0.0.0:#{local_port}/archives#{podpath}"
83
- rsync_command << local_path
84
- end
85
-
34
+ end
86
35
 
87
- cmd = ShellCommandExecution.new(rsync_command)
88
- cmd.execute
89
36
 
90
- sleep 1
91
- Process.kill("INT", pid)
37
+ desc "rsync <src> <dst>", "esegue un rsync dalla cartella (viene sincronizzato il contenuto)"
38
+ long_desc "Viene utilizzato rsync standard. La root del pod diviene il context di rsync, quindi
39
+ possiamo fare rsync con qualsiasi path del filesystem del pod.
40
+ Il modo con cui scrivere la path sorgente e quello di destinazione è tale a quello di rsync, quindi:
41
+ - voglio copiare il contenuto della cartella /ciao con il contenuto onlin del pod nella cartella
42
+ /home/pippo, dovrò scrivere /ciao/. podname:/home/pippo "
43
+ option :stack_name, required: false, type: :string, aliases: ["--namespace", "-n"]
92
44
 
45
+ def rsync(src, dst)
46
+ reg_exp = /(?<pod_name>.*)\:(?<path>.*)/
47
+ if File.exist?(src)
48
+ # il src é la cartella, quindi la destizione è il pod
49
+ direction = :up
50
+ local_path = src
51
+ podname = dst.match(reg_exp)[:pod_name]
52
+ podpath = dst.match(reg_exp)[:path]
53
+ else
54
+ direction = :down
55
+ podname = src.match(reg_exp)[:pod_name]
56
+ podpath = src.match(reg_exp)[:path]
57
+ local_path = dst
58
+ end
93
59
 
94
- puts "Eseguo pulizia"
95
- cmd = ShellCommandExecution.new([*base_cmd, "exec -i #{podname}", "--", 'bash -c "killall rsync"'])
96
- cmd.execute
97
- cmd = ShellCommandExecution.new([*base_cmd, "exec -i #{podname}", "--", 'bash -c "rm -fr /tmp/rsyncd*"'])
98
- cmd.execute
60
+ puts "#{src} #{direction} #{dst}"
99
61
 
100
- end
62
+ cfgs.env(options[:environment]) do |cfgs|
101
63
 
102
- end
64
+ cfgs.stack_name = options[:stack_name] || cfgs.stack_name
103
65
 
104
- end
66
+ sync = Kubernetes::SyncConfigs::Rsync.new(cfgs, {
67
+ service: Kubernetes::Pod.find_by_name(podname),
68
+ how: 'rsync',
69
+ configs: {
70
+ local: local_path,
71
+ remote: podpath
72
+ }
73
+ })
105
74
 
75
+ if direction == :down
76
+ sync.pull
77
+ end
78
+ if direction == :up
79
+ sync.push
106
80
  end
107
81
 
82
+
83
+
108
84
 
109
85
  end
110
86
  end
@@ -0,0 +1,75 @@
1
+ module SwarmClusterCliOpe
2
+ module Kubernetes
3
+ class Configuration < BaseConfiguration
4
+
5
+ def shell
6
+ @_shell = Thor::Shell::Basic.new
7
+ end
8
+
9
+ delegate :yes?,to: :shell
10
+
11
+ ##
12
+ # In kubernetes abbiamo il context, il context può essere ricevuto o dalla configurazione oppure dal current_context
13
+ # di kubelet
14
+ # @return [String]
15
+ def context
16
+
17
+ context = merged_configurations.dig(:connections_maps,:context) || nil
18
+
19
+ if context.nil?
20
+ cmd = ShellCommandExecution.new(['kubectl config current-context'])
21
+ context = cmd.execute.raw_result[:stdout]
22
+ unless yes? "Attenzione, non era presente il contesto nelle configurazioni, usiamo quello attualmente in uso: #{context}, proseguiamo lo stesso?[y,yes]"
23
+ exit
24
+ end
25
+
26
+ end
27
+ context
28
+ end
29
+
30
+ ##
31
+ # Salva le configurazioni base in HOME
32
+ def save_base_cfgs
33
+ super do |obj|
34
+ obj.merge({connections_maps: {context: context}})
35
+ end
36
+ end
37
+
38
+ ##
39
+ # In k8s utilizziamo namespace come identificativo per avere le idee più chiare a cosi ci riferiamo
40
+ alias_method :namespace, :stack_name
41
+
42
+
43
+ ##
44
+ # Funzione per la restituzione della classe di sincro corretta
45
+ def get_syncro(name)
46
+ case name
47
+ when 'sqlite3'
48
+ SyncConfigs::Sqlite3
49
+ when 'rsync'
50
+ SyncConfigs::Rsync
51
+ when 'mysql'
52
+ SyncConfigs::Mysql
53
+ when 'pg'
54
+ SyncConfigs::PostGres
55
+ else
56
+ logger.error { "CONFIGURAIONE NON PREVISTA: #{name}" }
57
+ nil
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def evaluate_correct_command_usage(configuration)
64
+
65
+ unless configuration[:connections_maps].keys.include?(:context)
66
+ puts "ATTENZIONE, I COMANDI NON DEVONO ESSERE LANCIATI DAL SUB COMANDO K8S"
67
+ exit
68
+ end
69
+
70
+ end
71
+
72
+
73
+ end
74
+ end
75
+ end