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,135 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
include Wire::Execution
|
8
|
+
|
9
|
+
# Wire module
|
10
|
+
module Wire
|
11
|
+
# Resource module
|
12
|
+
module Resource
|
13
|
+
# DHCPRangeConfiguration is a configuration resource
|
14
|
+
# for dnsmasq to support dhcp for a given network range
|
15
|
+
# on a given interface
|
16
|
+
class DHCPRangeConfiguration < ResourceBase
|
17
|
+
# +network_name+ name of network (and bridge)
|
18
|
+
# +network+ network entry
|
19
|
+
# +address_start+ start of address range (i.e.192.168.10.10)
|
20
|
+
# +address_end+ end of dhcp address range (i.e.192.168.10.100)
|
21
|
+
# +executables+ [Hash] of binaries needed to control
|
22
|
+
# the resource
|
23
|
+
attr_accessor :address_start, :address_end, :network_name, :network, :executables
|
24
|
+
|
25
|
+
# initialize the resourcen object with
|
26
|
+
# given +name+ and attributes
|
27
|
+
# params:
|
28
|
+
# +name+ resource name
|
29
|
+
# +network_name+ name of network (and bridge)
|
30
|
+
# +network+ network entry
|
31
|
+
# +address_start+ start of address range (i.e.192.168.10.10)
|
32
|
+
# +address_end+ end of dhcp address range (i.e.192.168.10.100)
|
33
|
+
def initialize(name, network_name, network, address_start, address_end)
|
34
|
+
super(name)
|
35
|
+
|
36
|
+
self.network_name = network_name
|
37
|
+
self.network = network
|
38
|
+
self.address_start = address_start
|
39
|
+
self.address_end = address_end
|
40
|
+
|
41
|
+
# TODO: make configurable
|
42
|
+
@executables = {
|
43
|
+
:service => '/usr/sbin/service'
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
# Build file name of dnsmasq file
|
48
|
+
# TODO: make configurable
|
49
|
+
def create_dnsmaqs_config_filename
|
50
|
+
"/etc/dnsmasq.d/#{@name}__#{@network_name}.conf"
|
51
|
+
end
|
52
|
+
|
53
|
+
# check if configuration entry exists
|
54
|
+
def exist?
|
55
|
+
filename = create_dnsmaqs_config_filename
|
56
|
+
File.exist?(filename) && File.readable?(filename) && File.file?(filename)
|
57
|
+
end
|
58
|
+
|
59
|
+
# check if dnsmasq is listening on the network device
|
60
|
+
def up?
|
61
|
+
return false unless exist?
|
62
|
+
|
63
|
+
filename = create_dnsmaqs_config_filename
|
64
|
+
|
65
|
+
cmd = "/bin/grep #{network_name} #{filename} >/dev/null 2>&1"
|
66
|
+
$log.debug("executing cmd=#{cmd}")
|
67
|
+
`#{cmd}`
|
68
|
+
|
69
|
+
($CHILD_STATUS == 0)
|
70
|
+
end
|
71
|
+
|
72
|
+
# restart dnsmasq service
|
73
|
+
def restart_dnsmasq
|
74
|
+
$log.debug('Restarting dnsmasq')
|
75
|
+
LocalExecution.with(@executables[:service],
|
76
|
+
%w(dnsmasq restart),
|
77
|
+
{ :b_sudo => true, :b_shell => false }) do |up_exec_obj|
|
78
|
+
up_exec_obj.run
|
79
|
+
return (up_exec_obj.exitstatus == 0)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# creates the configuration and restarts dnsmasq
|
84
|
+
def up
|
85
|
+
filename = create_dnsmaqs_config_filename
|
86
|
+
|
87
|
+
# use sudo'ed touch/chmod to create us the file we need
|
88
|
+
LocalExecution.with("sudo touch #{filename} && " \
|
89
|
+
"sudo chmod u+rw #{filename} && " \
|
90
|
+
"sudo chown #{ENV['USER']} #{filename}",
|
91
|
+
[], { :b_sudo => false, :b_shell => true }) do |up_exec_obj|
|
92
|
+
up_exec_obj.run
|
93
|
+
end
|
94
|
+
$log.debug("(Over-)writing #{filename}")
|
95
|
+
File.open(filename, 'w') do |file|
|
96
|
+
# TODO: add netmask
|
97
|
+
file.puts "dhcp-range=#{@network_name},#{@address_start},#{@address_end}"
|
98
|
+
end
|
99
|
+
|
100
|
+
restart_dnsmasq
|
101
|
+
rescue => exception
|
102
|
+
$log.error("Error writign dnsmasq config file/restarting dnsmasq, #{exception}")
|
103
|
+
return false
|
104
|
+
end
|
105
|
+
|
106
|
+
# checks if dnsmasq is NOT servicing dhcp request on network device
|
107
|
+
def down?
|
108
|
+
!(up?)
|
109
|
+
end
|
110
|
+
|
111
|
+
# removes configuration entry and restarts dnsmasq
|
112
|
+
def down
|
113
|
+
filename = create_dnsmaqs_config_filename
|
114
|
+
if File.exist?(filename) && File.readable?(filename) && File.file?(filename)
|
115
|
+
$log.debug("Deleting #{filename}")
|
116
|
+
LocalExecution.with("sudo rm #{filename}",
|
117
|
+
[], { :b_sudo => false, :b_shell => true }) do |up_exec_obj|
|
118
|
+
up_exec_obj.run
|
119
|
+
end
|
120
|
+
|
121
|
+
restart_dnsmasq
|
122
|
+
end
|
123
|
+
rescue => exception
|
124
|
+
$log.error("Error deleting dnsmasq config file/restarting dnsmasq, #{exception}")
|
125
|
+
return false
|
126
|
+
end
|
127
|
+
|
128
|
+
# Returns a string representation
|
129
|
+
def to_s
|
130
|
+
"DHCPRangeConfiguration:[#{name},network_name=#{network[:name]}" \
|
131
|
+
",start=#{address_start},end=#{address_end}]"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
include Wire::Execution
|
8
|
+
|
9
|
+
# Wire module
|
10
|
+
module Wire
|
11
|
+
# Resource module
|
12
|
+
module Resource
|
13
|
+
# Fig Adapter resource, runs fig script
|
14
|
+
# to control containers
|
15
|
+
class FigAdapter < ResourceBase
|
16
|
+
# +executables+ [Hash] of binaries needed to control
|
17
|
+
# the resource
|
18
|
+
attr_accessor :figfile, :executables
|
19
|
+
|
20
|
+
# initialize the object with
|
21
|
+
# given +name+ and path to fig file
|
22
|
+
# params:
|
23
|
+
# - name fig filename name, i.e. "backend.yaml"
|
24
|
+
def initialize(name, figfile)
|
25
|
+
super(name.tr('_-', ''))
|
26
|
+
@figfile = figfile
|
27
|
+
|
28
|
+
# TODO: make configurable
|
29
|
+
@executables = {
|
30
|
+
:fig => '/usr/local/bin/fig'
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
# checks if containers exist
|
35
|
+
def exist?
|
36
|
+
up?
|
37
|
+
end
|
38
|
+
|
39
|
+
# calls fig with correct -p and -f options
|
40
|
+
# and given +command_arr+ array
|
41
|
+
def with_fig(command_arr)
|
42
|
+
LocalExecution.with(@executables[:fig],
|
43
|
+
['-p', @name, '-f', @figfile, command_arr].flatten) do |exec_obj|
|
44
|
+
yield exec_obj
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# checks if containers are up (using fig ps)
|
49
|
+
def up?
|
50
|
+
with_fig(%w(ps)) do |exec_obj|
|
51
|
+
exec_obj.run
|
52
|
+
|
53
|
+
# parse stdout..
|
54
|
+
re = Regexp.new "^#{@name}.*Up.*"
|
55
|
+
num_up = 0
|
56
|
+
exec_obj.stdout.split("\n").each do |line|
|
57
|
+
next unless line.match(re)
|
58
|
+
|
59
|
+
$log.debug "Matching fig ps output: #{line}"
|
60
|
+
|
61
|
+
num_up += 1
|
62
|
+
end
|
63
|
+
$log.debug 'No containers found in fig ps output' if num_up == 0
|
64
|
+
|
65
|
+
return (exec_obj.exitstatus == 0 && num_up > 0)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# returns the container ids of currently running containers
|
70
|
+
# as [Array] of ids
|
71
|
+
def up_ids
|
72
|
+
with_fig(%w(ps -q)) do |exec_obj|
|
73
|
+
exec_obj.run
|
74
|
+
|
75
|
+
# parse stdout..
|
76
|
+
re = Regexp.new '^[0-9a-zA-Z]+'
|
77
|
+
res = []
|
78
|
+
|
79
|
+
exec_obj.stdout.split("\n").each do |line|
|
80
|
+
next unless line.match(re)
|
81
|
+
res << line.chomp.strip
|
82
|
+
end
|
83
|
+
|
84
|
+
return res
|
85
|
+
end
|
86
|
+
nil
|
87
|
+
end
|
88
|
+
|
89
|
+
# brings containers up
|
90
|
+
def up
|
91
|
+
$log.debug 'Bringing up fig containers ...'
|
92
|
+
with_fig(%w(up -d --no-recreate)) do |exec_obj|
|
93
|
+
exec_obj.run
|
94
|
+
|
95
|
+
return (exec_obj.exitstatus == 0)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# checks if the bridge is down
|
100
|
+
def down?
|
101
|
+
!(up?)
|
102
|
+
end
|
103
|
+
|
104
|
+
# takes containers down
|
105
|
+
def down
|
106
|
+
$log.debug 'Taking down fig containers ...'
|
107
|
+
with_fig(['stop']) do |exec_obj|
|
108
|
+
exec_obj.run
|
109
|
+
|
110
|
+
return false if (exec_obj.exitstatus != 0)
|
111
|
+
end
|
112
|
+
$log.debug 'Removing fig containers ...'
|
113
|
+
with_fig(%w(rm --force)) do |exec_obj|
|
114
|
+
exec_obj.run
|
115
|
+
|
116
|
+
return false if (exec_obj.exitstatus != 0)
|
117
|
+
end
|
118
|
+
true
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns a string representation
|
122
|
+
def to_s
|
123
|
+
"FigAdapter:[#{name},file=#{figfile}]"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,141 @@
|
|
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
|
+
# Resource module
|
10
|
+
module Resource
|
11
|
+
# IPBinary class wraps /sbin/ip and
|
12
|
+
# is able to parse the output and pass it
|
13
|
+
# on in a resource style
|
14
|
+
class IPBinary < ResourceBase
|
15
|
+
# sets the executables map
|
16
|
+
def initialize
|
17
|
+
super('undefined')
|
18
|
+
@executables = {
|
19
|
+
:ip => '/sbin/ip'
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
# call ip addr show and returns details
|
24
|
+
# as a map
|
25
|
+
# params:
|
26
|
+
# +device+ device (i.e. bridge0 to operate on)
|
27
|
+
# returns:
|
28
|
+
# - detail data of device as a map
|
29
|
+
def get_ipaddr_data(device)
|
30
|
+
fail(ArgumentError, 'Device name not given') unless device && device.size > 0
|
31
|
+
|
32
|
+
result = {}
|
33
|
+
stdout = call_addr_show(device)
|
34
|
+
|
35
|
+
# parse line-wise. first line is about the device
|
36
|
+
arr_lines = stdout.split("\n")
|
37
|
+
|
38
|
+
if !arr_lines || arr_lines.size == 0
|
39
|
+
fail("No output from #{@executables[:ip]} on dev #{device}")
|
40
|
+
end
|
41
|
+
result.merge!(get_ipaddr_data_device(arr_lines[0]))
|
42
|
+
result.merge!(get_ipaddr_data_link(arr_lines[0]))
|
43
|
+
|
44
|
+
# iterate all inet lines
|
45
|
+
parse_inet_lines(arr_lines, result)
|
46
|
+
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
# given the array of output lines (+arr_lines+)from ip binary call,
|
51
|
+
# this method parses the lines and adds structured detail
|
52
|
+
# data to +result+ map
|
53
|
+
def parse_inet_lines(arr_lines, result)
|
54
|
+
inet_map = {}
|
55
|
+
arr_lines[1..-1].select { |line| line =~ /inet / }.each do |line|
|
56
|
+
inet_result = get_ipaddr_data_inet(line)
|
57
|
+
inet_map.store inet_result[:device], inet_result
|
58
|
+
end
|
59
|
+
result.store(:inet, inet_map)
|
60
|
+
end
|
61
|
+
|
62
|
+
# calls /sbin/ip addr show <device>
|
63
|
+
# for given device name
|
64
|
+
def call_addr_show(device)
|
65
|
+
LocalExecution.with(@executables[:ip],
|
66
|
+
['addr', 'show', device]) do |up_exec_obj|
|
67
|
+
up_exec_obj.run
|
68
|
+
fail "Error on execution of #{@executables[:ip]}, " \
|
69
|
+
"exitcode=#{up_exec_obj.exitstatus}" unless up_exec_obj.exitstatus == 0
|
70
|
+
return up_exec_obj.stdout
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# runs a set of +matchers+ against given +line+ string,
|
75
|
+
# returns results
|
76
|
+
# params:
|
77
|
+
# +line+: line from command output
|
78
|
+
# +matchers+: map of regexps
|
79
|
+
# returns:
|
80
|
+
# - [HashMap] with keys identical to +matchers+ map
|
81
|
+
def generic_match_data(line, matchers)
|
82
|
+
result = {}
|
83
|
+
|
84
|
+
matchers.each do |key, regexp|
|
85
|
+
md = line.match regexp
|
86
|
+
result.store(key, md[1]) if md && md.size > 1
|
87
|
+
end
|
88
|
+
|
89
|
+
result
|
90
|
+
end
|
91
|
+
|
92
|
+
# retrieve device data from input
|
93
|
+
# params:
|
94
|
+
# +line+: input line from /sbin/ip addr show w/ device data
|
95
|
+
# returns:
|
96
|
+
# [HashMap] with id, devicename, options, mtu, state and group details
|
97
|
+
def get_ipaddr_data_device(line)
|
98
|
+
device_matchers = {
|
99
|
+
:id => /^([0-9]+):/,
|
100
|
+
:device => /^[0-9]+: (\w+): /,
|
101
|
+
:options => /^[0-9]+: \w+: <([\w,_]+)> /,
|
102
|
+
:mtu => /mtu (\w+)/,
|
103
|
+
:state => /state (\w+)/,
|
104
|
+
:group => /group (\w+)/
|
105
|
+
}
|
106
|
+
generic_match_data(line, device_matchers)
|
107
|
+
end
|
108
|
+
|
109
|
+
# retrieve link state data from input
|
110
|
+
# params:
|
111
|
+
# +line+: input line from /sbin/ip addr show w/ link data
|
112
|
+
# returns:
|
113
|
+
# [HashMap] with type, mac address and (optional) broadcast
|
114
|
+
def get_ipaddr_data_link(line)
|
115
|
+
link_matchers = {
|
116
|
+
:type => /link\/(\w+) /,
|
117
|
+
:mac => /link\/\w+ ([0-9:]+)/,
|
118
|
+
:brd => /brd ([0-9:]+)/
|
119
|
+
}
|
120
|
+
generic_match_data(line, link_matchers)
|
121
|
+
end
|
122
|
+
|
123
|
+
# retrieve inet state data from input
|
124
|
+
# params:
|
125
|
+
# +line+: input line from /sbin/ip addr show w/ "inet" data
|
126
|
+
# returns:
|
127
|
+
# [HashMap] with ip, broadcast, scope, device
|
128
|
+
def get_ipaddr_data_inet(line)
|
129
|
+
inet_matchers = {
|
130
|
+
:ip => /inet ([0-9\.]+)\//,
|
131
|
+
:cidr => /inet ([0-9\.\/]+) /,
|
132
|
+
:network => /inet [0-9\.]+(\/[0-9]+) /,
|
133
|
+
:brd => /brd ([0-9\.]+)/,
|
134
|
+
:scope => /scope (\w+)/,
|
135
|
+
:device => / ([\w:]+)$/
|
136
|
+
}
|
137
|
+
generic_match_data(line, inet_matchers)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
require 'ipaddr'
|
8
|
+
|
9
|
+
# reopen class to add needed methods
|
10
|
+
# for IP/subnetwork stuff
|
11
|
+
class IPAddr
|
12
|
+
# TODO: check if needed
|
13
|
+
# attr_reader :netmask_address
|
14
|
+
|
15
|
+
# compute broadcast address
|
16
|
+
def broadcast_address
|
17
|
+
_to_string(@addr | (2**32 - 1) - (@mask_addr))
|
18
|
+
end
|
19
|
+
|
20
|
+
# checks if self is within network range
|
21
|
+
# of given +network+ (IPAddr object)
|
22
|
+
# i.e. 10.10.2.0/24 is part of 10.10.0.0/16
|
23
|
+
# params:
|
24
|
+
# +network+ i.e. 10.10.0.0/16, if self == 10.10.2.0/24
|
25
|
+
# returns
|
26
|
+
# [bool]
|
27
|
+
def in_range_of?(network)
|
28
|
+
return false unless network.include?(self)
|
29
|
+
return false unless
|
30
|
+
network.include?(IPAddr.new(broadcast_address))
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
# return netmask as a string
|
35
|
+
def netmask
|
36
|
+
_to_string(@mask_addr)
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
include Wire::Execution
|
8
|
+
|
9
|
+
# Wire module
|
10
|
+
module Wire
|
11
|
+
# Resource module
|
12
|
+
module Resource
|
13
|
+
# Generic IP Address on an interface
|
14
|
+
# Able to add and remove ips on interfaces
|
15
|
+
class IPAddressOnIntf < ResourceBase
|
16
|
+
# +device+ (bridge) device name, i.e. "eth1"
|
17
|
+
# +executables+ array of paths to needed binaries
|
18
|
+
attr_accessor :device, :executables
|
19
|
+
|
20
|
+
# initialize the object with
|
21
|
+
# given name and device
|
22
|
+
# params:
|
23
|
+
# +name+ ip address in cidr notation
|
24
|
+
# +device+ device/interface name
|
25
|
+
def initialize(name, device)
|
26
|
+
super(name)
|
27
|
+
|
28
|
+
fail(ArgumentError, 'ip may not be empty') unless name && name.size > 0
|
29
|
+
fail(ArgumentError, 'device may not be empty') unless device && device.size > 0
|
30
|
+
|
31
|
+
@device = device
|
32
|
+
@executables = {
|
33
|
+
:ip => '/sbin/ip'
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
# constructs an ip addr show / grep command to see if an
|
38
|
+
# ip address is up on a device
|
39
|
+
# returns
|
40
|
+
# - command as [String]
|
41
|
+
def construct_exist_command
|
42
|
+
"#{@executables[:ip]} addr show #{device} | grep -wq -E \"^\\W*inet #{@name}.*#{@device}\""
|
43
|
+
end
|
44
|
+
|
45
|
+
# runs the "exist" command
|
46
|
+
# returns
|
47
|
+
# - [Boolean]: true: ip is on on device, false otherwise
|
48
|
+
def exist?
|
49
|
+
LocalExecution.with(construct_exist_command, [],
|
50
|
+
{ :b_shell => false, :b_sudo => false }) do |exec_obj|
|
51
|
+
exec_obj.run
|
52
|
+
return (exec_obj.exitstatus == 0)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# same as exist?
|
57
|
+
def up?
|
58
|
+
exist?
|
59
|
+
end
|
60
|
+
|
61
|
+
# constructs an ip addr add command to set up an ip
|
62
|
+
# returns
|
63
|
+
# - command as [String]
|
64
|
+
def construct_add_command
|
65
|
+
"#{@executables[:ip]} addr add #{name} dev #{device}"
|
66
|
+
end
|
67
|
+
|
68
|
+
# takes an ip up on given device
|
69
|
+
# returns
|
70
|
+
# - [Boolean]: true: ok, false otherwise
|
71
|
+
def up
|
72
|
+
LocalExecution.with(construct_add_command, [],
|
73
|
+
{ :b_shell => false, :b_sudo => true }) do |exec_obj|
|
74
|
+
exec_obj.run
|
75
|
+
return (exec_obj.exitstatus == 0)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# constructs an ip addr del command to delete an ip
|
80
|
+
# returns
|
81
|
+
# - command as [String]
|
82
|
+
def construct_delete_command
|
83
|
+
"#{@executables[:ip]} addr del #{name} dev #{device}"
|
84
|
+
end
|
85
|
+
|
86
|
+
# thats the opposite of up
|
87
|
+
def down?
|
88
|
+
!(up?)
|
89
|
+
end
|
90
|
+
|
91
|
+
# takes an ip down on given device
|
92
|
+
# returns
|
93
|
+
# - [Boolean]: true: ok, false otherwise
|
94
|
+
def down
|
95
|
+
LocalExecution.with(construct_delete_command, [],
|
96
|
+
{ :b_shell => false, :b_sudo => true }) do |exec_obj|
|
97
|
+
exec_obj.run
|
98
|
+
return (exec_obj.exitstatus == 0)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
# generate a string representation
|
103
|
+
def to_s
|
104
|
+
"IPAddressOnIntf:[#{name},device=#{device}]"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
# The MIT License (MIT)
|
4
|
+
# Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
|
5
|
+
#
|
6
|
+
|
7
|
+
include Wire::Execution
|
8
|
+
|
9
|
+
# Wire module
|
10
|
+
module Wire
|
11
|
+
# Resource module
|
12
|
+
module Resource
|
13
|
+
# Network Injection Resource controls the allocation
|
14
|
+
# of host and container network resources for
|
15
|
+
# all containers of an application group
|
16
|
+
class NetworkInjection < ResourceBase
|
17
|
+
# +executables+ [Hash] of binaries needed to control
|
18
|
+
# the resource
|
19
|
+
attr_accessor :executables
|
20
|
+
|
21
|
+
# ids of containers of appgroup
|
22
|
+
attr_accessor :containers
|
23
|
+
|
24
|
+
# names of networks to attach appgroup containers to
|
25
|
+
attr_accessor :networks
|
26
|
+
|
27
|
+
# initialize the object with
|
28
|
+
# given appgroup +name+ and +container+ ids
|
29
|
+
# params:
|
30
|
+
# ++name++: Application group name
|
31
|
+
# ++networks++: [Array] of network names to attach containers to
|
32
|
+
# ++containers+: [Array] of container ids (i.e. from fig ps -q)
|
33
|
+
def initialize(name, networks, containers)
|
34
|
+
super(name)
|
35
|
+
self.containers = containers
|
36
|
+
self.networks = networks
|
37
|
+
|
38
|
+
# TODO: make configurable
|
39
|
+
@executables = {
|
40
|
+
:network => '/usr/local/bin/wire-network-container.sh'
|
41
|
+
}
|
42
|
+
end
|
43
|
+
|
44
|
+
# calls helper executable with correct +action+
|
45
|
+
# and given +command_arr+ array
|
46
|
+
def with_helper(action, params)
|
47
|
+
# puts "#{@executables[:network]} #{action} --debug -- #{params.join(' ')}"
|
48
|
+
LocalExecution.with(@executables[:network],
|
49
|
+
[action, '--debug', '--', params].flatten,
|
50
|
+
{ :b_sudo => false, :b_shell => false }) do |exec_obj|
|
51
|
+
yield exec_obj
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# calls the verify action to see if container
|
56
|
+
# has been networked correctly
|
57
|
+
def exist?
|
58
|
+
up?
|
59
|
+
end
|
60
|
+
|
61
|
+
# for the network helper script, construct
|
62
|
+
# an array of container devices names and bridge names,
|
63
|
+
# i.e. eht1:br0 meaning container will be attached
|
64
|
+
# to bridge br0 with eth1.
|
65
|
+
# first iteration: choose device=network_name=bridge_name,
|
66
|
+
# all the same.
|
67
|
+
def construct_helper_params
|
68
|
+
res = []
|
69
|
+
networks.each do |network|
|
70
|
+
res << "#{network}:#{network}"
|
71
|
+
end
|
72
|
+
res.join(' ')
|
73
|
+
end
|
74
|
+
|
75
|
+
# same as exist?
|
76
|
+
def up?
|
77
|
+
with_helper('verify', [construct_helper_params,
|
78
|
+
containers.join(' ')]) do |exec_obj|
|
79
|
+
exec_obj.run
|
80
|
+
|
81
|
+
return (exec_obj.exitstatus == 0 && count_errors(exec_obj) == 0)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# attaches containers to networks
|
86
|
+
def up
|
87
|
+
$log.debug 'Attaching containers to networks ...'
|
88
|
+
with_helper('attach', [construct_helper_params,
|
89
|
+
containers.join(' ')]) do |exec_obj|
|
90
|
+
exec_obj.run
|
91
|
+
|
92
|
+
return (exec_obj.exitstatus == 0 && count_errors(exec_obj) == 0)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# checks if the bridge is down
|
97
|
+
def down?
|
98
|
+
!(up?)
|
99
|
+
end
|
100
|
+
|
101
|
+
# detaches network interfaces form containers and bridges
|
102
|
+
def down
|
103
|
+
$log.debug 'Taking down container network attachments ...'
|
104
|
+
with_helper('detach', [construct_helper_params,
|
105
|
+
containers.join(' ')]) do |exec_obj|
|
106
|
+
exec_obj.run
|
107
|
+
|
108
|
+
return (exec_obj.exitstatus == 0 && count_errors(exec_obj) == 0)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns a string representation
|
113
|
+
def to_s
|
114
|
+
"NetworkInjection:[#{name},containers=#{containers.join('/')}," \
|
115
|
+
"network_args=#{construct_helper_params}]"
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# counts errors in a text output from given
|
121
|
+
# +exec_obj+
|
122
|
+
def count_errors(exec_obj)
|
123
|
+
num_errors = 0
|
124
|
+
re = Regexp.new '^ERROR.*'
|
125
|
+
exec_obj.stdout.split("\n").each do |line|
|
126
|
+
$log.debug line
|
127
|
+
|
128
|
+
next unless line.match(re)
|
129
|
+
|
130
|
+
$log.debug "Matching error output: #{line}"
|
131
|
+
|
132
|
+
num_errors += 1
|
133
|
+
end
|
134
|
+
num_errors
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|