swarm_cluster_cli_ope 0.4.2 → 0.5.0.pre.5
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/Gemfile.lock +4 -4
- data/README.md +7 -2
- data/lib/swarm_cluster_cli_ope/base_configuration.rb +211 -0
- data/lib/swarm_cluster_cli_ope/cli.rb +6 -129
- data/lib/swarm_cluster_cli_ope/configuration.rb +3 -182
- data/lib/swarm_cluster_cli_ope/configuration_concern.rb +10 -9
- data/lib/swarm_cluster_cli_ope/k8s.rb +90 -0
- data/lib/swarm_cluster_cli_ope/kubernetes/configuration.rb +64 -0
- data/lib/swarm_cluster_cli_ope/kubernetes/pod.rb +144 -0
- data/lib/swarm_cluster_cli_ope/kubernetes/rsync_cfgs/password +1 -0
- data/lib/swarm_cluster_cli_ope/kubernetes/rsync_cfgs/rsyncd.conf +14 -0
- data/lib/swarm_cluster_cli_ope/kubernetes/rsync_cfgs/rsyncd.secrets +1 -0
- data/lib/swarm_cluster_cli_ope/kubernetes/sync_configs/base_decorator.rb +28 -0
- data/lib/swarm_cluster_cli_ope/kubernetes/sync_configs/rsync.rb +127 -0
- data/lib/swarm_cluster_cli_ope/kubernetes/sync_configs/sqlite3.rb +9 -0
- data/lib/swarm_cluster_cli_ope/shell_command_execution.rb +1 -1
- data/lib/swarm_cluster_cli_ope/shell_command_response.rb +18 -5
- data/lib/swarm_cluster_cli_ope/stack_sync_concern.rb +128 -0
- data/lib/swarm_cluster_cli_ope/sync_configs/base.rb +1 -1
- data/lib/swarm_cluster_cli_ope/thor_configuration_concern.rb +29 -0
- data/lib/swarm_cluster_cli_ope/version.rb +1 -1
- metadata +16 -4
@@ -0,0 +1 @@
|
|
1
|
+
root
|
@@ -0,0 +1 @@
|
|
1
|
+
root:root
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
module SwarmClusterCliOpe
|
3
|
+
module Kubernetes
|
4
|
+
module SyncConfigs
|
5
|
+
module BaseDecorator
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
|
10
|
+
delegate :namespace, :context, to: :@stack_cfgs
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# @return [SwarmClusterCliOpe::Kubernetes::Pod]
|
15
|
+
def container
|
16
|
+
return @service if @service.is_a? SwarmClusterCliOpe::Kubernetes::Pod
|
17
|
+
@_container ||= Pod.find_by_selector(service, namespace: namespace, context: context)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
# module ClassMethods
|
23
|
+
|
24
|
+
# end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module SwarmClusterCliOpe
|
2
|
+
module Kubernetes
|
3
|
+
module SyncConfigs
|
4
|
+
class Rsync < SwarmClusterCliOpe::SyncConfigs::Base
|
5
|
+
|
6
|
+
include BaseDecorator
|
7
|
+
|
8
|
+
# @return [String]
|
9
|
+
def local_folder
|
10
|
+
@configs[:configs][:local]
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [String]
|
14
|
+
def remote_folder
|
15
|
+
@configs[:configs][:remote]
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
# @return [SwarmClusterCliOpe::ShellCommandResponse]
|
20
|
+
def push
|
21
|
+
execute(direction: :up)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [SwarmClusterCliOpe::ShellCommandResponse]
|
25
|
+
def pull
|
26
|
+
execute(direction: :down)
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def execute(direction: :down)
|
33
|
+
|
34
|
+
if container.nil?
|
35
|
+
say "Container non trovato"
|
36
|
+
exit
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
if yes? "Attenzione, i dati locali o remoti verranno sovrascritti/cancellati?[y,yes]"
|
41
|
+
|
42
|
+
podname = container.name
|
43
|
+
|
44
|
+
if namespace.nil?
|
45
|
+
say "Mancata configurazione del namespace tramite argomento o .swarm_cluster_project"
|
46
|
+
exit
|
47
|
+
end
|
48
|
+
|
49
|
+
cmd = container.exec(['bash -c "apt update && apt install -yq rsync psmisc"'])
|
50
|
+
if cmd.execute.failed?
|
51
|
+
puts "Problemi nell'installazione di rsync nel pod"
|
52
|
+
else
|
53
|
+
cmd = container.cp_in(File.expand_path("../../rsync_cfgs/rsyncd.conf", __FILE__), "/tmp/.")
|
54
|
+
copy_1 = cmd.execute.failed?
|
55
|
+
cmd = container.cp_in(File.expand_path("../../rsync_cfgs/rsyncd.secrets", __FILE__), "/tmp/.")
|
56
|
+
copy_2 = cmd.execute.failed?
|
57
|
+
cmd = container.exec(['bash -c "chmod 600 /tmp/rsyncd.secrets && chown root /tmp/*"'])
|
58
|
+
chmod = cmd.execute.failed?
|
59
|
+
if copy_1 or copy_2 or chmod
|
60
|
+
puts "problema nella copia dei file di configurazione nel pod"
|
61
|
+
else
|
62
|
+
|
63
|
+
begin
|
64
|
+
cmd = container.exec('bash -c "rsync --daemon --config=/tmp/rsyncd.conf --verbose --log-file=/tmp/rsync.log"')
|
65
|
+
if cmd.execute.failed?
|
66
|
+
say "Rsync non Inizializzato"
|
67
|
+
else
|
68
|
+
begin
|
69
|
+
local_port = rand(30000..40000)
|
70
|
+
|
71
|
+
p = IO.popen(container.base_cmd("port-forward #{podname} #{local_port}:873").string_command)
|
72
|
+
pid = p.pid
|
73
|
+
say "PID in execuzione port forward:#{pid}"
|
74
|
+
|
75
|
+
begin
|
76
|
+
|
77
|
+
sleep 1
|
78
|
+
|
79
|
+
# lanciamo il comando quindi per far rsync
|
80
|
+
rsync_command = [
|
81
|
+
"rsync -az --no-o --no-g",
|
82
|
+
"--delete",
|
83
|
+
"--password-file=#{ File.expand_path("../../rsync_cfgs/password", __FILE__)}"
|
84
|
+
]
|
85
|
+
|
86
|
+
if direction == :up
|
87
|
+
rsync_command << "#{local_folder}/."
|
88
|
+
rsync_command << "rsync://root@0.0.0.0:#{local_port}/archives#{remote_folder}"
|
89
|
+
else
|
90
|
+
rsync_command << "rsync://root@0.0.0.0:#{local_port}/archives#{remote_folder}/."
|
91
|
+
rsync_command << local_folder
|
92
|
+
end
|
93
|
+
say "Eseguo rsync #{rsync_command.join(" ")}"
|
94
|
+
|
95
|
+
cmd = ShellCommandExecution.new(rsync_command)
|
96
|
+
cmd.execute
|
97
|
+
|
98
|
+
ensure
|
99
|
+
sleep 1
|
100
|
+
say "Stoppo porta forwarded"
|
101
|
+
Process.kill("INT", pid)
|
102
|
+
end
|
103
|
+
ensure
|
104
|
+
say "Tolgo il servizio di rsyn"
|
105
|
+
cmd = container.exec('bash -c "killall rsync"')
|
106
|
+
cmd.execute
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
ensure
|
111
|
+
say "Eseguo pulizia configurazioni caricate"
|
112
|
+
cmd = container.exec('bash -c "rm -fr /tmp/rsyncd*"')
|
113
|
+
cmd.execute
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
|
3
3
|
module SwarmClusterCliOpe
|
4
|
-
##
|
5
|
-
# Identifica una risposta dalla shell
|
4
|
+
##
|
5
|
+
# Identifica una risposta dalla shell
|
6
6
|
class ShellCommandResponse
|
7
7
|
extend Forwardable
|
8
8
|
include LoggerConcern
|
@@ -28,9 +28,22 @@ module SwarmClusterCliOpe
|
|
28
28
|
##
|
29
29
|
# Risultato, essendo sempre composto da una lista di righe in formato json, ritorniamo un array di json
|
30
30
|
# @param [Object] object_class
|
31
|
-
# @return [Array<object_class
|
32
|
-
def result(object_class: OpenStruct)
|
33
|
-
|
31
|
+
# @return [Array<object_class>,Object]
|
32
|
+
def result(object_class: OpenStruct, single: false)
|
33
|
+
#tento prima di estrapolare direttamente da json e sucessivamente come array
|
34
|
+
if single
|
35
|
+
# questo per k8s, dato che abbiamo come risposta un json vero
|
36
|
+
object_class.new(JSON.parse(raw_result[:stdout]))
|
37
|
+
else
|
38
|
+
# questo nel caso siamo in swarm che ci ritorna un array di json
|
39
|
+
raw_result[:stdout].split("\n").collect { |s| object_class.new(JSON.parse(s)) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param [Class<OpenStruct>] object_class
|
44
|
+
# @return [Object]
|
45
|
+
def single_obj(object_class: OpenStruct)
|
46
|
+
result(object_class: object_class, single: true)
|
34
47
|
end
|
35
48
|
|
36
49
|
#
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module SwarmClusterCliOpe
|
4
|
+
module StackSyncConcern
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
|
9
|
+
desc "stacksync [DIRECTION:pull|push]", "Si occupa di scaricare|caricare,utilizzando le configurazioni presenti, i dati dallo stack remoto"
|
10
|
+
long_desc <<-LONGDESC.gsub("\n", "\x5")
|
11
|
+
le configurazioni sono contenute nell'array: sync_configs.
|
12
|
+
ogni configurazione è composta da:
|
13
|
+
{
|
14
|
+
service:""
|
15
|
+
how:""
|
16
|
+
configs:{ }
|
17
|
+
}
|
18
|
+
- service è il nome del servizio (o nel caso di k8s una stringa da utilizzare come selettore labels)
|
19
|
+
- how è il come sincronizzare, definendo la tipologia:
|
20
|
+
---- pg -> DB TODO
|
21
|
+
---- mysql -> DB dump con mysql
|
22
|
+
---- sqlite3 -> DB: viene eseguita una copia del file
|
23
|
+
---- rsync -> RSYNC
|
24
|
+
- configs: è un hash con le configurazioni per ogni tipo di sincronizzazione
|
25
|
+
|
26
|
+
Possibili CFGS per tipologia:
|
27
|
+
rsync:
|
28
|
+
--local: -> path cartella locale
|
29
|
+
--remote: -> path cartella remota (contesto del container)
|
30
|
+
|
31
|
+
sqlite3:
|
32
|
+
--local: -> path al file
|
33
|
+
--remote: -> path al file remoto (contesto del container)
|
34
|
+
|
35
|
+
mysql:
|
36
|
+
--local: -> hash di configurazioni per il DB locale
|
37
|
+
- service: "db" -> nome del servizio nel compose locale, DEFAULT: quello definito sopra
|
38
|
+
- mysql_password_env: "MYSQL_PASSWORD" -> variabile ambiente interna al servizio contenente PASSWORD, DEFAULT: MYSQL_PASSWORD
|
39
|
+
- mysql_password: "root" -> valore in chiaro, in sostituzione della variabile ambiente, DEFAULT: root
|
40
|
+
- mysql_user_env: "MYSQL_USER" -> variabile ambiente interna al servizio contenente USERNAME, DEFAULT: MYSQL_USER
|
41
|
+
- mysql_user: "root" -> valore in chiaro, in sostituzione della variabile ambiente, DEFAULT: root
|
42
|
+
- database_name_env: "MYSQL_DATABASE" -> variabile ambiente interna al servizio contenente NOME DB, DEFAULT: MYSQL_DATABASE
|
43
|
+
- database_name: "nome_db" -> valore in chiaro, in sostituzione della variabile ambiente
|
44
|
+
--remote: -> hash di configurazioni per il DB remoto
|
45
|
+
- service: "db" -> nome del servizio nel compose locale, DEFAULT: quello definito sopra
|
46
|
+
- mysql_password_env: "MYSQL_PASSWORD" -> variabile ambiente interna al servizio contenente PASSWORD, DEFAULT: MYSQL_PASSWORD
|
47
|
+
- mysql_password: "root" -> valore in chiaro, in sostituzione della variabile ambiente, DEFAULT: root
|
48
|
+
- mysql_user_env: "MYSQL_USER" -> variabile ambiente interna al servizio contenente USERNAME, DEFAULT: MYSQL_USER
|
49
|
+
- mysql_user: "root" -> valore in chiaro, in sostituzione della variabile ambiente, DEFAULT: root
|
50
|
+
- database_name_env: "MYSQL_DATABASE" -> variabile ambiente interna al servizio contenente NOME DB, DEFAULT: MYSQL_DATABASE
|
51
|
+
- database_name: "MYSQL_DATABASE" -> valore in chiaro, in sostituzione della variabile ambiente
|
52
|
+
pg:
|
53
|
+
--local: -> hash di configurazioni per il DB locale
|
54
|
+
- service: "db" -> nome del servizio nel compose locale, DEFAULT: quello definito sopra
|
55
|
+
- pg_password_env: "POSTGRES_USER" -> variabile ambiente interna al servizio contenente PASSWORD, DEFAULT: POSTGRES_PASSWORD
|
56
|
+
- pg_password: "" -> valore in chiaro, in sostituzione della variabile ambiente
|
57
|
+
- pg_user_env: "POSTGRES_USER" -> variabile ambiente interna al servizio contenente USERNAME, DEFAULT: POSTGRES_USER
|
58
|
+
- pg_user: "postgres" -> valore in chiaro, in sostituzione della variabile ambiente, DEFAULT: postgres
|
59
|
+
- database_name_env: "POSTGRES_DB" -> variabile ambiente interna al servizio contenente NOME DB, DEFAULT: POSTGRES_DB
|
60
|
+
- database_name: "nome_db" -> valore in chiaro, in sostituzione della variabile ambiente
|
61
|
+
--remote: -> hash di configurazioni per il DB remoto
|
62
|
+
- service: "db" -> nome del servizio nel compose locale, DEFAULT: quello definito sopra
|
63
|
+
- pg_password_env: "POSTGRES_USER" -> variabile ambiente interna al servizio contenente PASSWORD, DEFAULT: POSTGRES_PASSWORD
|
64
|
+
- pg_password: "" -> valore in chiaro, in sostituzione della variabile ambiente
|
65
|
+
- pg_user_env: "POSTGRES_USER" -> variabile ambiente interna al servizio contenente USERNAME, DEFAULT: POSTGRES_USER
|
66
|
+
- pg_user: "postgres" -> valore in chiaro, in sostituzione della variabile ambiente, DEFAULT: postgres
|
67
|
+
- database_name_env: "POSTGRES_DB" -> variabile ambiente interna al servizio contenente NOME DB, DEFAULT: POSTGRES_DB
|
68
|
+
- database_name: "nome_db" -> valore in chiaro, in sostituzione della variabile ambiente
|
69
|
+
|
70
|
+
|
71
|
+
EXAMPLE:
|
72
|
+
Esempio di sincronizzazione di un file sqlite3 e una cartella
|
73
|
+
{
|
74
|
+
"stack_name": "test1",
|
75
|
+
"sync_configs": [
|
76
|
+
{
|
77
|
+
"service": "second",
|
78
|
+
"how": "rsync",
|
79
|
+
"configs": {
|
80
|
+
"remote": "/test_bind",
|
81
|
+
"local": "./uploads"
|
82
|
+
}
|
83
|
+
},
|
84
|
+
{
|
85
|
+
"service": "test_sqlite3",
|
86
|
+
"how": "sqlite3",
|
87
|
+
"configs": {
|
88
|
+
"remote": "/cartella_sqlite3/esempio.sqlite3",
|
89
|
+
"local": "./development.sqlite3"
|
90
|
+
}
|
91
|
+
}
|
92
|
+
]
|
93
|
+
}
|
94
|
+
LONGDESC
|
95
|
+
|
96
|
+
def stacksync(direction)
|
97
|
+
direction = case direction
|
98
|
+
when 'push'
|
99
|
+
:push
|
100
|
+
when 'pull'
|
101
|
+
:pull
|
102
|
+
else
|
103
|
+
raise "ONLY [push|pull] action accepted"
|
104
|
+
end
|
105
|
+
cfgs.env(options[:environment]) do |cfgs|
|
106
|
+
sync_cfgs = cfgs.sync_configurations
|
107
|
+
if sync_cfgs.empty?
|
108
|
+
say "Attenzione, configurazioni di sincronizzazione vuoto. Leggere la documentazione"
|
109
|
+
else
|
110
|
+
sync_cfgs.each do |sync|
|
111
|
+
say "----------->>>>>>"
|
112
|
+
say "[ #{sync.class.name} ]"
|
113
|
+
sync.send(direction)
|
114
|
+
say "COMPLETE"
|
115
|
+
say "<<<<<<-----------"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
# module ClassMethods
|
125
|
+
|
126
|
+
# end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module SwarmClusterCliOpe
|
4
|
+
module ThorConfigurationConcern
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
|
9
|
+
desc "config", "Visualizza le configurazioni mergiate (HOME + Project configuration[#{Configuration.cfgs_project_file_name}])"
|
10
|
+
|
11
|
+
def config
|
12
|
+
cfgs.env(options[:environment]) do
|
13
|
+
puts JSON.pretty_generate(cfgs.merged_configurations)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "configure_project STACK_NAME", "Genera il file di configurazione del progetto contenente il nome dello stack"
|
18
|
+
|
19
|
+
def configure_project(stack_name)
|
20
|
+
cfgs.env(options[:environment]) do |c|
|
21
|
+
c.stack_name = stack_name
|
22
|
+
c.save_project_cfgs
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
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.
|
4
|
+
version: 0.5.0.pre.5
|
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-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- Rakefile
|
89
89
|
- exe/swarm_cli_ope
|
90
90
|
- lib/swarm_cluster_cli_ope.rb
|
91
|
+
- lib/swarm_cluster_cli_ope/base_configuration.rb
|
91
92
|
- lib/swarm_cluster_cli_ope/cli.rb
|
92
93
|
- lib/swarm_cluster_cli_ope/commands/base.rb
|
93
94
|
- lib/swarm_cluster_cli_ope/commands/compose_container.rb
|
@@ -97,6 +98,15 @@ files:
|
|
97
98
|
- lib/swarm_cluster_cli_ope/commands/task.rb
|
98
99
|
- lib/swarm_cluster_cli_ope/configuration.rb
|
99
100
|
- lib/swarm_cluster_cli_ope/configuration_concern.rb
|
101
|
+
- lib/swarm_cluster_cli_ope/k8s.rb
|
102
|
+
- lib/swarm_cluster_cli_ope/kubernetes/configuration.rb
|
103
|
+
- lib/swarm_cluster_cli_ope/kubernetes/pod.rb
|
104
|
+
- lib/swarm_cluster_cli_ope/kubernetes/rsync_cfgs/password
|
105
|
+
- lib/swarm_cluster_cli_ope/kubernetes/rsync_cfgs/rsyncd.conf
|
106
|
+
- lib/swarm_cluster_cli_ope/kubernetes/rsync_cfgs/rsyncd.secrets
|
107
|
+
- lib/swarm_cluster_cli_ope/kubernetes/sync_configs/base_decorator.rb
|
108
|
+
- lib/swarm_cluster_cli_ope/kubernetes/sync_configs/rsync.rb
|
109
|
+
- lib/swarm_cluster_cli_ope/kubernetes/sync_configs/sqlite3.rb
|
100
110
|
- lib/swarm_cluster_cli_ope/logger_concern.rb
|
101
111
|
- lib/swarm_cluster_cli_ope/manager.rb
|
102
112
|
- lib/swarm_cluster_cli_ope/models/base.rb
|
@@ -109,6 +119,7 @@ files:
|
|
109
119
|
- lib/swarm_cluster_cli_ope/node.rb
|
110
120
|
- lib/swarm_cluster_cli_ope/shell_command_execution.rb
|
111
121
|
- lib/swarm_cluster_cli_ope/shell_command_response.rb
|
122
|
+
- lib/swarm_cluster_cli_ope/stack_sync_concern.rb
|
112
123
|
- lib/swarm_cluster_cli_ope/sync_configs/base.rb
|
113
124
|
- lib/swarm_cluster_cli_ope/sync_configs/base_database.rb
|
114
125
|
- lib/swarm_cluster_cli_ope/sync_configs/copy.rb
|
@@ -117,6 +128,7 @@ files:
|
|
117
128
|
- lib/swarm_cluster_cli_ope/sync_configs/post_gres.rb
|
118
129
|
- lib/swarm_cluster_cli_ope/sync_configs/rsync.rb
|
119
130
|
- lib/swarm_cluster_cli_ope/sync_configs/sqlite3.rb
|
131
|
+
- lib/swarm_cluster_cli_ope/thor_configuration_concern.rb
|
120
132
|
- lib/swarm_cluster_cli_ope/version.rb
|
121
133
|
- lib/swarm_cluster_cli_ope/worker.rb
|
122
134
|
- swarm_cluster_cli_ope.gemspec
|
@@ -139,9 +151,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
139
151
|
version: 2.3.0
|
140
152
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
153
|
requirements:
|
142
|
-
- - "
|
154
|
+
- - ">"
|
143
155
|
- !ruby/object:Gem::Version
|
144
|
-
version:
|
156
|
+
version: 1.3.1
|
145
157
|
requirements: []
|
146
158
|
rubygems_version: 3.0.8
|
147
159
|
signing_key:
|