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.
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