dewiring 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|