vagrant-compose 0.2.4 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/CHANGELOG.md +4 -0
- data/README.md +15 -408
- data/doc/declarative.md +431 -0
- data/doc/programmatic.md +435 -0
- data/lib/locales/en.yml +7 -4
- data/lib/vagrant/compose/config.rb +89 -20
- data/lib/vagrant/compose/declarative/cluster.rb +139 -0
- data/lib/vagrant/compose/errors.rb +5 -1
- data/lib/vagrant/compose/{util/node.rb → node.rb} +0 -0
- data/lib/vagrant/compose/programmatic/cluster.rb +227 -0
- data/lib/vagrant/compose/programmatic/node_group.rb +104 -0
- data/lib/vagrant/compose/version.rb +1 -1
- data/vagrant-compose.gemspec +3 -2
- metadata +22 -5
- data/lib/vagrant/compose/util/cluster.rb +0 -265
- data/lib/vagrant/compose/util/node_group.rb +0 -102
@@ -1,265 +0,0 @@
|
|
1
|
-
require_relative "node_group"
|
2
|
-
|
3
|
-
|
4
|
-
module VagrantPlugins
|
5
|
-
module Compose
|
6
|
-
|
7
|
-
# This class defines a cluster, thas is a set of group of nodes, where nodes in each group has similar characteristics.
|
8
|
-
# Basically, a cluster is a data structure that can be used as a recipe for setting up and provisioning a
|
9
|
-
# vagrant cluster composed by several machines with different roles.
|
10
|
-
class Cluster
|
11
|
-
|
12
|
-
# The name of the cluster
|
13
|
-
attr_reader :name
|
14
|
-
|
15
|
-
# The default vagrant base box to be used for creating vagrant machines in this cluster.
|
16
|
-
# This setting can be changed at group/node level
|
17
|
-
attr_accessor :box
|
18
|
-
|
19
|
-
# The network domain to wich the cluster belongs (used for computing nodes fqdn)
|
20
|
-
attr_accessor :domain
|
21
|
-
|
22
|
-
|
23
|
-
# The root path for ansible playbook; it is used as a base path for computing ansible_group_vars and ansible_host_vars
|
24
|
-
# It defaults to current directory/provisioning
|
25
|
-
attr_accessor :ansible_playbook_path
|
26
|
-
|
27
|
-
# A dictionary, allowing to setup ansible_group_vars generators foreach node_group
|
28
|
-
attr_reader :ansible_group_vars
|
29
|
-
|
30
|
-
# A dictionary, allowing to setup ansible_host_vars generators foreach node_group
|
31
|
-
attr_reader :ansible_host_vars
|
32
|
-
|
33
|
-
# A dictionary, allowing to setup context vars to be uses is value_generators when composing nodes
|
34
|
-
attr_reader :ansible_context_vars
|
35
|
-
|
36
|
-
# A variable that reflects if vagrant is tageting a single machine, like f.i. when executing vagrant up machine-name
|
37
|
-
attr_reader :multimachine_filter
|
38
|
-
|
39
|
-
# Costruttore di una istanza di cluster.
|
40
|
-
def initialize(name)
|
41
|
-
@group_index = 0
|
42
|
-
@node_groups = {}
|
43
|
-
@ansible_context_vars = {}
|
44
|
-
@ansible_group_vars = {}
|
45
|
-
@ansible_host_vars = {}
|
46
|
-
@multimachine_filter = ""
|
47
|
-
@ansible_playbook_path = File.join(Dir.pwd, 'provisioning')
|
48
|
-
|
49
|
-
@name = name
|
50
|
-
@box = 'ubuntu/trusty64'
|
51
|
-
@domain = 'vagrant'
|
52
|
-
end
|
53
|
-
|
54
|
-
# Metodo per la creazione di un gruppo di nodi; in fase di creazione, il blocco inizializza
|
55
|
-
# i valori/le expressioni da utilizzarsi nella valorizzazione degli attributi dei nodi in fase di compose.
|
56
|
-
#
|
57
|
-
# Oltre alla creazione dei nodi, il metodo prevede anche l'esecuzione di un blocco di codice per
|
58
|
-
# la configurazione del gruppo di nodi stesso.
|
59
|
-
def nodes(instances, name, &block)
|
60
|
-
raise RuntimeError, "Nodes #{name} already exists in this cluster." unless not @node_groups.has_key?(name)
|
61
|
-
|
62
|
-
@node_groups[name] = NodeGroup.new(@group_index, instances, name)
|
63
|
-
@node_groups[name].box = @box
|
64
|
-
@node_groups[name].boxname = lambda { |group_index, group_name, node_index| return "#{group_name}#{node_index + 1}" }
|
65
|
-
@node_groups[name].hostname = lambda { |group_index, group_name, node_index| return "#{group_name}#{node_index + 1}" }
|
66
|
-
@node_groups[name].aliases = []
|
67
|
-
@node_groups[name].ip = lambda { |group_index, group_name, node_index| return "172.31.#{group_index}.#{100 + node_index + 1}" }
|
68
|
-
@node_groups[name].cpus = 1
|
69
|
-
@node_groups[name].memory = 256
|
70
|
-
@node_groups[name].ansible_groups = []
|
71
|
-
@node_groups[name].attributes = {}
|
72
|
-
|
73
|
-
@group_index += 1
|
74
|
-
|
75
|
-
block.call(@node_groups[name]) if block_given?
|
76
|
-
end
|
77
|
-
|
78
|
-
# Prepara il provisioning del cluster
|
79
|
-
def compose
|
80
|
-
|
81
|
-
@multimachine_filter = ((['up', 'provision'].include? ARGV[0]) && ARGV.length > 1) ? ARGV.drop(1) : [] # detect if running vagrant up/provision MACHINE
|
82
|
-
|
83
|
-
## Fase1: Creazione dei nodi
|
84
|
-
|
85
|
-
# sviluppa i vari gruppi di nodi, creando i singoli nodi
|
86
|
-
nodes = []
|
87
|
-
|
88
|
-
@node_groups.each do |key, group|
|
89
|
-
group.compose(@name, @domain, nodes.size) do |node|
|
90
|
-
nodes << node
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# sviluppa i gruppi abbinando a ciascono i nodi creati
|
95
|
-
# NB. tiene in considerazione anche l'eventualità che un gruppo possa essere composto da nodi appartenenti a diversi node_groups
|
96
|
-
ansible_groups= {}
|
97
|
-
nodes.each do |node|
|
98
|
-
node.ansible_groups.each do |ansible_group|
|
99
|
-
ansible_groups[ansible_group] = [] unless ansible_groups.has_key? (ansible_group)
|
100
|
-
ansible_groups[ansible_group] << node
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
## Fase2: Configurazione provisioning del cluster via Ansible
|
105
|
-
# Ogni nodo diventerà una vm su cui sarà fatto il provisioning, ovvero un host nell'inventory di ansible
|
106
|
-
# Ad ogni gruppo corrispondono nodi con caratteristiche simili
|
107
|
-
|
108
|
-
# genearazione inventory file per ansible, aka ansible_groups in Vagrant (NB. 1 group = 1 gruppo ansible)
|
109
|
-
ansible_groups_provision = {}
|
110
|
-
ansible_groups.each do |ansible_group, ansible_group_nodes|
|
111
|
-
ansible_groups_provision[ansible_group] = []
|
112
|
-
ansible_group_nodes.each do |node|
|
113
|
-
ansible_groups_provision[ansible_group] << node.hostname if checkMultimachineFilter(node.boxname) #filter ansible groups if vagrant command on one node
|
114
|
-
end
|
115
|
-
end
|
116
|
-
ansible_groups_provision['all_groups:children'] = ansible_groups.keys
|
117
|
-
|
118
|
-
# Oltre alla creazione del file di inventory per ansible, contenente gruppi e host, è supportata:
|
119
|
-
# - la creazione di file ansible_group_vars, ovvero di file preposti a contenere una serie di variabili - specifico di ogni gruppo di host -
|
120
|
-
# per condizionare il provisioning ansible sulla base delle caratteristiche del cluster specifico
|
121
|
-
# - la creazione di file ansible_host_vars, ovvero di file preposti a contenere una serie di variabili - specifico di ogni host -
|
122
|
-
# per condizionare il provisioning ansible sulla base delle caratteristiche del cluster specifico
|
123
|
-
|
124
|
-
# La generazione delle variabili utilizza una serie di VariableProvisioner, uno o più d'uno per ogni gruppo di hosts, configurati durante la
|
125
|
-
# definizione del cluster.
|
126
|
-
|
127
|
-
context = {}
|
128
|
-
|
129
|
-
#genearazione context (NB. 1 group = 1 gruppo host ansible)
|
130
|
-
ansible_groups.each do |ansible_group, ansible_group_nodes|
|
131
|
-
# genero le variabili per il group
|
132
|
-
provisioners = @ansible_context_vars[ansible_group]
|
133
|
-
unless provisioners.nil?
|
134
|
-
|
135
|
-
# se necessario, normalizzo provisioner in array provisioners
|
136
|
-
provisioners = [ provisioners ] if not provisioners.respond_to?('each')
|
137
|
-
# per tutti i provisioners abbinati al ruolo
|
138
|
-
provisioners.each do |provisioner|
|
139
|
-
begin
|
140
|
-
vars = provisioner.call(context, ansible_group_nodes)
|
141
|
-
|
142
|
-
#TODO: gestire conflitto (n>=2 gruppi che generano la stessa variabile - con valori diversi)
|
143
|
-
context = context.merge(vars)
|
144
|
-
rescue Exception => e
|
145
|
-
raise VagrantPlugins::Compose::Errors::ContextVarExpressionError, :message => e.message, :ansible_group => ansible_group
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
# cleanup ansible_group_vars files
|
152
|
-
# TODO: make safe
|
153
|
-
ansible_group_vars_path = File.join(@ansible_playbook_path, 'group_vars')
|
154
|
-
|
155
|
-
FileUtils.mkdir_p(ansible_group_vars_path) unless File.exists?(ansible_group_vars_path)
|
156
|
-
Dir.foreach(ansible_group_vars_path) {|f| fn = File.join(ansible_group_vars_path, f); File.delete(fn) if f.end_with?(".yml")}
|
157
|
-
|
158
|
-
#generazione ansible_group_vars file (NB. 1 group = 1 gruppo host ansible)
|
159
|
-
ansible_groups.each do |ansible_group, ansible_group_nodes|
|
160
|
-
ansible_group_vars = {}
|
161
|
-
# genero le variabili per il group
|
162
|
-
provisioners = @ansible_group_vars[ansible_group]
|
163
|
-
unless provisioners.nil?
|
164
|
-
# se necessario, normalizzo provisioner in array provisioners
|
165
|
-
provisioners = [ provisioners ] if not provisioners.respond_to?('each')
|
166
|
-
# per tutti i provisioners abbinati al ruolo
|
167
|
-
provisioners.each do |provisioner|
|
168
|
-
begin
|
169
|
-
vars = provisioner.call(context, ansible_group_nodes)
|
170
|
-
|
171
|
-
#TODO: gestire conflitto (n>=2 gruppi che generano la stessa variabile - con valori diversi)
|
172
|
-
ansible_group_vars = ansible_group_vars.merge(vars)
|
173
|
-
rescue Exception => e
|
174
|
-
raise VagrantPlugins::Compose::Errors::GroupVarExpressionError, :message => e.message, :ansible_group => ansible_group
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
# crea il file (se sono state generate delle variabili)
|
180
|
-
unless ansible_group_vars.empty?
|
181
|
-
# TODO: make safe
|
182
|
-
File.open(File.join(ansible_group_vars_path,"#{ansible_group}.yml") , 'w+') do |file|
|
183
|
-
file.puts YAML::dump(ansible_group_vars)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
# cleanup ansible_host_vars files (NB. 1 nodo = 1 host)
|
189
|
-
# TODO: make safe
|
190
|
-
ansible_host_vars_path = File.join(@ansible_playbook_path, 'host_vars')
|
191
|
-
|
192
|
-
FileUtils.mkdir_p(ansible_host_vars_path) unless File.exists?(ansible_host_vars_path)
|
193
|
-
Dir.foreach(ansible_host_vars_path) {|f| fn = File.join(ansible_host_vars_path, f); File.delete(fn) if f.end_with?(".yml")}
|
194
|
-
|
195
|
-
#generazione ansible_host_vars file
|
196
|
-
nodes.each do |node|
|
197
|
-
# genero le variabili per il nodo; il nodo, può essere abbinato a diversi gruppi
|
198
|
-
ansible_host_vars = {}
|
199
|
-
node.ansible_groups.each do |ansible_group|
|
200
|
-
# genero le variabili per il gruppo
|
201
|
-
provisioners = @ansible_host_vars[ansible_group]
|
202
|
-
unless provisioners.nil?
|
203
|
-
# se necessario, normalizzo provisioner in array provisioners
|
204
|
-
provisioners = [ provisioners ] if not provisioners.respond_to?('each')
|
205
|
-
# per tutti i provisioners abbinati al gruppo
|
206
|
-
provisioners.each do |provisioner|
|
207
|
-
begin
|
208
|
-
vars = provisioner.call(context, node)
|
209
|
-
|
210
|
-
#TODO: gestire conflitto (n>=2 gruppi che generano la stessa variabile - con valori diversi)
|
211
|
-
ansible_host_vars = ansible_host_vars.merge(vars)
|
212
|
-
rescue Exception => e
|
213
|
-
raise VagrantPlugins::Compose::Errors::HostVarExpressionError, :message => e.message, :host => node.hostname, :ansible_group => ansible_group
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
# crea il file (se sono state generate delle variabili)
|
220
|
-
unless ansible_host_vars.empty?
|
221
|
-
# TODO: make safe
|
222
|
-
File.open(File.join(ansible_host_vars_path,"#{node.hostname}.yml") , 'w+') do |file|
|
223
|
-
file.puts YAML::dump(ansible_host_vars)
|
224
|
-
end
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
return nodes, ansible_groups_provision
|
229
|
-
end
|
230
|
-
|
231
|
-
# Prepara il provisioning del cluster
|
232
|
-
def from(file)
|
233
|
-
puts "from #{file}"
|
234
|
-
begin
|
235
|
-
a = `ls`
|
236
|
-
puts "get #{a}"
|
237
|
-
rescue Exception => e
|
238
|
-
raise VagrantPlugins::Compose::Errors::PyComposeError, :message => e.message
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
def checkMultimachineFilter(boxname)
|
243
|
-
if @multimachine_filter.length > 0
|
244
|
-
@multimachine_filter.each do |name|
|
245
|
-
if pattern = name[/^\/(.+?)\/$/, 1]
|
246
|
-
# This is a regular expression name, so we convert to a regular
|
247
|
-
# expression and allow that sort of matching.
|
248
|
-
regex = Regexp.new(pattern)
|
249
|
-
return boxname =~ regex
|
250
|
-
else
|
251
|
-
# String name, just look for a specific VM
|
252
|
-
return boxname == name
|
253
|
-
end
|
254
|
-
end
|
255
|
-
else
|
256
|
-
# No name was given, so we return every VM in the order
|
257
|
-
# configured.
|
258
|
-
return true
|
259
|
-
end
|
260
|
-
end
|
261
|
-
|
262
|
-
end
|
263
|
-
|
264
|
-
end
|
265
|
-
end
|
@@ -1,102 +0,0 @@
|
|
1
|
-
require_relative "node"
|
2
|
-
|
3
|
-
module VagrantPlugins
|
4
|
-
module Compose
|
5
|
-
|
6
|
-
# This class defines a group of nodes, representig a set of vagrant machines with similar characteristics.
|
7
|
-
# Nodes will be composed by NodeGroup.compose method, according with the configuration of values/value_generator
|
8
|
-
# of the group of node itself.
|
9
|
-
class NodeGroup
|
10
|
-
|
11
|
-
# A number identifying the group of nodes withing the cluster.
|
12
|
-
attr_reader :index
|
13
|
-
|
14
|
-
# The name of the group of nodes
|
15
|
-
attr_reader :name
|
16
|
-
|
17
|
-
# The number of nodes/instances to be created in the group of nodes.
|
18
|
-
attr_reader :instances
|
19
|
-
|
20
|
-
# The value/value generator to be used for assigning to each node in this group a vagrant base box to be used for creating vagrant machines implementing nodes in this group.
|
21
|
-
attr_accessor :box
|
22
|
-
|
23
|
-
# The value/value generator to be used for assigning to each node in this group a box name a.k.a. the name for the machine in VirtualBox/VMware console.
|
24
|
-
attr_accessor :boxname
|
25
|
-
|
26
|
-
# The value/value generator to be used for assigning to each node in this group a unique hostname
|
27
|
-
attr_accessor :hostname
|
28
|
-
|
29
|
-
# The value/value generator to be used for assigning to each node in this group a unique list of aliases a.k.a. alternative host names
|
30
|
-
attr_accessor :aliases
|
31
|
-
|
32
|
-
# The value/value generator to be used for assigning to each node in this groupa unique ip
|
33
|
-
attr_accessor :ip
|
34
|
-
|
35
|
-
# The value/value generator to be used for assigning to each node in this group cpus
|
36
|
-
attr_accessor :cpus
|
37
|
-
|
38
|
-
# The value/value generator to be used for assigning to each node in this group memory
|
39
|
-
attr_accessor :memory
|
40
|
-
|
41
|
-
# The value/value generator to be used for assigning each node in this group to a list of ansible groups
|
42
|
-
attr_accessor :ansible_groups
|
43
|
-
|
44
|
-
# The value/value generator to be used for assigning a dictionary with custom attributes - Hash(String, obj) - to each node in this group.
|
45
|
-
attr_accessor :attributes
|
46
|
-
|
47
|
-
def initialize(index, instances, name)
|
48
|
-
@index = index
|
49
|
-
@name = name
|
50
|
-
@instances = instances
|
51
|
-
end
|
52
|
-
|
53
|
-
# Composes the group of nodes, by creating the required number of nodes
|
54
|
-
# in accordance with values/value_generators.
|
55
|
-
# Additionally, some "embedded" trasformation will be applied to attributes (boxname, hostname) and
|
56
|
-
# some "autogenerated" node properties will be computed (fqdn).
|
57
|
-
def compose(cluster_name, cluster_domain, cluster_offset)
|
58
|
-
node_index = 0
|
59
|
-
while node_index < @instances
|
60
|
-
box = generate(:box, @box, node_index)
|
61
|
-
boxname = maybe_prefix(cluster_name,
|
62
|
-
"#{generate(:boxname, @boxname, node_index)}")
|
63
|
-
hostname = maybe_prefix(cluster_name,
|
64
|
-
"#{generate(:hostname, @hostname, node_index)}")
|
65
|
-
aliases = generate(:aliases, @aliases, node_index).join(',')
|
66
|
-
fqdn = cluster_domain.empty? ? "#{hostname}" : "#{hostname}.#{cluster_domain}"
|
67
|
-
ip = generate(:ip, @ip, node_index)
|
68
|
-
cpus = generate(:cpus, @cpus, node_index)
|
69
|
-
memory = generate(:memory, @memory, node_index)
|
70
|
-
ansible_groups = generate(:ansible_groups, @ansible_groups, node_index)
|
71
|
-
attributes = generate(:attributes, @attributes, node_index)
|
72
|
-
yield Node.new(box, boxname, hostname, fqdn, aliases, ip, cpus, memory, ansible_groups, attributes, cluster_offset + node_index, node_index)
|
73
|
-
|
74
|
-
node_index += 1
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# utility function for concatenating cluster name (if present) to boxname/hostname
|
79
|
-
def maybe_prefix(cluster_name, name)
|
80
|
-
if cluster_name && cluster_name.length > 0
|
81
|
-
"#{cluster_name}-" + name
|
82
|
-
else
|
83
|
-
name
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
# utility function for resolving value/value generators
|
88
|
-
def generate(var, generator, node_index)
|
89
|
-
unless generator.respond_to? :call
|
90
|
-
return generator
|
91
|
-
else
|
92
|
-
begin
|
93
|
-
return generator.call(@index, @name, node_index)
|
94
|
-
rescue Exception => e
|
95
|
-
raise VagrantPlugins::Compose::Errors::AttributeExpressionError, :message => e.message, :attribute => var, :node_index => node_index, :node_group_name => name
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
end
|
102
|
-
end
|