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,80 @@
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
+ # Base class for up/down commands
10
+ class UpDownCommand < BaseCommand
11
+ # generic method, calls run_on_project_zones for
12
+ # all zones in model
13
+ def run_on_project
14
+ zones = @project.get_element('zones')
15
+
16
+ # iterates all zones, descend into zone
17
+ # for further checks, mark all those bad
18
+ # zones, decide upon boolean return flag
19
+ (run_on_project_zones(zones)
20
+ .each do |_zone_name, zone_data|
21
+ # error occured in run_on_zone call. Lets mark this
22
+ zone_data.store :status, :failed
23
+
24
+ end.size > 0)
25
+ end
26
+
27
+ # run on all given +zones+
28
+ # Returns [Hash] of zones that failed.
29
+ def run_on_project_zones(zones)
30
+ zones.select do |zone_name, _|
31
+ $log.debug("Processing zone #{zone_name} ...")
32
+ run_on_zone(zone_name) == false
33
+ end
34
+ end
35
+
36
+ # if dhcp is part of given +network_data+, use
37
+ # +handler+ to process it.
38
+ # +zone_name+:: Name of zone
39
+ # +network_name+:: Name of network
40
+ def default_handle_dhcp(zone_name, network_name, network_data, handler)
41
+ dhcp_data = network_data[:dhcp]
42
+ return true unless dhcp_data
43
+
44
+ $log.debug 'Processing dhcp/dnsmasq ...'
45
+ handler.handle_dhcp(zone_name,
46
+ network_name, network_data,
47
+ dhcp_data[:start], dhcp_data[:end])
48
+ end
49
+
50
+ # if host ip is enabled for given network (+network_name+, +network_data+)
51
+ # use +handler+ to process it
52
+ def default_handle_hostip(network_name, network_data, handler)
53
+ hostip = network_data[:hostip]
54
+ return true unless hostip
55
+
56
+ $log.debug "Processing host ip on network #{network_name} ..."
57
+
58
+ # if the hostip is not in cidr, take netmask
59
+ # from network entry, add to hostip
60
+ hostip = ensure_hostip_netmask(hostip, network_data)
61
+
62
+ # forward to handler
63
+ handler.handle_hostip(network_name, hostip)
64
+ end
65
+
66
+ # returns networks from given +networks+ array that
67
+ # belong to +zone_name+
68
+ # params:
69
+ # +networks+: array of all networks
70
+ # +zone_name+: name of desired zone
71
+ # returns:
72
+ # # => [Array] of networks for given zone
73
+ def self.get_networks_for_zone(networks, zone_name)
74
+ # select networks in given zone only
75
+ networks.select do |_, network_data|
76
+ network_data[:zone] == zone_name
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,64 @@
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
+ # Validate Command reads yaml, parses model elements
10
+ # and runs a number of consistency checks
11
+ class ValidateCommand < BaseCommand
12
+ # array of +errors+
13
+ attr_accessor :errors
14
+
15
+ # array of validations
16
+ attr_accessor :validations
17
+
18
+ # initializes an empty error list
19
+ def initialize
20
+ @errors = []
21
+ @validations = [NetworksValidation, AppGroupValidation]
22
+ end
23
+
24
+ # runs validation on given project
25
+ # returns
26
+ # => list of +errors+
27
+ def run_on_project
28
+ @errors = []
29
+
30
+ # run validations against it
31
+ # TODO: Move validation classes to class level definition
32
+ @validations.each do |val_clazz|
33
+ (@errors << run_validation(@project, val_clazz)).flatten!
34
+ end
35
+
36
+ if @errors.size == 0
37
+ outputs 'VALIDATE', 'OK, model is consistent.', :ok
38
+ else
39
+ outputs 'VALIDATE', 'ERROR, detected inconsistencies:', :error
40
+ @errors.each do |val_error|
41
+ outputs 'VALIDATE', val_error.to_s, :error
42
+ end
43
+ end
44
+
45
+ @errors
46
+ end
47
+
48
+ # run a validation of given +validation_class+ against
49
+ # the model
50
+ #
51
+ # params:
52
+ # +project+:: project model object, to validate
53
+ # +validation_class+:: class object of validation, i.e. NetworksValidation
54
+ #
55
+ # returns:
56
+ # list of errors from validation object
57
+ def run_validation(project, validation_class)
58
+ $log.debug "Running validation class #{validation_class}"
59
+ val_object = validation_class.new(project)
60
+ val_object.run_validations
61
+ val_object.errors
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,196 @@
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
+ # Verify Command reads yaml, parses model elements
10
+ # and checks if given elements are present on the system
11
+ # rubocop:disable ClassLength
12
+ class VerifyCommand < BaseCommand
13
+ # +project+:: to operate upon
14
+ # +findings+:: is an array of potential errors that occured
15
+ # during verification run
16
+ attr_accessor :project, :findings
17
+ # allow to get access to handler object
18
+ attr_reader :handler
19
+
20
+ # set up with empty findings arraay
21
+ def initialize
22
+ @findings = []
23
+ @handler = VerifyCommandHandler.new
24
+ end
25
+
26
+ # add a finding to the findings array
27
+ # params:
28
+ # +msg+:: what went wrong
29
+ # +type+:: element type, i.e. Network
30
+ # +element_name+:: element_name
31
+ # +element_data+:: map of details, from model
32
+ def mark(msg, type, element_name, element_data)
33
+ @findings <<
34
+ VerificationError.new(msg, type,
35
+ element_name, element_data)
36
+ end
37
+
38
+ # run verification on whole project
39
+ # iterates all zones, descend into zone
40
+ # verification
41
+ # returns:
42
+ # - [bool] true = verification ok
43
+ def run_on_project
44
+ zones = @project.get_element('zones')
45
+
46
+ # iterates all zones, descend into zone
47
+ # for further checks, mark all those bad
48
+ # zones, decide upon boolean return flag
49
+ (run_on_project_zones(zones)
50
+ .each do |zone_name, zone_data|
51
+ # error occured in run_on_zone call. Lets mark this
52
+ zone_data.store :status, :failed
53
+ mark("Not all elements of zone \'#{zone_name}\' are valid.",
54
+ :zone, zone_name, zone_data)
55
+ end.size > 0)
56
+ end
57
+
58
+ # run verification on given +zones+
59
+ def run_on_project_zones(zones)
60
+ zones.select do |zone_name, _|
61
+ $log.debug("Verifying zone #{zone_name} ...")
62
+ b_zone_res = run_on_zone(zone_name)
63
+
64
+ if b_zone_res
65
+ outputs 'VERIFY', "Zone \'#{zone_name}\' verified successfully", :ok
66
+ else
67
+ outputs 'VERIFY', "Zone \'#{zone_name}\' NOT verified successfully", :err
68
+ end
69
+
70
+ b_zone_res == false
71
+ end
72
+ end
73
+
74
+ # run verification for given +zone_name+:
75
+ # - check if bridges exist for all networks in
76
+ # this zone
77
+ def run_on_zone(zone_name)
78
+ networks = @project.get_element('networks')
79
+
80
+ b_verify_ok = true
81
+
82
+ # select networks in current zone only
83
+ networks_in_zone = networks.select do |_, network_data|
84
+ network_data[:zone] == zone_name
85
+ end
86
+ # verify these networks
87
+ b_verify_ok = false unless verify_networks(networks_in_zone, zone_name)
88
+
89
+ # select appgroups in this zone and verify them
90
+ appgroups_in_zone = objects_in_zone('appgroups', zone_name)
91
+ b_verify_ok = false unless verify_appgroups(appgroups_in_zone, zone_name)
92
+
93
+ b_verify_ok
94
+ end
95
+
96
+ # given an array of network elements (+networks_in_zone+), this
97
+ # method runs the verification on each network.
98
+ # It checks the availability of a bridge and
99
+ # the optional host ip on that bridge.
100
+ # Params:
101
+ # +networks_in_zone+:: Array of network data elements in desired zone
102
+ # +zone_name+:: Name of zone
103
+ def verify_networks(networks_in_zone, zone_name)
104
+ b_verify_ok = true
105
+ networks_in_zone.each do |network_name, network_data|
106
+ $log.debug("Verifying network \'#{network_name}\'")
107
+
108
+ bridge_name = network_name
109
+
110
+ $log.debug 'checking bridge ...'
111
+ # we should have a bridge with that name.
112
+ if @handler.handle_bridge(bridge_name) == false
113
+ network_data.store :status, :failed
114
+ b_verify_ok = false
115
+ mark("Bridge \'#{bridge_name}\' does not exist.",
116
+ :network, network_name, network_data)
117
+ else
118
+ network_data.store :status, :ok
119
+
120
+ hostip = network_data[:hostip]
121
+ # if we have a host ip, then that bridge should have
122
+ # this ip
123
+ if hostip
124
+ $log.debug 'checking host-ip ...'
125
+
126
+ # if the hostip is not in cidr, take netmask
127
+ # from network entry, add to hostip
128
+ hostip = ensure_hostip_netmask(hostip, network_data)
129
+
130
+ if @handler.handle_hostip(bridge_name, hostip) == false
131
+ network_data.store :status, :failed
132
+ b_verify_ok = false
133
+ mark("Host ip \'#{hostip}\' not up on bridge \'#{bridge_name}\'.",
134
+ :network, network_name, network_data)
135
+ else
136
+ network_data.store :status, :ok
137
+ end
138
+ end
139
+
140
+ # if we have dhcp, check this
141
+ dhcp_data = network_data[:dhcp]
142
+ if dhcp_data
143
+ $log.debug 'checking dhcp ...'
144
+ if @handler.handle_dhcp(zone_name, network_name, network_data,
145
+ dhcp_data[:start],
146
+ dhcp_data[:end]) == false
147
+ network_data.store :status, :failed
148
+ b_verify_ok = false
149
+ mark("dnsmasq/dhcp not configured on network \'#{bridge_name}\'.",
150
+ :network, network_name, network_data)
151
+ else
152
+ network_data.store :status, :ok
153
+ end
154
+ end
155
+ end
156
+ end
157
+ b_verify_ok
158
+ end
159
+
160
+ # Given a +zone_name+ and an array of +appgroups+ entries
161
+ # this methods verifies if these appgroups are up and running
162
+ # It also checks container's network attachments
163
+ def verify_appgroups(appgroups, zone_name)
164
+ b_verify_ok = true
165
+
166
+ appgroups.each do |appgroup_name, appgroup_data|
167
+ $log.debug("Verifying appgroup \'#{appgroup_name}\'")
168
+
169
+ if @handler.handle_appgroup(zone_name, appgroup_name,
170
+ appgroup_data, @project.target_dir) == false
171
+ appgroup_data.store :status, :failed
172
+ b_verify_ok = false
173
+ mark("Appgroup \'#{appgroup_name}\' does not run correctly.",
174
+ :appgroup, appgroup_name, appgroup_data)
175
+ else
176
+ appgroup_data.store :status, :ok
177
+ end
178
+
179
+ next unless b_verify_ok
180
+
181
+ zone_networks = objects_in_zone('networks', zone_name)
182
+ if @handler.handle_network_attachments(zone_name, zone_networks,
183
+ appgroup_name, appgroup_data,
184
+ @project.target_dir) == false
185
+ appgroup_data.store :status, :failed
186
+ b_verify_ok = false
187
+ mark("Appgroup \'#{appgroup_name}\' has missing network attachments",
188
+ :appgroup, appgroup_name, appgroup_data)
189
+ else
190
+ appgroup_data.store :status, :ok
191
+ end
192
+ end
193
+ b_verify_ok
194
+ end
195
+ end
196
+ 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
+ # handle_xxx methods for VerifyCommand
10
+ class VerifyCommandHandler < BaseCommand
11
+ # runs verification for a bridge resource identified by
12
+ # +bridge_name+
13
+ # Returns
14
+ # - [Bool] true if bridge exists
15
+ def handle_bridge(bridge_name)
16
+ bridge_resource = Wire::Resource::ResourceFactory.instance.create(:ovsbridge, bridge_name)
17
+ if bridge_resource.exist?
18
+ outputs 'VERIFY', "Bridge \'#{bridge_name}\' exists.", :ok
19
+ state.update(:bridge, bridge_name, :up)
20
+ return true
21
+ else
22
+ outputs 'VERIFY', "Bridge \'#{bridge_name}\' does not exist.", :err
23
+ state.update(:bridge, bridge_name, :down)
24
+ return false
25
+ end
26
+ end
27
+
28
+ # runs verification for a ip resource identified by
29
+ # +bridge_name+ and +host_ip+
30
+ # Returns
31
+ # - [Bool] true if hostip if up on bridge
32
+ def handle_hostip(bridge_name, hostip)
33
+ hostip_resource = Wire::Resource::ResourceFactory
34
+ .instance.create(:bridgeip, hostip, bridge_name)
35
+ if hostip_resource.up?
36
+ outputs 'VERIFY', "IP \'#{hostip}\' on bridge \'#{bridge_name}\' exists.", :ok
37
+ state.update(:hostip, hostip, :up)
38
+ return true
39
+ else
40
+ outputs 'VERIFY', "IP \'#{hostip}\' on bridge \'#{bridge_name}\' does not exist.", :err
41
+ state.update(:hostip, hostip, :down)
42
+ return false
43
+ end
44
+ end
45
+
46
+ # runs verification for dnsmasqs dhcp resource
47
+ # Returns
48
+ # - [Bool] true if dhcp setup is valid
49
+ def handle_dhcp(zone_name, network_name, network_entry, address_start, address_end)
50
+ resource = Wire::Resource::ResourceFactory
51
+ .instance.create(:dhcpconfig, "wire__#{zone_name}", network_name,
52
+ network_entry, address_start, address_end)
53
+ if resource.up?
54
+ outputs 'VERIFY', "dnsmasq/dhcp config on network \'#{network_name}\' is valid.", :ok
55
+ state.update(:dnsmasq, network_name, :up)
56
+ return true
57
+ else
58
+ outputs 'VERIFY', "dnsmasq/dhcp config on network \'#{network_name}\' is not valid.", :err
59
+ state.update(:dnsmasq, network_name, :down)
60
+ return false
61
+ end
62
+ end
63
+
64
+ # runs verification for appgroups
65
+ # Returns
66
+ # - [Bool] true if appgroup setup is ok
67
+ def handle_appgroup(_zone_name, appgroup_name, appgroup_entry, target_dir)
68
+ # get path
69
+ controller_entry = appgroup_entry[:controller]
70
+
71
+ if controller_entry[:type] == 'fig'
72
+ fig_path = File.join(File.expand_path(target_dir), controller_entry[:file])
73
+
74
+ resource = Wire::Resource::ResourceFactory
75
+ .instance.create(:figadapter, "#{appgroup_name}", fig_path)
76
+ if resource.up?
77
+ outputs 'VERIFY', "appgroup \'#{appgroup_name}\' is running.", :ok
78
+ state.update(:appgroup, appgroup_name, :up)
79
+ return true
80
+ else
81
+ outputs 'VERIFY', "appgroup \'#{appgroup_name}\' is not running.", :err
82
+ state.update(:appgroup, appgroup_name, :down)
83
+ return false
84
+ end
85
+ end
86
+
87
+ $log.error "Appgroup not handled, unknown controller type #{controller_entry[:type]}"
88
+ false
89
+ end
90
+
91
+ # runs verification for container network attachment
92
+ # Params:
93
+ # ++_zone_name++: Name of zone
94
+ # ++networks++: Array of networks names, what to attach
95
+ # ++appgroup_name++: Name of appgroup
96
+ # ++appgroup_entry++: appgroup hash
97
+ # ++target_dir++: project target dir
98
+ # Returns
99
+ # - [Bool] true if appgroup setup is ok
100
+ def handle_network_attachments(_zone_name, networks, appgroup_name,
101
+ appgroup_entry, target_dir)
102
+ # query container ids of containers running here
103
+ # get path
104
+ controller_entry = appgroup_entry[:controller]
105
+
106
+ container_ids = []
107
+
108
+ if controller_entry[:type] == 'fig'
109
+ fig_path = File.join(File.expand_path(target_dir), controller_entry[:file])
110
+
111
+ resource = Wire::Resource::ResourceFactory
112
+ .instance.create(:figadapter, "#{appgroup_name}", fig_path)
113
+
114
+ container_ids = resource.up_ids || []
115
+ $log.debug "Got #{container_ids.size} container id(s) from adapter"
116
+ end
117
+
118
+ #
119
+ resource = Wire::Resource::ResourceFactory
120
+ .instance.create(:networkinjection, appgroup_name, networks.keys, container_ids)
121
+ if resource.up?
122
+ outputs 'VERIFY', "appgroup \'#{appgroup_name}\' has network(s) " \
123
+ "\'#{networks.keys.join(',')}\' attached.", :ok
124
+ state.update(:appgroup, appgroup_name, :up)
125
+ return true
126
+ else
127
+ outputs 'VERIFY', "appgroup \'#{appgroup_name}\' does not have " \
128
+ "all networks \'#{networks.keys.join(',')}\' attached.", :err
129
+ state.update(:appgroup, appgroup_name, :down)
130
+ return false
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ # The MIT License (MIT)
4
+ # Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
5
+ #
6
+
7
+ require_relative 'commands/base_command.rb'
8
+ require_relative 'commands/init_command.rb'
9
+ require_relative 'commands/init_interactive.rb'
10
+ require_relative 'commands/validate_command.rb'
11
+ require_relative 'commands/verify_command.rb'
12
+ require_relative 'commands/verify_command_handler.rb'
13
+ require_relative 'commands/spec_command.rb'
14
+ require_relative 'commands/spec_templates.rb'
15
+ require_relative 'commands/updown_command_base.rb'
16
+ require_relative 'commands/up_command.rb'
17
+ require_relative 'commands/up_command_handler.rb'
18
+ require_relative 'commands/down_command.rb'
19
+ require_relative 'commands/down_command_handler.rb'
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+
3
+ # The MIT License (MIT)
4
+ # Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
5
+ #
6
+
7
+ require 'thor'
8
+
9
+ require 'rainbow'
10
+ require 'rainbow/ext/string'
11
+
12
+ require 'yaml'
13
+ require 'pp'
14
+ require 'English'
15
+ require 'erb'
16
+ require 'tempfile'
17
+
18
+ # set up log object
19
+ require 'logger'
20
+
21
+ $log = Logger.new STDOUT
22
+ # parametrize
23
+ $log.formatter = proc do |severity, _, _, msg|
24
+ "#{severity} #{msg}\n"
25
+ end
26
+ $log.level = Logger::INFO
27
+
28
+ # define exit codes
29
+ module Wire
30
+ # central place for exit codes, given by +id+
31
+ # Params
32
+ # +id+ i.e. :init_bad_input
33
+ # Returns
34
+ # exitcode as [int]
35
+ def self.cli_exitcode(id)
36
+ codes = {
37
+ :init_bad_input => 10,
38
+ :init_dir_error => 20
39
+ }
40
+ codes[id]
41
+ end
42
+ end
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+
3
+ # The MIT License (MIT)
4
+ # Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
5
+ #
6
+
7
+ require 'singleton'
8
+
9
+ # Wire module
10
+ module Wire
11
+ # Execution module for executing commands
12
+ module Execution
13
+ # return singleton object
14
+ def self.global_execution_options
15
+ ExecutionOptions.singleton
16
+ end
17
+
18
+ # Global execution options, such as noop mode etc.
19
+ class ExecutionOptions
20
+ include Singleton
21
+
22
+ # set default execution options
23
+ def initialize
24
+ @options = { :b_noop => false }
25
+ end
26
+
27
+ # returns
28
+ # - [Boolean] true if no_op mode
29
+ def noop?
30
+ @options[:b_noop]
31
+ end
32
+ end
33
+
34
+ # Able to execute commands locally
35
+ # supports sudo and shell wrapping
36
+ class LocalExecution
37
+ # +exitstatus+ the exit status of a command that we ran
38
+ # +stdout+ stdout from command as [String]
39
+ # +stderr+ stderr from command as [String]
40
+ attr_accessor :exitstatus, :stdout, :stderr
41
+
42
+ # params:
43
+ # - command: binary to execute
44
+ # - args: optional cmd line arguments (exec array)
45
+ # - options:
46
+ # - b_shell: if true, run as /bin/sh -c '<command> [args]'
47
+ # - b_sudo: insert sudo if true
48
+ def initialize(command, args = nil, options =
49
+ { :b_shell => true, :b_sudo => true })
50
+ @command = command
51
+ @args = array_or_nil_as_str(args)
52
+ @options = options
53
+ end
54
+
55
+ # block-style. Creates a LocalExecution object with
56
+ # given parameters, yields it into a given block.
57
+ # Params:
58
+ # +command+ Command string, usually the binary
59
+ # +args+ argument array
60
+ # +options+ option map (b_shell, b_sudo flags)
61
+ # Yields
62
+ # - LocalExecution object
63
+ def self.with(command, args = nil, options =
64
+ { :b_shell => true, :b_sudo => true })
65
+ obj = LocalExecution.new command, args, options
66
+ yield obj
67
+ end
68
+
69
+ # constructs the single command line string from
70
+ # given parameters.
71
+ # Returns
72
+ # - Command line as [String]
73
+ def construct_command
74
+ cmd_arr = []
75
+ command_args = "#{@command} #{@args}".strip
76
+ sudo_str = (@options[:b_sudo] ? 'sudo ' : '')
77
+ if @options[:b_shell]
78
+ cmd_arr << '/bin/sh'
79
+ cmd_arr << '-c'
80
+
81
+ cmd_arr << "'#{sudo_str}#{command_args}'"
82
+ else
83
+ cmd_arr << "#{sudo_str}#{command_args}"
84
+ end
85
+
86
+ cmd_arr.join(' ').strip
87
+ end
88
+
89
+ # runs the command
90
+ # sets instance variables
91
+ # stdout, stderr, exitstatus
92
+ def run
93
+ cmd = construct_command
94
+
95
+ $log.debug "Executing #{cmd}"
96
+ @stdout = `#{cmd}`
97
+ @stderr = nil
98
+ @exitstatus = $CHILD_STATUS.exitstatus
99
+ end
100
+
101
+ private
102
+
103
+ # converts given +array_or_nil+ object to identity
104
+ # if array or an empty array if nil
105
+ def array_or_nil_as_str(array_or_nil)
106
+ (array_or_nil || []).join(' ')
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,7 @@
1
+ # encoding: utf-8
2
+
3
+ # The MIT License (MIT)
4
+ # Copyright (c) 2014 Andreas Schmidt, andreas@de-wiring.net
5
+ #
6
+
7
+ require_relative 'execution/local_exec.rb'
@@ -0,0 +1,45 @@
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
+ # Run validations on appgroup model part
10
+ class AppGroupValidation < ValidationBase
11
+ # run validation steps on appgroup elements
12
+ # returns
13
+ # - nil, results in errors of ValidationBase
14
+ def run_validations
15
+ return unless @project.element?('appgroups')
16
+
17
+ appgroups_attached_to_zones?
18
+ controllers_valid?
19
+ end
20
+
21
+ # ensures that all application groups are attached to a zone
22
+ def appgroups_attached_to_zones?
23
+ objects_attached_to_zones? 'appgroups'
24
+ end
25
+
26
+ # ensures that all application groups have a known controller
27
+ def controllers_valid?
28
+ @project.get_element('appgroups').each do |appgroup_name, appgroup_data|
29
+ controller_data = appgroup_data[:controller]
30
+ type = 'appgroup'
31
+ name = appgroup_name
32
+ if !controller_data
33
+ mark('Appgroup is not attached to a zone', type, name)
34
+ else
35
+ type = controller_data[:type]
36
+ mark('Appgroup controller does not have a type', type, name) unless type && type.size > 0
37
+
38
+ known_types = %w(fig)
39
+ mark('Appgroup controller has an unkown type (#{type})',
40
+ type, name) unless known_types.include?(type)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end