dewiring 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +15 -0
  2. data/bin/wire +7 -0
  3. data/bin/wire-network-container.sh +547 -0
  4. data/lib/test_fig.rb +46 -0
  5. data/lib/wire/cli/cli_commands.rb +88 -0
  6. data/lib/wire/cli/main_cli.rb +129 -0
  7. data/lib/wire/cli.rb +8 -0
  8. data/lib/wire/commands/base_command.rb +139 -0
  9. data/lib/wire/commands/down_command.rb +69 -0
  10. data/lib/wire/commands/down_command_handler.rb +199 -0
  11. data/lib/wire/commands/init_command.rb +89 -0
  12. data/lib/wire/commands/init_interactive.rb +75 -0
  13. data/lib/wire/commands/spec_command.rb +240 -0
  14. data/lib/wire/commands/spec_templates.rb +134 -0
  15. data/lib/wire/commands/up_command.rb +69 -0
  16. data/lib/wire/commands/up_command_handler.rb +193 -0
  17. data/lib/wire/commands/updown_command_base.rb +80 -0
  18. data/lib/wire/commands/validate_command.rb +64 -0
  19. data/lib/wire/commands/verify_command.rb +196 -0
  20. data/lib/wire/commands/verify_command_handler.rb +134 -0
  21. data/lib/wire/commands.rb +19 -0
  22. data/lib/wire/common.rb +42 -0
  23. data/lib/wire/execution/local_exec.rb +110 -0
  24. data/lib/wire/execution.rb +7 -0
  25. data/lib/wire/model/appgroup_validation.rb +45 -0
  26. data/lib/wire/model/loader.rb +49 -0
  27. data/lib/wire/model/network_validation.rb +111 -0
  28. data/lib/wire/model/project.rb +64 -0
  29. data/lib/wire/model/state.rb +154 -0
  30. data/lib/wire/model/validation.rb +66 -0
  31. data/lib/wire/model/verification.rb +37 -0
  32. data/lib/wire/model.rb +13 -0
  33. data/lib/wire/resource/bridge.rb +76 -0
  34. data/lib/wire/resource/dhcp_range_config.rb +135 -0
  35. data/lib/wire/resource/fig_adapter.rb +127 -0
  36. data/lib/wire/resource/ip_binary.rb +141 -0
  37. data/lib/wire/resource/ipaddr_ext.rb +38 -0
  38. data/lib/wire/resource/ipaddr_on_intf.rb +108 -0
  39. data/lib/wire/resource/network_injection.rb +138 -0
  40. data/lib/wire/resource/resource.rb +52 -0
  41. data/lib/wire/resource.rb +14 -0
  42. data/lib/wire/version.rb +14 -0
  43. data/lib/wire.rb +24 -0
  44. 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