dewiring 0.1.2
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 +15 -0
- data/bin/wire +7 -0
- data/bin/wire-network-container.sh +547 -0
- data/lib/test_fig.rb +46 -0
- data/lib/wire/cli/cli_commands.rb +88 -0
- data/lib/wire/cli/main_cli.rb +129 -0
- data/lib/wire/cli.rb +8 -0
- data/lib/wire/commands/base_command.rb +139 -0
- data/lib/wire/commands/down_command.rb +69 -0
- data/lib/wire/commands/down_command_handler.rb +199 -0
- data/lib/wire/commands/init_command.rb +89 -0
- data/lib/wire/commands/init_interactive.rb +75 -0
- data/lib/wire/commands/spec_command.rb +240 -0
- data/lib/wire/commands/spec_templates.rb +134 -0
- data/lib/wire/commands/up_command.rb +69 -0
- data/lib/wire/commands/up_command_handler.rb +193 -0
- data/lib/wire/commands/updown_command_base.rb +80 -0
- data/lib/wire/commands/validate_command.rb +64 -0
- data/lib/wire/commands/verify_command.rb +196 -0
- data/lib/wire/commands/verify_command_handler.rb +134 -0
- data/lib/wire/commands.rb +19 -0
- data/lib/wire/common.rb +42 -0
- data/lib/wire/execution/local_exec.rb +110 -0
- data/lib/wire/execution.rb +7 -0
- data/lib/wire/model/appgroup_validation.rb +45 -0
- data/lib/wire/model/loader.rb +49 -0
- data/lib/wire/model/network_validation.rb +111 -0
- data/lib/wire/model/project.rb +64 -0
- data/lib/wire/model/state.rb +154 -0
- data/lib/wire/model/validation.rb +66 -0
- data/lib/wire/model/verification.rb +37 -0
- data/lib/wire/model.rb +13 -0
- data/lib/wire/resource/bridge.rb +76 -0
- data/lib/wire/resource/dhcp_range_config.rb +135 -0
- data/lib/wire/resource/fig_adapter.rb +127 -0
- data/lib/wire/resource/ip_binary.rb +141 -0
- data/lib/wire/resource/ipaddr_ext.rb +38 -0
- data/lib/wire/resource/ipaddr_on_intf.rb +108 -0
- data/lib/wire/resource/network_injection.rb +138 -0
- data/lib/wire/resource/resource.rb +52 -0
- data/lib/wire/resource.rb +14 -0
- data/lib/wire/version.rb +14 -0
- data/lib/wire.rb +24 -0
- metadata +117 -0
@@ -0,0 +1,75 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
# Wire module
|
8
|
+
module Wire
|
9
|
+
# interactive ask_ commands
|
10
|
+
class InitInteractive
|
11
|
+
# ask for a comma separated list of zone names
|
12
|
+
# returns
|
13
|
+
# - [Array] of zone names
|
14
|
+
def self.ask_for_zone_names
|
15
|
+
question = <<-EOF
|
16
|
+
Please enter the names of desired system zones,
|
17
|
+
as a comma-separated list:
|
18
|
+
EOF
|
19
|
+
puts question
|
20
|
+
print '> '
|
21
|
+
|
22
|
+
line = STDIN.gets.chomp
|
23
|
+
|
24
|
+
line.split(',').map { |zone_name| zone_name.strip }
|
25
|
+
end
|
26
|
+
|
27
|
+
# Ask for network names in a zone given by +zone_name+
|
28
|
+
# Returns
|
29
|
+
# - [Array] of network names
|
30
|
+
def self.ask_for_network_in_zone(zone_name)
|
31
|
+
question = <<-EOF
|
32
|
+
- Configuring networks in zone #{zone_name}:
|
33
|
+
Please enter the names of logical networks
|
34
|
+
(or leave empty if no networks desired):
|
35
|
+
EOF
|
36
|
+
puts question
|
37
|
+
print '> '
|
38
|
+
|
39
|
+
line = STDIN.gets.chomp
|
40
|
+
|
41
|
+
line.split(',').map { |network_name| network_name.strip }
|
42
|
+
end
|
43
|
+
|
44
|
+
# For a network given by +network_name+, ask for details
|
45
|
+
# i.e. ipaddress etc.
|
46
|
+
# Returns
|
47
|
+
# - [Hash] of details
|
48
|
+
def self.ask_detail_data_for_network(network_name)
|
49
|
+
question = <<-EOF
|
50
|
+
= Configuring network #{network_name}
|
51
|
+
Please enter network address in cidr (i.e.192.168.1.0/24)
|
52
|
+
EOF
|
53
|
+
puts question
|
54
|
+
print '> '
|
55
|
+
|
56
|
+
line = STDIN.gets.chomp
|
57
|
+
result = {}
|
58
|
+
|
59
|
+
result.store :network, line.chomp.strip
|
60
|
+
|
61
|
+
question = <<-EOF
|
62
|
+
Please enter ip address of this network on host (i.e.192.168.1.1)
|
63
|
+
OR leave empty if not desired.
|
64
|
+
EOF
|
65
|
+
puts question
|
66
|
+
print '> '
|
67
|
+
|
68
|
+
line = STDIN.gets.chomp.strip
|
69
|
+
|
70
|
+
result.store(:hostip, line) if line.size > 0
|
71
|
+
|
72
|
+
result
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,240 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
# Wire module
|
8
|
+
module Wire
|
9
|
+
# SpecCommand generates a serverspec output for
|
10
|
+
# given model which tests all model elements.
|
11
|
+
# optionally runs serverspec
|
12
|
+
class SpecCommand < BaseCommand
|
13
|
+
# +project+ to operate on
|
14
|
+
attr_accessor :project
|
15
|
+
# +target_dir+ to read model from (and put specs into)
|
16
|
+
attr_accessor :target_dir
|
17
|
+
|
18
|
+
# spec_code will contain all serverspec
|
19
|
+
# code blocks, ready to be written to file
|
20
|
+
attr_accessor :spec_code
|
21
|
+
|
22
|
+
# initializes empty spec
|
23
|
+
def initialize
|
24
|
+
@spec_code = []
|
25
|
+
end
|
26
|
+
|
27
|
+
# process specification for whole project model
|
28
|
+
def run_on_project
|
29
|
+
@target_dir = @params[:target_dir]
|
30
|
+
zones = @project.get_element('zones')
|
31
|
+
|
32
|
+
# iterates all zones, descend into zone
|
33
|
+
run_on_project_zones(zones)
|
34
|
+
|
35
|
+
# use the specwrite class to write a complete
|
36
|
+
# serverspec example in a subdirectory(serverspec)
|
37
|
+
target_specdir = File.join(@target_dir, 'serverspec')
|
38
|
+
|
39
|
+
begin
|
40
|
+
spec_writer = SpecWriter.new(target_specdir, @spec_code)
|
41
|
+
spec_writer.write
|
42
|
+
|
43
|
+
outputs 'SPEC', "Serverspecs written to #{target_specdir}. Run:"
|
44
|
+
outputs 'SPEC', "( cd #{target_specdir}; sudo rake spec )"
|
45
|
+
outputs 'SPEC', 'To run automatically, use --run'
|
46
|
+
rescue => exception
|
47
|
+
$log.error "Error writing serverspec files, #{exception}"
|
48
|
+
STDERR.puts e.inspect
|
49
|
+
end
|
50
|
+
|
51
|
+
run_serverspec(target_specdir) if @params[:auto_run]
|
52
|
+
end
|
53
|
+
|
54
|
+
# executes serverspec in its target directory
|
55
|
+
# TODO: stream into stdout instead of Kernel.``
|
56
|
+
# params:
|
57
|
+
# +target_dir+ model and output dir
|
58
|
+
def run_serverspec(target_specdir)
|
59
|
+
$log.debug 'Running serverspec'
|
60
|
+
cmd = "cd #{target_specdir} && sudo rake spec"
|
61
|
+
$log.debug "cmd=#{cmd}"
|
62
|
+
result = `#{cmd}`
|
63
|
+
puts result
|
64
|
+
end
|
65
|
+
|
66
|
+
# run verification on +zones+
|
67
|
+
def run_on_project_zones(zones)
|
68
|
+
zones.select do |zone_name, _|
|
69
|
+
$log.debug("Creating specs for zone #{zone_name} ...")
|
70
|
+
run_on_zone(zone_name)
|
71
|
+
$log.debug("Done for zone #{zone_name} ...")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# run spec steps in given +zone_name+
|
76
|
+
def run_on_zone(zone_name)
|
77
|
+
networks = @project.get_element('networks')
|
78
|
+
|
79
|
+
# select networks in current zone only
|
80
|
+
networks_in_zone = networks.select do|_, network_data|
|
81
|
+
network_data[:zone] == zone_name
|
82
|
+
end
|
83
|
+
networks_in_zone.each do |network_name, network_data|
|
84
|
+
run_on_network_in_zone zone_name, network_name, network_data
|
85
|
+
end
|
86
|
+
|
87
|
+
# select application groups in current zone
|
88
|
+
objects_in_zone('appgroups', zone_name).each do |appgroup_name, appgroup_data|
|
89
|
+
run_on_appgroup_in_zone zone_name, appgroup_name, appgroup_data
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# given a network object, this generates spec
|
94
|
+
# for it.
|
95
|
+
# params:
|
96
|
+
# +zone_name+ name of zone (needed for erb context)
|
97
|
+
# +bridge_name+ name of network/bridge (needed for erb context)
|
98
|
+
# +network_data+ network details
|
99
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
100
|
+
# rubocop:disable Lint/UselessAssignment
|
101
|
+
# :reek:UnusedParameters
|
102
|
+
def run_on_network_in_zone(zone_name, bridge_name, network_data)
|
103
|
+
$log.debug("Creating specs for network #{bridge_name}")
|
104
|
+
|
105
|
+
template = SpecTemplates.build_template__bridge_exists
|
106
|
+
erb = ERB.new(template, nil, '%')
|
107
|
+
@spec_code << erb.result(binding)
|
108
|
+
|
109
|
+
# render template for hostip (if any)
|
110
|
+
ip = network_data[:hostip]
|
111
|
+
if ip
|
112
|
+
template = SpecTemplates.build_template__ip_is_up
|
113
|
+
erb = ERB.new(template, nil, '%')
|
114
|
+
@spec_code << erb.result(binding)
|
115
|
+
end
|
116
|
+
|
117
|
+
# render dhcp spec (if any)
|
118
|
+
dhcp_data = network_data[:dhcp]
|
119
|
+
if dhcp_data
|
120
|
+
ip_start = dhcp_data[:start]
|
121
|
+
ip_end = dhcp_data[:end]
|
122
|
+
hostip = ip
|
123
|
+
template = SpecTemplates.build_template__dhcp_is_valid
|
124
|
+
erb = ERB.new(template, nil, '%')
|
125
|
+
@spec_code << erb.result(binding)
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
$log.debug("Done for network #{bridge_name}")
|
130
|
+
end
|
131
|
+
|
132
|
+
# given an appgroup object, this generates spec
|
133
|
+
# for it.
|
134
|
+
# params:
|
135
|
+
# +zone_name+ name of zone (needed for erb context)
|
136
|
+
# +appgroup_name+ name of appgroup (needed for erb context)
|
137
|
+
# +appgroup_data+ appgroup details
|
138
|
+
# rubocop:disable Lint/UnusedMethodArgument Lint/UselessAssignment
|
139
|
+
# :reek:UnusedParameters
|
140
|
+
def run_on_appgroup_in_zone(zone_name, appgroup_name, appgroup_data)
|
141
|
+
$log.debug("Creating specs for appgroup #{appgroup_name}")
|
142
|
+
|
143
|
+
# check controller
|
144
|
+
controller_data = appgroup_data[:controller]
|
145
|
+
if controller_data[:type] == 'fig'
|
146
|
+
# get fig file name
|
147
|
+
figfile_part = controller_data[:file] || "#{zone_name}/fig.yaml"
|
148
|
+
figfile = File.join(File.expand_path(@target_dir), figfile_part)
|
149
|
+
|
150
|
+
template = SpecTemplates.build_template__fig_file_is_valid
|
151
|
+
erb = ERB.new(template, nil, '%')
|
152
|
+
@spec_code << erb.result(binding)
|
153
|
+
|
154
|
+
template = SpecTemplates.build_template__fig_containers_are_up
|
155
|
+
erb = ERB.new(template, nil, '%')
|
156
|
+
@spec_code << erb.result(binding)
|
157
|
+
end
|
158
|
+
|
159
|
+
$log.debug("Done for appgroup #{appgroup_name}")
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
# SpecWriter is able to create a directory
|
164
|
+
# structure according to basic serverspec
|
165
|
+
# needs and fill in the templates
|
166
|
+
class SpecWriter
|
167
|
+
# create SpecWriter in +target_dir+ directory
|
168
|
+
# with given +spec_contents+
|
169
|
+
def initialize(target_dir, spec_contents)
|
170
|
+
@target_dir = target_dir
|
171
|
+
@spec_contents = spec_contents
|
172
|
+
end
|
173
|
+
|
174
|
+
# writes spec to disk
|
175
|
+
def write
|
176
|
+
ensure_directory_structure
|
177
|
+
ensure_files
|
178
|
+
end
|
179
|
+
|
180
|
+
# make sure that we have a rspec-conformant dir structure
|
181
|
+
def ensure_directory_structure
|
182
|
+
ensure_directory @target_dir
|
183
|
+
ensure_directory File.join(@target_dir, 'spec')
|
184
|
+
ensure_directory File.join(@target_dir, 'spec', 'localhost')
|
185
|
+
end
|
186
|
+
|
187
|
+
# writes erb +template+ to open +file+ object
|
188
|
+
def write_template(template, file)
|
189
|
+
erb = ERB.new(template, nil, '%')
|
190
|
+
file.puts(erb.result(binding))
|
191
|
+
end
|
192
|
+
|
193
|
+
# ensures that all serverspec skeleton files such as
|
194
|
+
# Rakefile, spec_helper etc. exist
|
195
|
+
# Then writes the models specification files into the
|
196
|
+
# skeleton
|
197
|
+
def ensure_files
|
198
|
+
rakefile_name = File.join(@target_dir, 'Rakefile')
|
199
|
+
file?(rakefile_name) || File.open(rakefile_name, 'w') do |file|
|
200
|
+
write_template(SpecTemplates.template_rakefile, file)
|
201
|
+
end
|
202
|
+
|
203
|
+
spechelper_name = File.join(@target_dir, 'spec', 'spec_helper.rb')
|
204
|
+
file?(spechelper_name) || File.open(spechelper_name, 'w') do |file|
|
205
|
+
write_template(SpecTemplates.template_spec_helper, file)
|
206
|
+
end
|
207
|
+
|
208
|
+
specfile_name = File.join(@target_dir, 'spec', 'localhost', 'wire_spec.rb')
|
209
|
+
File.open(specfile_name, 'w') do |file|
|
210
|
+
template = <<ERB
|
211
|
+
require 'spec_helper.rb'
|
212
|
+
|
213
|
+
# begin of generated specs
|
214
|
+
|
215
|
+
<%= @spec_contents.join('\n') %>
|
216
|
+
|
217
|
+
# end of spec file
|
218
|
+
ERB
|
219
|
+
write_template(template, file)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
# make sure that +target_dir+ exists
|
226
|
+
def ensure_directory(target_dir)
|
227
|
+
return if File.exist?(target_dir)
|
228
|
+
begin
|
229
|
+
FileUtils.mkdir_p(target_dir)
|
230
|
+
rescue => excpt
|
231
|
+
$log.error "ERROR: Unable to create #{target_dir}: #{excpt}"
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# checks if +target_file+ exists
|
236
|
+
def file?(target_file)
|
237
|
+
File.exist?(target_file) && File.file?(target_file)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
# Wire module
|
8
|
+
module Wire
|
9
|
+
# stateless erb template methods used by spec_command.rb
|
10
|
+
class SpecTemplates
|
11
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
12
|
+
# :reek:UnusedParameters
|
13
|
+
def self.build_template__bridge_exists
|
14
|
+
<<ERB
|
15
|
+
describe 'In zone <%= zone_name %> we should have an ovs bridge named <%= bridge_name %>' do
|
16
|
+
describe command "sudo ovs-vsctl list-br" do
|
17
|
+
its(:stdout) { should match /<%= bridge_name %>/ }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
ERB
|
21
|
+
end
|
22
|
+
|
23
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
24
|
+
# :reek:UnusedParameters
|
25
|
+
def self.build_template__ip_is_up
|
26
|
+
<<ERB
|
27
|
+
describe 'In zone <%= zone_name %> we should have the ip <%= ip %> ' \
|
28
|
+
'on ovs bridge named <%= bridge_name %>' do
|
29
|
+
describe interface "<%= bridge_name %>" do
|
30
|
+
it { should have_ipv4_address '<%= ip %>' }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
ERB
|
34
|
+
end
|
35
|
+
|
36
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
37
|
+
# :reek:UnusedParameters
|
38
|
+
# requires zone_name, hostip, bridge_name, ip_start, ip_end
|
39
|
+
def self.build_template__dhcp_is_valid
|
40
|
+
<<ERB
|
41
|
+
describe 'In zone <%= zone_name %> we should have dhcp service on ip <%= hostip %> ' \
|
42
|
+
'on ovs bridge named <%= bridge_name %>, serving addresses from ' \
|
43
|
+
'<%= ip_start %> to <%= ip_end %>' do
|
44
|
+
|
45
|
+
describe file '/etc/dnsmasq.d/wire__<%= zone_name %>.conf' do
|
46
|
+
it { should be_file }
|
47
|
+
its(:content) { should match /<%= ip_start %>/ }
|
48
|
+
its(:content) { should match /<%= ip_end %>/ }
|
49
|
+
its(:content) { should match /<%= bridge_name %>/ }
|
50
|
+
end
|
51
|
+
|
52
|
+
describe process 'dnsmasq' do
|
53
|
+
it { should be_running }
|
54
|
+
end
|
55
|
+
|
56
|
+
describe port(67) do
|
57
|
+
it { should be_listening.with('udp') }
|
58
|
+
end
|
59
|
+
|
60
|
+
describe command '/bin/netstat -nlup' do
|
61
|
+
its(:stdout) { should match /67.*dnsmasq/ }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
ERB
|
65
|
+
end
|
66
|
+
|
67
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
68
|
+
# :reek:UnusedParameters
|
69
|
+
# requires figfile, appgroup_name
|
70
|
+
def self.build_template__fig_file_is_valid
|
71
|
+
<<ERB
|
72
|
+
describe 'In zone <%= zone_name %> we should have fig model file for '\
|
73
|
+
'appgroup <%= appgroup_name %>' do
|
74
|
+
describe file '<%= figfile %>' do
|
75
|
+
it { should be_file }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
ERB
|
79
|
+
end
|
80
|
+
|
81
|
+
# rubocop:disable Lint/UnusedMethodArgument
|
82
|
+
# :reek:UnusedParameters
|
83
|
+
# requires zone_name, figfile, appgroup_name
|
84
|
+
def self.build_template__fig_containers_are_up
|
85
|
+
<<ERB
|
86
|
+
describe 'In zone <%= zone_name %> we should have containers managed '\
|
87
|
+
'by fig for appgroup <%= appgroup_name %>' do
|
88
|
+
describe command 'sudo fig -p <%= appgroup_name %> -f <%= figfile %> ps' do
|
89
|
+
its(:stdout) { should match /Up/ }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
ERB
|
93
|
+
end
|
94
|
+
|
95
|
+
# generate template part
|
96
|
+
# returns
|
97
|
+
# - erb template for spec_helper.rb file
|
98
|
+
def self.template_spec_helper
|
99
|
+
<<ERB
|
100
|
+
require 'serverspec'
|
101
|
+
require 'rspec/its'
|
102
|
+
|
103
|
+
include SpecInfra::Helper::Exec
|
104
|
+
include SpecInfra::Helper::DetectOS
|
105
|
+
|
106
|
+
RSpec.configure do |c|
|
107
|
+
if ENV['ASK_SUDO_PASSWORD']
|
108
|
+
require 'highline/import'
|
109
|
+
c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false }
|
110
|
+
else
|
111
|
+
c.sudo_password = ENV['SUDO_PASSWORD']
|
112
|
+
end
|
113
|
+
end
|
114
|
+
ERB
|
115
|
+
end
|
116
|
+
|
117
|
+
# generate template part
|
118
|
+
# returns
|
119
|
+
# - erb template for Rakefile
|
120
|
+
def self.template_rakefile
|
121
|
+
<<ERB
|
122
|
+
require 'rake'
|
123
|
+
require 'rspec/core/rake_task'
|
124
|
+
|
125
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
126
|
+
t.pattern = 'spec/*/*_spec.rb'
|
127
|
+
t.rspec_opts = '--format documentation --color'
|
128
|
+
end
|
129
|
+
|
130
|
+
task :default => :spec
|
131
|
+
ERB
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
# Wire module
|
8
|
+
module Wire
|
9
|
+
# UpCommand reads yaml, parses model elements
|
10
|
+
# and brings all defined model elements "up", that is
|
11
|
+
# starting bridges, containers etc.
|
12
|
+
class UpCommand < UpDownCommand
|
13
|
+
# allow to get access to handler object
|
14
|
+
attr_reader :handler
|
15
|
+
|
16
|
+
# initialize
|
17
|
+
def initialize
|
18
|
+
@handler = UpCommandHandler.new
|
19
|
+
end
|
20
|
+
|
21
|
+
# run in given +zone_name+:
|
22
|
+
# returns:
|
23
|
+
# - bool: true if successful, false otherwise
|
24
|
+
# rubocop:disable CyclomaticComplexity
|
25
|
+
def run_on_zone(zone_name)
|
26
|
+
b_result = true
|
27
|
+
|
28
|
+
networks = @project.get_element('networks')
|
29
|
+
|
30
|
+
# select networks in current zone only
|
31
|
+
networks_in_zone = UpDownCommand.get_networks_for_zone(networks, zone_name)
|
32
|
+
networks_in_zone.each do |network_name, network_data|
|
33
|
+
$log.debug("Bringing up network #{network_name}")
|
34
|
+
|
35
|
+
success = @handler.handle_bridge(network_name)
|
36
|
+
b_result &= success
|
37
|
+
if success
|
38
|
+
# if we have a host ip on that bridge, take it down first
|
39
|
+
b_result &= default_handle_hostip(network_name, network_data, @handler)
|
40
|
+
|
41
|
+
# if we have dhcp, configure dnsmasq
|
42
|
+
b_result &= default_handle_dhcp(zone_name, network_name, network_data, @handler)
|
43
|
+
else
|
44
|
+
$log.debug("Will not touch dependant objects of #{network_name} due to previous error(s)")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# select appgroups in this zone and bring them up
|
49
|
+
appgroups_in_zone = objects_in_zone('appgroups', zone_name)
|
50
|
+
appgroups_in_zone.each do |appgroup_name, appgroup_data|
|
51
|
+
$log.debug("Processing appgroup \'#{appgroup_name}\'")
|
52
|
+
|
53
|
+
success = handler.handle_appgroup(zone_name,
|
54
|
+
appgroup_name, appgroup_data,
|
55
|
+
@project.target_dir)
|
56
|
+
b_result &= success
|
57
|
+
|
58
|
+
# process network attachments
|
59
|
+
zone_networks = objects_in_zone('networks', zone_name)
|
60
|
+
success = handler.handle_network_attachments(zone_name, zone_networks,
|
61
|
+
appgroup_name, appgroup_data,
|
62
|
+
@project.target_dir)
|
63
|
+
b_result &= success
|
64
|
+
end
|
65
|
+
|
66
|
+
b_result
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,193 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
# Wire module
|
8
|
+
module Wire
|
9
|
+
# handle_xxx methods for UpCommand
|
10
|
+
# rubocop:disable ClassLength
|
11
|
+
class UpCommandHandler < BaseCommand
|
12
|
+
# bring bridge resource up, identified by
|
13
|
+
# +bridge_name+
|
14
|
+
# Returns
|
15
|
+
# - [Bool] true if hostip if up on bridge
|
16
|
+
def handle_bridge(bridge_name)
|
17
|
+
b_result = true
|
18
|
+
|
19
|
+
# we should have a bridge with that name.
|
20
|
+
bridge_resource = Wire::Resource::ResourceFactory.instance.create(:ovsbridge, bridge_name)
|
21
|
+
if bridge_resource.up?
|
22
|
+
outputs 'UP', "Bridge #{bridge_name} already up.", :ok2
|
23
|
+
else
|
24
|
+
bridge_resource.up
|
25
|
+
if bridge_resource.up?
|
26
|
+
outputs 'UP', "Bridge #{bridge_name} up.", :ok
|
27
|
+
state.update(:bridge, bridge_name, :up)
|
28
|
+
else
|
29
|
+
outputs 'UP', "Error bringing up bridge #{bridge_name}.", :err
|
30
|
+
b_result = false
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
b_result
|
35
|
+
end
|
36
|
+
|
37
|
+
# bring ip resource up on device identified by
|
38
|
+
# +bridge_name+ and +host_ip+
|
39
|
+
# Returns
|
40
|
+
# - [Bool] true if hostip if up on bridge
|
41
|
+
def handle_hostip(bridge_name, hostip)
|
42
|
+
b_result = true
|
43
|
+
|
44
|
+
# we should have a bridge with that name.
|
45
|
+
hostip_resource = Wire::Resource::ResourceFactory
|
46
|
+
.instance.create(:bridgeip, hostip, bridge_name)
|
47
|
+
if hostip_resource.up?
|
48
|
+
outputs 'UP', "IP #{hostip} on bridge #{bridge_name} already up.", :ok2
|
49
|
+
else
|
50
|
+
hostip_resource.up
|
51
|
+
if hostip_resource.up?
|
52
|
+
outputs 'UP', "IP #{hostip} on bridge #{bridge_name} up.", :ok
|
53
|
+
state.update(:hostip, hostip, :up)
|
54
|
+
else
|
55
|
+
outputs 'UP', "Error bringing up ip #{hostip} on bridge #{bridge_name}.", :err
|
56
|
+
b_result = false
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
b_result
|
61
|
+
end
|
62
|
+
|
63
|
+
# configures dnsmasq for dhcp
|
64
|
+
# +zone_name+ name of zone
|
65
|
+
# +network_name+ name of network (and bridge)
|
66
|
+
# +network+ network entry
|
67
|
+
# +address_start+ start of address range (i.e.192.168.10.10)
|
68
|
+
# +address_end+ end of dhcp address range (i.e.192.168.10.100)
|
69
|
+
# Returns
|
70
|
+
# - [Bool] true if dhcp setup is valid
|
71
|
+
def handle_dhcp(zone_name, network_name, network_entry, address_start, address_end)
|
72
|
+
resource_dhcp = Wire::Resource::ResourceFactory
|
73
|
+
.instance.create(:dhcpconfig, "wire__#{zone_name}", network_name,
|
74
|
+
network_entry, address_start, address_end)
|
75
|
+
if resource_dhcp.up?
|
76
|
+
outputs 'UP', "dnsmasq/dhcp config on network \'#{network_name}\' is already up.", :ok2
|
77
|
+
return true
|
78
|
+
else
|
79
|
+
resource_dhcp.up
|
80
|
+
if resource_dhcp.up?
|
81
|
+
outputs 'UP', "dnsmasq/dhcp config on network \'#{network_name}\' is up.", :ok
|
82
|
+
state.update(:dnsmasq, network_name, :up)
|
83
|
+
return true
|
84
|
+
else
|
85
|
+
outputs 'UP', "Error configuring dnsmasq/dhcp config on network \'#{network_name}\'.",
|
86
|
+
:err
|
87
|
+
return false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# take the appgroups' controller and directs methods to
|
93
|
+
# it. First checks if appgroup is up. If so, ok. If not, bring it up
|
94
|
+
# and ensure that it's up
|
95
|
+
# Params:
|
96
|
+
# +zone_name+:: Name of zone
|
97
|
+
# +appgroup_name+:: Name of Appgroup
|
98
|
+
# +appgroup_entry+:: Appgroup data from model
|
99
|
+
def handle_appgroup(zone_name, appgroup_name, appgroup_entry, target_dir)
|
100
|
+
# get path
|
101
|
+
controller_entry = appgroup_entry[:controller]
|
102
|
+
|
103
|
+
if controller_entry[:type] == 'fig'
|
104
|
+
return handle_appgroup__fig(zone_name, appgroup_name, appgroup_entry, target_dir)
|
105
|
+
end
|
106
|
+
|
107
|
+
$log.error "Appgroup not handled, unknown controller type #{controller_entry[:type]}"
|
108
|
+
false
|
109
|
+
end
|
110
|
+
|
111
|
+
# implement appgroup handling for fig controller
|
112
|
+
# Params:
|
113
|
+
# +zone_name+:: Name of zone
|
114
|
+
# +appgroup_name+:: Name of Appgroup
|
115
|
+
# +appgroup_entry+:: Appgroup data from model
|
116
|
+
# +target_dir+:: Target directory (where fig file is located)
|
117
|
+
def handle_appgroup__fig(zone_name, appgroup_name, appgroup_entry, target_dir)
|
118
|
+
# get path
|
119
|
+
controller_entry = appgroup_entry[:controller]
|
120
|
+
|
121
|
+
fig_path = File.join(File.expand_path(target_dir), controller_entry[:file])
|
122
|
+
|
123
|
+
resource_fig = Wire::Resource::ResourceFactory
|
124
|
+
.instance.create(:figadapter, "#{appgroup_name}", fig_path)
|
125
|
+
|
126
|
+
if resource_fig.up?
|
127
|
+
outputs 'UP', "appgroup \'#{appgroup_name}\' in zone #{zone_name} is already up.", :ok2
|
128
|
+
return true
|
129
|
+
else
|
130
|
+
resource_fig.up
|
131
|
+
if resource_fig.up?
|
132
|
+
outputs 'UP', "appgroup \'#{appgroup_name}\' in zone #{zone_name} is up.", :ok
|
133
|
+
state.update(:appgroup, appgroup_name, :up)
|
134
|
+
return true
|
135
|
+
else
|
136
|
+
outputs 'UP', "Error bringing up appgroup \'#{appgroup_name}\' in zone #{zone_name} .",
|
137
|
+
:err
|
138
|
+
return false
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
# attaches networks to containers of appgroup
|
144
|
+
# Params:
|
145
|
+
# ++_zone_name++: Name of zone
|
146
|
+
# ++networks++: Array of networks names, what to attach
|
147
|
+
# ++appgroup_name++: Name of appgroup
|
148
|
+
# ++appgroup_entry++: appgroup hash
|
149
|
+
# ++target_dir++: project target dir
|
150
|
+
# Returns
|
151
|
+
# - [Bool] true if appgroup setup is ok
|
152
|
+
def handle_network_attachments(_zone_name, networks, appgroup_name,
|
153
|
+
appgroup_entry, target_dir)
|
154
|
+
# query container ids of containers running here
|
155
|
+
# get path
|
156
|
+
controller_entry = appgroup_entry[:controller]
|
157
|
+
|
158
|
+
container_ids = []
|
159
|
+
|
160
|
+
if controller_entry[:type] == 'fig'
|
161
|
+
fig_path = File.join(File.expand_path(target_dir), controller_entry[:file])
|
162
|
+
|
163
|
+
resource_fig = Wire::Resource::ResourceFactory
|
164
|
+
.instance.create(:figadapter, "#{appgroup_name}", fig_path)
|
165
|
+
|
166
|
+
container_ids = resource_fig.up_ids || []
|
167
|
+
$log.debug "Got #{container_ids.size} container id(s) from adapter"
|
168
|
+
end
|
169
|
+
|
170
|
+
#
|
171
|
+
resource_nw = Wire::Resource::ResourceFactory
|
172
|
+
.instance.create(:networkinjection, appgroup_name, networks.keys, container_ids)
|
173
|
+
if resource_nw.up?
|
174
|
+
outputs 'UP', "appgroup \'#{appgroup_name}\' already has valid network " \
|
175
|
+
'attachments.', :ok2
|
176
|
+
state.update(:appgroup, appgroup_name, :up)
|
177
|
+
return true
|
178
|
+
else
|
179
|
+
resource_nw.up
|
180
|
+
if resource_nw.up?
|
181
|
+
outputs 'UP', "appgroup \'#{appgroup_name}\' attached " \
|
182
|
+
"networks #{networks.keys.join(',')}.", :ok
|
183
|
+
state.update(:appgroup, appgroup_name, :up)
|
184
|
+
return true
|
185
|
+
else
|
186
|
+
outputs 'UP', "Error attaching networks to appgroup \'#{appgroup_name}\'.",
|
187
|
+
:err
|
188
|
+
return false
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|