akaer 1.5.8 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis-gemfile +13 -0
- data/.travis.yml +6 -4
- data/Gemfile +12 -1
- data/README.md +7 -4
- data/Rakefile +2 -9
- data/akaer.gemspec +5 -10
- data/bin/akaer +19 -17
- data/doc/Akaer/Application.html +1186 -860
- data/doc/Akaer/ApplicationMethods/General.html +365 -0
- data/doc/Akaer/ApplicationMethods/System.html +456 -0
- data/doc/Akaer/{Errors.html → ApplicationMethods.html} +21 -11
- data/doc/Akaer/Configuration.html +3 -3
- data/doc/Akaer/Version.html +6 -6
- data/doc/Akaer.html +6 -6
- data/doc/_index.html +41 -4
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +53 -42
- data/doc/frames.html +1 -1
- data/doc/index.html +53 -42
- data/doc/method_list.html +30 -22
- data/doc/top-level-namespace.html +3 -3
- data/lib/akaer/application.rb +323 -199
- data/lib/akaer/configuration.rb +13 -13
- data/lib/akaer/version.rb +4 -4
- data/lib/akaer.rb +2 -1
- data/locales/en.yml +52 -0
- data/locales/it.yml +52 -0
- data/spec/akaer/application_spec.rb +25 -25
- data/spec/akaer/configuration_spec.rb +3 -3
- data/spec/coverage_helper.rb +6 -9
- data/spec/spec_helper.rb +1 -2
- metadata +18 -115
- data/doc/Akaer/Errors/InvalidConfiguration.html +0 -123
- data/doc/Akaer/Logger.html +0 -596
- data/doc/Fixnum.html +0 -200
data/lib/akaer/application.rb
CHANGED
@@ -1,69 +1,302 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
#
|
3
|
-
# This file is part of the akaer gem. Copyright (C)
|
3
|
+
# This file is part of the akaer gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
4
|
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
5
|
#
|
6
6
|
|
7
7
|
# A small utility to add aliases to network interfaces.
|
8
8
|
module Akaer
|
9
|
+
# Methods for the {Application Application} class.
|
10
|
+
module ApplicationMethods
|
11
|
+
# General methods.
|
12
|
+
module General
|
13
|
+
extend ActiveSupport::Concern
|
14
|
+
|
15
|
+
# Checks if we are running on MacOS X.
|
16
|
+
#
|
17
|
+
# System services are only available on that platform.
|
18
|
+
#
|
19
|
+
# @return [Boolean] `true` if the current platform is MacOS X, `false` otherwise.
|
20
|
+
def is_osx?
|
21
|
+
::RbConfig::CONFIG['host_os'] =~ /^darwin/
|
22
|
+
end
|
23
|
+
|
24
|
+
# Adds or removes an alias from the interface.
|
25
|
+
#
|
26
|
+
# @param type [Symbol] The operation to execute. Can be `:add` or `:remove`.
|
27
|
+
# @param address [String] The address to manage.
|
28
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
29
|
+
def manage(type, address)
|
30
|
+
locale = self.i18n
|
31
|
+
config = self.config
|
32
|
+
quiet = config.quiet
|
33
|
+
rv, command, prefix = setup_management(type, address)
|
34
|
+
|
35
|
+
# Now execute
|
36
|
+
if rv then
|
37
|
+
if !config.dry_run then
|
38
|
+
execute_manage(command, prefix, type, address, config, quiet)
|
39
|
+
else
|
40
|
+
log_management(:dry_run, prefix, type, locale.remove, locale.add, address, config, quiet)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
rv
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
# Setups management.
|
49
|
+
#
|
50
|
+
# @param type [Symbol] The type of operation. Can be `:add` or `:remove`.
|
51
|
+
# @param address [String] The address to manage.
|
52
|
+
# @return [Array] A list of parameters for the management.
|
53
|
+
def setup_management(type, address)
|
54
|
+
begin
|
55
|
+
@addresses ||= self.compute_addresses
|
56
|
+
length = self.pad_number(@addresses.length)
|
57
|
+
[true, Mustache.render(config.send((type == :remove) ? :remove_command : :add_command), {interface: config.interface, alias: address}) + " > /dev/null 2>&1", "{mark=blue}[{mark=bright white}#{self.pad_number((@addresses.index(address) || 0) + 1, length.length)}{mark=reset blue}/{/mark}#{length}{/mark}]{/mark}"]
|
58
|
+
rescue ArgumentError
|
59
|
+
[false]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
# Executes management.
|
64
|
+
#
|
65
|
+
# @param command [String] The command to execute.
|
66
|
+
# @param prefix [String] The prefix to apply to the message.
|
67
|
+
# @param type [Symbol] The type of operation. Can be `:add` or `:remove`.
|
68
|
+
# @param address [String] The address that will be managed.
|
69
|
+
# @param config [Configuration] The current configuration.
|
70
|
+
# @param quiet [Boolean] Whether to show the message.
|
71
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
72
|
+
def execute_manage(command, prefix, type, address, config, quiet)
|
73
|
+
locale = self.i18n
|
74
|
+
log_management(:run, prefix, type, locale.removing, locale.adding, address, config, quiet)
|
75
|
+
rv = self.execute_command(command)
|
76
|
+
labels = (type == :remove ? [locale.remove, locale.from] : [locale.add, locale.to])
|
77
|
+
@logger.error(@command.application.console.replace_markers(locale.general_error(labels[0], address, labels[1], config.interface))) if !rv
|
78
|
+
rv
|
79
|
+
end
|
80
|
+
|
81
|
+
# Logs an operation.
|
82
|
+
#
|
83
|
+
# @param message [Symbol] The message to print.
|
84
|
+
# @param prefix [String] The prefix to apply to the message.
|
85
|
+
# @param type [Symbol] The type of operation. Can be `:add` or `:remove`.
|
86
|
+
# @param remove_label [String] The label to use for removing.
|
87
|
+
# @param add_label [String] The label to use for adding.
|
88
|
+
# @param address [String] The address that will be managed.
|
89
|
+
# @param config [Configuration] The current configuration.
|
90
|
+
# @param quiet [Boolean] Whether to show the message.
|
91
|
+
def log_management(message, prefix, type, remove_label, add_label, address, config, quiet)
|
92
|
+
locale = self.i18n
|
93
|
+
labels = (type == :remove ? [remove_label, locale.from] : [add_label, locale.to])
|
94
|
+
@logger.info(@command.application.console.replace_markers(self.i18n.send(message, prefix, labels[0], address, labels[1], config.interface))) if !quiet
|
95
|
+
end
|
96
|
+
|
97
|
+
# Manages an action on the request addresses.
|
98
|
+
#
|
99
|
+
# @param operation [Symbol] The type of operation. Can be `:add` or `:remove`.
|
100
|
+
# @param message [String] The message to show if no addresses are found.
|
101
|
+
# @param quiet [Boolean] Whether to show the failure message.
|
102
|
+
def manage_action(operation, message, quiet)
|
103
|
+
addresses = self.compute_addresses
|
104
|
+
|
105
|
+
if addresses.present? then
|
106
|
+
# Now, for every address, call the command
|
107
|
+
addresses.all? {|address|
|
108
|
+
self.manage(operation, address)
|
109
|
+
}
|
110
|
+
else
|
111
|
+
@logger.error(message) if !quiet
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# System management methods.
|
117
|
+
module System
|
118
|
+
# Adds aliases to the interface.
|
119
|
+
#
|
120
|
+
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
121
|
+
def action_add
|
122
|
+
manage_action(:add, self.i18n.add_empty, self.config.quiet)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Removes aliases from the interface.
|
126
|
+
#
|
127
|
+
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
128
|
+
def action_remove
|
129
|
+
manage_action(:remove, self.i18n.remove_empty, self.config.quiet)
|
130
|
+
end
|
131
|
+
|
132
|
+
# Installs the application into the autolaunch.
|
133
|
+
#
|
134
|
+
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
135
|
+
def action_install
|
136
|
+
manage_agent(self.launch_agent_path, :create_agent, :load_agent, self.config.quiet)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Uninstalls the application from the autolaunch.
|
140
|
+
#
|
141
|
+
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
142
|
+
def action_uninstall
|
143
|
+
manage_agent(self.launch_agent_path, :unload_agent, :delete_agent, self.config.quiet)
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
# Manages a OSX agent.
|
148
|
+
#
|
149
|
+
# @param launch_agent [String] The agent path.
|
150
|
+
# @param first_operation [Symbol] The first operation to execute.
|
151
|
+
# @param second_operation [Symbol] The second operation to execute.
|
152
|
+
# @param quiet [Boolean] Whether to show messages.
|
153
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
154
|
+
def manage_agent(launch_agent, first_operation, second_operation, quiet)
|
155
|
+
rv = true
|
156
|
+
|
157
|
+
rv = check_agent_available(quiet)
|
158
|
+
rv = send(first_operation, launch_agent, quiet) if rv
|
159
|
+
rv = send(second_operation, launch_agent, quiet) if rv
|
160
|
+
rv
|
161
|
+
end
|
162
|
+
|
163
|
+
# Checks if agent is enabled (that is, we are on OSX).
|
164
|
+
#
|
165
|
+
# @param quiet [Boolean] Whether to show messages.
|
166
|
+
# @return [Boolean] `true` if the agent is enabled, `false` otherwise.
|
167
|
+
def check_agent_available(quiet)
|
168
|
+
rv = true
|
169
|
+
if !self.is_osx? then
|
170
|
+
logger.fatal(self.i18n.no_agent) if !quiet
|
171
|
+
rv = false
|
172
|
+
end
|
173
|
+
|
174
|
+
rv
|
175
|
+
end
|
176
|
+
|
177
|
+
# Creates a OSX system agent.
|
178
|
+
#
|
179
|
+
# @param launch_agent [String] The agent path.
|
180
|
+
# @param quiet [Boolean] Whether to show messages.
|
181
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
182
|
+
def create_agent(launch_agent, quiet)
|
183
|
+
begin
|
184
|
+
self.logger.info(self.i18n.agent_creating(launch_agent)) if !quiet
|
185
|
+
write_agent(launch_agent)
|
186
|
+
self.execute_command("plutil -convert binary1 \"#{launch_agent}\"")
|
187
|
+
true
|
188
|
+
rescue
|
189
|
+
self.logger.error(self.i18n.agent_creating_error) if !quiet
|
190
|
+
false
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# Writes a OSX system agent.
|
195
|
+
#
|
196
|
+
# @param launch_agent [String] The agent path.
|
197
|
+
def write_agent(launch_agent)
|
198
|
+
::File.open(launch_agent, "w") {|f|
|
199
|
+
f.write({"KeepAlive" => false, "Label" => "it.cowtech.akaer", "Program" => (::Pathname.new(Dir.pwd) + $0).to_s, "ProgramArguments" => ($ARGV ? $ARGV[0, $ARGV.length - 1] : []), "RunAtLoad" => true}.to_json)
|
200
|
+
f.flush
|
201
|
+
}
|
202
|
+
end
|
203
|
+
|
204
|
+
# Deletes a OSX system agent.
|
205
|
+
#
|
206
|
+
# @param launch_agent [String] The agent path.
|
207
|
+
# @param quiet [Boolean] Whether to show messages.
|
208
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
209
|
+
def delete_agent(launch_agent, quiet)
|
210
|
+
begin
|
211
|
+
self.logger.info(self.i18n.agent_deleting(launch_agent)) if !quiet
|
212
|
+
::File.delete(launch_agent)
|
213
|
+
rescue => e
|
214
|
+
self.logger.warn(self.i18n.agent_deleting_error) if !quiet
|
215
|
+
return false
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# Loads a OSX system agent.
|
220
|
+
#
|
221
|
+
# @param launch_agent [String] The agent path.
|
222
|
+
# @param quiet [Boolean] Whether to show messages.
|
223
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
224
|
+
def load_agent(launch_agent, quiet)
|
225
|
+
begin
|
226
|
+
perform_agent_loading(launch_agent, "load", :agent_loading, quiet)
|
227
|
+
rescue
|
228
|
+
self.logger.error(self.i18n.agent_loading_error) if !quiet
|
229
|
+
false
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# Unloads a OSX system agent.
|
234
|
+
#
|
235
|
+
# @param launch_agent [String] The agent path.
|
236
|
+
# @param quiet [Boolean] Whether to show messages.
|
237
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
238
|
+
def unload_agent(launch_agent, quiet)
|
239
|
+
begin
|
240
|
+
perform_agent_loading(launch_agent, "unload", :agent_unloading, quiet)
|
241
|
+
rescue => e
|
242
|
+
self.logger.warn(self.i18n.agent_unloading_error) if !quiet
|
243
|
+
false
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# Performs operatoin on a OSX system agent.
|
248
|
+
#
|
249
|
+
# @param launch_agent [String] The agent path.
|
250
|
+
# @param command [String] The command to run.
|
251
|
+
# @param message [String] The message to show.
|
252
|
+
# @param quiet [Boolean] Whether to show messages.
|
253
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
254
|
+
def perform_agent_loading(launch_agent, command, message, quiet)
|
255
|
+
self.logger.info(self.i18n.send(message, launch_agent)) if !quiet
|
256
|
+
self.execute_command("launchctl #{command} -w \"#{launch_agent}\" > /dev/null 2>&1")
|
257
|
+
true
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
9
262
|
# The main Akaer application.
|
263
|
+
#
|
264
|
+
# @attribute config
|
265
|
+
# @return [Configuration] The {Configuration Configuration} of this application.
|
266
|
+
# @attribute command
|
267
|
+
# @return [Mamertes::Command] The Mamertes command.
|
268
|
+
# @attribute
|
269
|
+
# @return [Bovem::Logger] logger The logger for this application.
|
10
270
|
class Application
|
11
|
-
# The {Configuration Configuration} of this application.
|
12
271
|
attr_reader :config
|
13
|
-
|
14
|
-
# The Mamertes command.
|
15
272
|
attr_reader :command
|
16
|
-
|
17
|
-
# The logger for this application.
|
18
273
|
attr_accessor :logger
|
19
274
|
|
275
|
+
include Lazier::I18n
|
276
|
+
include Akaer::ApplicationMethods::General
|
277
|
+
include Akaer::ApplicationMethods::System
|
278
|
+
|
20
279
|
# Creates a new application.
|
21
280
|
#
|
22
281
|
# @param command [Mamertes::Command] The current Mamertes command.
|
23
|
-
|
282
|
+
# @param locale [Symbol] The locale to use for the application.
|
283
|
+
def initialize(command, locale)
|
284
|
+
self.i18n_setup(:akaer, ::File.absolute_path(::Pathname.new(::File.dirname(__FILE__)).to_s + "/../../locales/"))
|
285
|
+
self.i18n = locale
|
286
|
+
|
24
287
|
@command = command
|
25
|
-
|
288
|
+
options = @command.application.get_options.reject {|k,v| v.nil? }
|
26
289
|
|
27
290
|
# Setup logger
|
28
291
|
Bovem::Logger.start_time = Time.now
|
29
|
-
@logger = Bovem::Logger.create(Bovem::Logger.get_real_file(
|
292
|
+
@logger = Bovem::Logger.create(Bovem::Logger.get_real_file(options["log_file"]) || Bovem::Logger.default_file, Logger::INFO)
|
30
293
|
|
31
294
|
# Open configuration
|
32
|
-
|
33
|
-
overrides = {
|
34
|
-
:interface => application.options["interface"].value,
|
35
|
-
:addresses => application.options["addresses"].value,
|
36
|
-
:start_address => application.options["start-address"].value,
|
37
|
-
:aliases => application.options["aliases"].value,
|
38
|
-
:add_command => application.options["add-command"].value,
|
39
|
-
:remove_command => application.options["remove-command"].value,
|
40
|
-
:log_file => application.options["log-file"].value,
|
41
|
-
:log_level => application.options["log-level"].value,
|
42
|
-
:dry_run => application.options["dry-run"].value,
|
43
|
-
:quiet => application.options["quiet"].value
|
44
|
-
}.reject {|k,v| v.nil? }
|
45
|
-
|
46
|
-
@config = Akaer::Configuration.new(application.options["configuration"].value, overrides, @logger)
|
47
|
-
|
48
|
-
@logger = nil
|
49
|
-
@logger = self.get_logger
|
50
|
-
rescue Bovem::Errors::InvalidConfiguration => e
|
51
|
-
@logger ? @logger.fatal(e.message) : Bovem::Logger.create("STDERR").fatal("Cannot log to {mark=bright}#{config.log_file}{/mark}. Exiting...")
|
52
|
-
raise ::SystemExit
|
53
|
-
end
|
295
|
+
read_configuration(options)
|
54
296
|
|
55
297
|
self
|
56
298
|
end
|
57
299
|
|
58
|
-
# Checks if we are running on MacOS X.
|
59
|
-
#
|
60
|
-
# System services are only available on that platform.
|
61
|
-
#
|
62
|
-
# @return [Boolean] `true` if the current platform is MacOS X, `false` otherwise.
|
63
|
-
def is_osx?
|
64
|
-
::Config::CONFIG['host_os'] =~ /^darwin/
|
65
|
-
end
|
66
|
-
|
67
300
|
# Checks if and address is a valid IPv4 address.
|
68
301
|
#
|
69
302
|
# @param address [String] The address to check.
|
@@ -134,176 +367,67 @@ module Akaer
|
|
134
367
|
# @param type [Symbol] The type of addresses to consider. Valid values are `:ipv4`, `:ipv6`, otherwise all addresses are considered.
|
135
368
|
# @return [Array] The list of addresses to add or remove from the interface.
|
136
369
|
def compute_addresses(type = :all)
|
137
|
-
|
138
|
-
|
139
|
-
if self.config.addresses.present? # We have an explicit list
|
140
|
-
rv = self.config.addresses
|
141
|
-
|
142
|
-
# Now filter the addresses
|
143
|
-
filters = [type != :ipv6 ? :ipv4 : nil, type != :ipv4 ? :ipv6 : nil].compact
|
144
|
-
rv = rv.select {|address|
|
145
|
-
filters.any? {|filter| self.send("is_#{filter}?", address) }
|
146
|
-
}.compact.uniq
|
147
|
-
else
|
148
|
-
begin
|
149
|
-
ip = IPAddr.new(self.config.start_address.ensure_string)
|
150
|
-
raise ArgumentError if (type == :ipv4 && !ip.ipv4?) || (type == :ipv6 && !ip.ipv6?)
|
151
|
-
|
152
|
-
(self.config.aliases > 0 ? self.config.aliases : 5).times do
|
153
|
-
rv << ip.to_s
|
154
|
-
ip = ip.succ
|
155
|
-
end
|
156
|
-
rescue ArgumentError
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
rv
|
161
|
-
end
|
162
|
-
|
163
|
-
# Adds or removes an alias from the interface.
|
164
|
-
#
|
165
|
-
# @param type [Symbol] The operation to execute. Can be `:add` or `:remove`.
|
166
|
-
# @param address [String] The address to manage.
|
167
|
-
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
168
|
-
def manage(type, address)
|
169
|
-
rv = true
|
170
|
-
|
171
|
-
# Compute the command
|
172
|
-
command = (type == :remove) ? self.config.remove_command : self.config.add_command
|
173
|
-
|
174
|
-
# Interpolate
|
175
|
-
command = command.gsub("@INTERFACE@", self.config.interface).gsub("@ALIAS@", address) + " > /dev/null 2>&1"
|
176
|
-
|
177
|
-
# Compute the prefix
|
178
|
-
@addresses ||= self.compute_addresses
|
179
|
-
length = self.pad_number(@addresses.length)
|
180
|
-
index = (@addresses.index(address) || 0) + 1
|
181
|
-
prefix = "{mark=blue}[{mark=bright white}#{self.pad_number(index, length.length)}{mark=reset blue}/{/mark}#{length}{/mark}]{/mark}"
|
182
|
-
|
183
|
-
# Now execute
|
184
|
-
if !self.config.dry_run then
|
185
|
-
@logger.info(@command.application.console.replace_markers("#{prefix} {mark=bright}#{(type == :remove ? "Removing" : "Adding")}{/mark} address {mark=bright}#{address}{/mark} #{type != :remove ? "to" : "from"} interface {mark=bright}#{self.config.interface}{/mark}...")) if !self.config.quiet
|
186
|
-
rv = self.execute_command(command)
|
187
|
-
@logger.error(@command.application.console.replace_markers("Cannot {mark=bright}#{(type == :remove ? "remove" : "add")}{/mark} address {mark=bright}#{address}{/mark} #{type != :remove ? "to" : "from"} interface {mark=bright}#{self.config.interface}{/mark}.")) if !rv
|
188
|
-
else
|
189
|
-
@logger.info(@command.application.console.replace_markers("#{prefix} I will {mark=bright}#{(type == :remove ? "remove" : "add")}{/mark} address {mark=bright}#{address}{/mark} #{type != :remove ? "to" : "from"} interface {mark=bright}#{self.config.interface}{/mark}.")) if !self.config.quiet
|
190
|
-
end
|
191
|
-
|
192
|
-
rv
|
193
|
-
end
|
194
|
-
|
195
|
-
# Adds aliases to the interface.
|
196
|
-
#
|
197
|
-
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
198
|
-
def action_add
|
199
|
-
addresses = self.compute_addresses
|
200
|
-
|
201
|
-
if addresses.present? then
|
202
|
-
# Now, for every address, call the command
|
203
|
-
addresses.all? {|address|
|
204
|
-
self.manage(:add, address)
|
205
|
-
}
|
206
|
-
else
|
207
|
-
@logger.error("No valid addresses to add to the interface found.") if !self.config.quiet
|
208
|
-
end
|
370
|
+
config = self.config
|
371
|
+
config.addresses.present? ? filter_addresses(config, type) : generate_addresses(config, type)
|
209
372
|
end
|
210
373
|
|
211
|
-
#
|
374
|
+
# Returns a unique (singleton) instance of the application.
|
212
375
|
#
|
213
|
-
# @
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
self.manage(:remove, address)
|
221
|
-
}
|
222
|
-
else
|
223
|
-
@logger.error("No valid addresses to remove from the interface found.") if !self.config.quiet
|
224
|
-
end
|
376
|
+
# @param command [Mamertes::Command] The current Mamertes command.
|
377
|
+
# @param locale [Symbol] The locale to use for the application.
|
378
|
+
# @param force [Boolean] If to force recreation of the instance.
|
379
|
+
# @return [Application] The unique (singleton) instance of the application.
|
380
|
+
def self.instance(command, locale = nil, force = false)
|
381
|
+
@instance = nil if force
|
382
|
+
@instance ||= Akaer::Application.new(command, locale)
|
225
383
|
end
|
226
384
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
begin
|
241
|
-
logger.info("Creating the launch agent in {mark=bright}#{launch_agent}{/mark} ...") if !self.config.quiet
|
242
|
-
|
243
|
-
args = $ARGV ? $ARGV[0, $ARGV.length - 1] : []
|
244
|
-
|
245
|
-
plist = {"KeepAlive" => false, "Label" => "it.cowtech.akaer", "Program" => (::Pathname.new(Dir.pwd) + $0).to_s, "ProgramArguments" => args, "RunAtLoad" => true}
|
246
|
-
::File.open(launch_agent, "w") {|f|
|
247
|
-
f.write(plist.to_json)
|
248
|
-
f.flush
|
249
|
-
}
|
250
|
-
self.execute_command("plutil -convert binary1 \"#{launch_agent}\"")
|
251
|
-
rescue => e
|
252
|
-
logger.error("Cannot create the launch agent.") if !self.config.quiet
|
253
|
-
return false
|
385
|
+
private
|
386
|
+
# Reads the configuration.
|
387
|
+
#
|
388
|
+
# @param options [Hash] The options to read.
|
389
|
+
def read_configuration(options)
|
390
|
+
begin
|
391
|
+
@config = Akaer::Configuration.new(options["configuration"], options, @logger)
|
392
|
+
@logger = nil
|
393
|
+
@logger = self.get_logger
|
394
|
+
rescue Bovem::Errors::InvalidConfiguration => e
|
395
|
+
@logger ? @logger.fatal(e.message) : Bovem::Logger.create("STDERR").fatal(self.i18n.logging_failed(log_file))
|
396
|
+
raise ::SystemExit
|
397
|
+
end
|
254
398
|
end
|
255
399
|
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
400
|
+
# Filters a list of addresses to return just certain type(s).
|
401
|
+
#
|
402
|
+
# @param config [Configuration] The current configuration.
|
403
|
+
# @param type [Symbol] The type of addresses to return.
|
404
|
+
# @return [Array] A list of IPs.
|
405
|
+
def filter_addresses(config, type)
|
406
|
+
filters = [:ipv4, :ipv6].select {|i| type == i || type == :all }.compact
|
263
407
|
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
# Uninstalls the application from the autolaunch.
|
268
|
-
#
|
269
|
-
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
270
|
-
def action_uninstall
|
271
|
-
logger = self.get_logger
|
272
|
-
|
273
|
-
if !self.is_osx? then
|
274
|
-
logger.fatal("Install akaer on autolaunch is only available on MacOSX.") if !self.config.quiet
|
275
|
-
return false
|
408
|
+
rv = config.addresses.select { |address|
|
409
|
+
filters.any? {|filter| self.send("is_#{filter}?", address) }
|
410
|
+
}.compact.uniq
|
276
411
|
end
|
277
412
|
|
278
|
-
|
279
|
-
|
280
|
-
#
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
413
|
+
# Generates a list of addresses which are immediate successors of a start address.
|
414
|
+
#
|
415
|
+
# @param config [Configuration] The current configuration.
|
416
|
+
# @param type [Symbol] The type of addresses to return.
|
417
|
+
# @return [Array] A list of IPs.
|
418
|
+
def generate_addresses(config, type)
|
419
|
+
begin
|
420
|
+
ip = IPAddr.new(config.start_address.ensure_string)
|
421
|
+
raise ArgumentError if type != :all && !ip.send("#{type}?")
|
286
422
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
423
|
+
(config.aliases > 0 ? config.aliases : 5).times.collect {|i|
|
424
|
+
current = ip
|
425
|
+
ip = ip.succ
|
426
|
+
current
|
427
|
+
}
|
428
|
+
rescue ArgumentError
|
429
|
+
[]
|
430
|
+
end
|
294
431
|
end
|
295
|
-
|
296
|
-
true
|
297
|
-
end
|
298
|
-
|
299
|
-
# Returns a unique (singleton) instance of the application.
|
300
|
-
#
|
301
|
-
# @param command [Mamertes::Command] The current Mamertes command.
|
302
|
-
# @param force [Boolean] If to force recreation of the instance.
|
303
|
-
# @return [Application] The unique (singleton) instance of the application.
|
304
|
-
def self.instance(command, force = false)
|
305
|
-
@instance = nil if force
|
306
|
-
@instance ||= Akaer::Application.new(command)
|
307
|
-
end
|
308
432
|
end
|
309
433
|
end
|
data/lib/akaer/configuration.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
#
|
3
|
-
# This file is part of the akaer gem. Copyright (C)
|
3
|
+
# This file is part of the akaer gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
4
|
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
5
|
#
|
6
6
|
|
@@ -8,34 +8,34 @@ module Akaer
|
|
8
8
|
# This class holds the configuration of the applicaton.
|
9
9
|
class Configuration < Bovem::Configuration
|
10
10
|
# The default interface to manage. Default: `lo0`.
|
11
|
-
property :interface, :
|
11
|
+
property :interface, default: "lo0"
|
12
12
|
|
13
13
|
# The default list of aliases to add. Default: `[]`.
|
14
|
-
property :addresses, :
|
14
|
+
property :addresses, default: []
|
15
15
|
|
16
16
|
# The starting address for sequential aliases. Default: `10.0.0.1`.
|
17
|
-
property :start_address, :
|
17
|
+
property :start_address, default: "10.0.0.1"
|
18
18
|
|
19
19
|
# The number of aliases to add. Default: `5`.
|
20
|
-
property :aliases, :
|
20
|
+
property :aliases, default: 5
|
21
21
|
|
22
|
-
# The command to run for adding an alias. Default: `sudo ifconfig
|
23
|
-
property :add_command, :
|
22
|
+
# The command to run for adding an alias. Default: `sudo ifconfig {{interface}} alias {{alias}}`.
|
23
|
+
property :add_command, default: "sudo ifconfig {{interface}} alias {{alias}}"
|
24
24
|
|
25
|
-
# The command to run for removing an alias. Default: `sudo ifconfig
|
26
|
-
property :remove_command, :
|
25
|
+
# The command to run for removing an alias. Default: `sudo ifconfig {{interface}} alias {{alias}}`.
|
26
|
+
property :remove_command, default: "sudo ifconfig {{interface}} -alias {{alias}}"
|
27
27
|
|
28
28
|
# The file to log to. Default is the standard output.
|
29
|
-
property :log_file, :
|
29
|
+
property :log_file, default: "STDOUT"
|
30
30
|
|
31
31
|
# The minimum severity to log. Default: `Logger::INFO`.
|
32
|
-
property :log_level, :
|
32
|
+
property :log_level, default: Logger::INFO
|
33
33
|
|
34
34
|
# Only show which modifications will be done.
|
35
|
-
property :dry_run, :
|
35
|
+
property :dry_run, default: false
|
36
36
|
|
37
37
|
# Do not show any message.
|
38
|
-
property :quiet, :
|
38
|
+
property :quiet, default: false
|
39
39
|
|
40
40
|
# Creates a new configuration.
|
41
41
|
#
|
data/lib/akaer/version.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
#
|
3
|
-
# This file is part of the akaer gem. Copyright (C)
|
3
|
+
# This file is part of the akaer gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
4
|
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
5
|
#
|
6
6
|
|
@@ -10,13 +10,13 @@ module Akaer
|
|
10
10
|
# @see http://semver.org
|
11
11
|
module Version
|
12
12
|
# The major version.
|
13
|
-
MAJOR =
|
13
|
+
MAJOR = 2
|
14
14
|
|
15
15
|
# The minor version.
|
16
|
-
MINOR =
|
16
|
+
MINOR = 0
|
17
17
|
|
18
18
|
# The patch version.
|
19
|
-
PATCH =
|
19
|
+
PATCH = 0
|
20
20
|
|
21
21
|
# The current version of akaer.
|
22
22
|
STRING = [MAJOR, MINOR, PATCH].compact.join(".")
|
data/lib/akaer.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
#
|
3
|
-
# This file is part of the akaer gem. Copyright (C)
|
3
|
+
# This file is part of the akaer gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
4
|
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
5
|
#
|
6
6
|
|
7
7
|
require "mamertes"
|
8
|
+
require "mustache"
|
8
9
|
require "ipaddr"
|
9
10
|
|
10
11
|
require "akaer/version" if !defined?(Akaer::Version)
|