akaer 0.3.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +3 -0
- data/Gemfile.lock +20 -24
- data/README.md +19 -14
- data/akaer.gemspec +3 -6
- data/bin/akaer +83 -1
- data/lib/akaer.rb +2 -9
- data/lib/akaer/application.rb +284 -76
- data/lib/akaer/configuration.rb +39 -24
- data/lib/akaer/version.rb +11 -2
- data/spec/akaer/application_spec.rb +311 -1
- data/spec/akaer/configuration_spec.rb +13 -1
- data/spec/spec_helper.rb +7 -1
- metadata +16 -68
- data/lib/akaer/errors.rb +0 -12
- data/lib/akaer/logger.rb +0 -58
- data/spec/akaer/logger_spec.rb +0 -11
data/.travis.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,51 +1,48 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
akaer (0.
|
5
|
-
|
6
|
-
|
7
|
-
hashie (~> 1.2.0)
|
8
|
-
rainbow (~> 1.1.0)
|
4
|
+
akaer (1.0.0)
|
5
|
+
bovem (>= 0.5.0)
|
6
|
+
gli (~> 1.6.0)
|
9
7
|
|
10
8
|
GEM
|
11
9
|
remote: http://rubygems.org/
|
12
10
|
specs:
|
13
|
-
actionpack (3.2.
|
14
|
-
activemodel (= 3.2.
|
15
|
-
activesupport (= 3.2.
|
11
|
+
actionpack (3.2.7)
|
12
|
+
activemodel (= 3.2.7)
|
13
|
+
activesupport (= 3.2.7)
|
16
14
|
builder (~> 3.0.0)
|
17
15
|
erubis (~> 2.7.0)
|
18
|
-
journey (~> 1.0.
|
16
|
+
journey (~> 1.0.4)
|
19
17
|
rack (~> 1.4.0)
|
20
18
|
rack-cache (~> 1.2)
|
21
19
|
rack-test (~> 0.6.1)
|
22
20
|
sprockets (~> 2.1.3)
|
23
|
-
activemodel (3.2.
|
24
|
-
activesupport (= 3.2.
|
21
|
+
activemodel (3.2.7)
|
22
|
+
activesupport (= 3.2.7)
|
25
23
|
builder (~> 3.0.0)
|
26
|
-
activesupport (3.2.
|
24
|
+
activesupport (3.2.7)
|
27
25
|
i18n (~> 0.6)
|
28
26
|
multi_json (~> 1.0)
|
27
|
+
bovem (0.6.0)
|
28
|
+
lazier (~> 1.0)
|
29
|
+
rainbow (~> 1.1.0)
|
29
30
|
builder (3.0.0)
|
30
31
|
coderay (1.0.7)
|
31
|
-
cowtech-extensions (2.7.1)
|
32
|
-
actionpack (~> 3.0)
|
33
|
-
json (~> 1.7.0)
|
34
|
-
tzinfo (~> 0.3.0)
|
35
|
-
cowtech-lib (2.0.2)
|
36
|
-
open4
|
37
32
|
diff-lcs (1.1.3)
|
38
33
|
erubis (2.7.0)
|
39
34
|
github-markup (0.7.2)
|
40
|
-
|
35
|
+
gli (1.6.0)
|
41
36
|
hike (1.2.1)
|
42
37
|
i18n (0.6.0)
|
43
38
|
journey (1.0.4)
|
44
|
-
json (1.7.
|
39
|
+
json (1.7.4)
|
40
|
+
lazier (1.0.1)
|
41
|
+
actionpack (~> 3.0)
|
42
|
+
json (~> 1.7.0)
|
43
|
+
tzinfo (~> 0.3.0)
|
45
44
|
method_source (0.8)
|
46
45
|
multi_json (1.3.6)
|
47
|
-
net-dns (0.7.1)
|
48
|
-
open4 (1.3.0)
|
49
46
|
pry (0.9.10)
|
50
47
|
coderay (~> 1.0.5)
|
51
48
|
method_source (~> 0.8)
|
@@ -85,8 +82,7 @@ PLATFORMS
|
|
85
82
|
DEPENDENCIES
|
86
83
|
akaer!
|
87
84
|
github-markup (~> 0.7.0)
|
88
|
-
|
89
|
-
pry (~> 0.9.10)
|
85
|
+
pry
|
90
86
|
rake (~> 0.9.0)
|
91
87
|
redcarpet (~> 2.1.0)
|
92
88
|
rspec (~> 2.11.0)
|
data/README.md
CHANGED
@@ -4,21 +4,26 @@
|
|
4
4
|
[![Dependency Status](https://gemnasium.com/ShogunPanda/akaer.png?travis)](https://gemnasium.com/ShogunPanda/akaer)
|
5
5
|
|
6
6
|
A small utility to add aliases to network interfaces.
|
7
|
+
|
7
8
|
http://github.com/ShogunPanda/akaer
|
8
9
|
|
9
10
|
## Description
|
10
11
|
|
11
|
-
Akaer is a small utility that adds and
|
12
|
+
Akaer is a small utility that adds and removes aliases to your network interfaces. This is useful in web development.
|
12
13
|
|
13
14
|
## Basic usage
|
14
15
|
|
15
16
|
1. Install the gem:
|
16
17
|
|
17
|
-
|
18
|
+
```sh
|
19
|
+
gem install akaer
|
20
|
+
```
|
18
21
|
|
19
22
|
2. Run the application:
|
20
23
|
|
21
|
-
|
24
|
+
```sh
|
25
|
+
akaer
|
26
|
+
```
|
22
27
|
|
23
28
|
**You're done!**
|
24
29
|
|
@@ -33,23 +38,23 @@ By defaults, Akaer uses a configuration file in `~/.akaer_config`, but you can c
|
|
33
38
|
The file is a plain Ruby file with a single `config` object that supports the following directives.
|
34
39
|
|
35
40
|
* `interface`: The network interface to manage. `lo0` by default.
|
36
|
-
* `
|
37
|
-
* `
|
41
|
+
* `addresses`: A specific list of aliases to manage.
|
42
|
+
* `start_address`: The address to start sequential address. `10.0.0.1` by default. Not used if `addresses` is specified.
|
38
43
|
* `aliases`: The number of sequential addresses to add. 5 by default.
|
44
|
+
* `add_command`: The command to run for adding an alias. `sudo ifconfig @INTERFACE@ alias @ALIAS@` by default.
|
45
|
+
* `remove_command`: The command to run for removing an alias. `sudo ifconfig @INTERFACE@ -alias @ALIAS@` by default.
|
39
46
|
* `log_file`: The default log file. By default it logs to standard output.
|
40
47
|
* `log_level`: The default log level. Valid values are from 0 to 5 where 0 means "all messages".
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
Akaer is tightly coupled with the UNIX tools, so it won't work for Windows.
|
48
|
+
* `dry_run`: Only show which modifications will be done.
|
49
|
+
* `quiet`: Do not show any message.
|
45
50
|
|
46
51
|
## Contributing to akaer
|
47
52
|
|
48
|
-
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
49
|
-
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
50
|
-
* Fork the project
|
51
|
-
* Start a feature/bugfix branch
|
52
|
-
* Commit and push until you are happy with your contribution
|
53
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet.
|
54
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it.
|
55
|
+
* Fork the project.
|
56
|
+
* Start a feature/bugfix branch.
|
57
|
+
* Commit and push until you are happy with your contribution.
|
53
58
|
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
54
59
|
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
55
60
|
|
data/akaer.gemspec
CHANGED
@@ -21,16 +21,13 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
22
22
|
gem.require_paths = ["lib"]
|
23
23
|
|
24
|
-
gem.add_dependency("
|
25
|
-
gem.add_dependency("
|
26
|
-
gem.add_dependency("hashie", "~> 1.2.0")
|
27
|
-
gem.add_dependency("rainbow", "~> 1.1.0")
|
24
|
+
gem.add_dependency("bovem", ">= 0.5.0")
|
25
|
+
gem.add_dependency("gli", "~> 1.6.0")
|
28
26
|
|
29
27
|
gem.add_development_dependency("rspec", "~> 2.11.0")
|
30
28
|
gem.add_development_dependency("rake", "~> 0.9.0")
|
31
29
|
gem.add_development_dependency("simplecov", "~> 0.6.0")
|
32
|
-
gem.add_development_dependency("pry", "
|
33
|
-
gem.add_development_dependency("net-dns", "~> 0.7.0")
|
30
|
+
gem.add_development_dependency("pry", ">= 0")
|
34
31
|
gem.add_development_dependency("yard", "~> 0.8.0")
|
35
32
|
gem.add_development_dependency("redcarpet", "~> 2.1.0")
|
36
33
|
gem.add_development_dependency("github-markup", "~> 0.7.0")
|
data/bin/akaer
CHANGED
@@ -6,4 +6,86 @@
|
|
6
6
|
|
7
7
|
require "rubygems"
|
8
8
|
require "akaer"
|
9
|
-
|
9
|
+
require "gli"
|
10
|
+
|
11
|
+
include GLI
|
12
|
+
|
13
|
+
program_desc("A small utility to add aliases to network interfaces.")
|
14
|
+
version(Akaer::Version::STRING)
|
15
|
+
|
16
|
+
desc("The default interface to manage.")
|
17
|
+
default_value("lo0")
|
18
|
+
arg_name("INTERFACE")
|
19
|
+
flag(:i, :interface)
|
20
|
+
|
21
|
+
desc("The default list of aliases to add.")
|
22
|
+
default_value([])
|
23
|
+
arg_name("ADDRESSES")
|
24
|
+
flag(:A, :addresses)
|
25
|
+
|
26
|
+
desc("The starting address for sequential aliases.")
|
27
|
+
default_value("10.0.0.1")
|
28
|
+
arg_name("ADDRESS")
|
29
|
+
flag(:s, :"start-address")
|
30
|
+
|
31
|
+
desc("The number of aliases to add.")
|
32
|
+
default_value(5)
|
33
|
+
arg_name("ALIASES")
|
34
|
+
flag(:S, :aliases)
|
35
|
+
|
36
|
+
desc("The command to run for adding an alias.")
|
37
|
+
default_value("sudo ifconfig @INTERFACE@ alias @ALIAS@")
|
38
|
+
arg_name("COMMAND")
|
39
|
+
flag(:c, :"add-command")
|
40
|
+
|
41
|
+
desc("The command to run for adding an alias.")
|
42
|
+
default_value("sudo ifconfig @INTERFACE@ -alias @ALIAS@")
|
43
|
+
arg_name("COMMAND")
|
44
|
+
flag(:C, :"remove-command")
|
45
|
+
|
46
|
+
desc("The default log file.")
|
47
|
+
default_value("STDOUT")
|
48
|
+
arg_name("LOG")
|
49
|
+
flag([:l, :log])
|
50
|
+
|
51
|
+
desc("The default log level. Valid values are from 0 to 5 where 0 means \"all messages\".")
|
52
|
+
default_value(1)
|
53
|
+
arg_name("LEVEL")
|
54
|
+
flag([:L, :"log-level"])
|
55
|
+
|
56
|
+
desc("Only show which modifications will be done")
|
57
|
+
switch([:n, :"dry-run"])
|
58
|
+
|
59
|
+
desc("Do not show any message.")
|
60
|
+
switch([:q, :quiet])
|
61
|
+
|
62
|
+
desc("Add aliases.")
|
63
|
+
command [:a, :add] do |c|
|
64
|
+
c.action do |globals, locals, args|
|
65
|
+
Akaer::Application.instance(globals, locals, args).action_add()
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
desc("Remove aliases.")
|
70
|
+
command [:r, :remove] do |c|
|
71
|
+
c.action do |globals, locals, args|
|
72
|
+
Akaer::Application.instance(globals, locals, args).action_remove()
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
desc("Install the application for autolaunch.")
|
77
|
+
command [:i, :install] do |c|
|
78
|
+
c.action do |globals, locals, args|
|
79
|
+
Akaer::Application.instance(globals, locals, args).action_install()
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
desc("Uninstall the application from autolaunch.")
|
84
|
+
command [:u, :uninstall] do |c|
|
85
|
+
c.action do |globals, locals, args|
|
86
|
+
Akaer::Application.instance(globals, locals, args).action_uninstall()
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
ARGV << "help" if ARGV.length == 0
|
91
|
+
exit(GLI.run(ARGV))
|
data/lib/akaer.rb
CHANGED
@@ -4,16 +4,9 @@
|
|
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
|
-
require "
|
8
|
-
require "cowtech-lib"
|
7
|
+
require "bovem"
|
9
8
|
require "ipaddr"
|
10
|
-
require "hashie"
|
11
|
-
require "rainbow"
|
12
|
-
require "pathname"
|
13
9
|
|
14
10
|
require "akaer/version" if !defined?(Akaer::Version)
|
15
|
-
require "akaer/errors"
|
16
|
-
require "akaer/logger"
|
17
11
|
require "akaer/configuration"
|
18
|
-
require "akaer/application"
|
19
|
-
|
12
|
+
require "akaer/application"
|
data/lib/akaer/application.rb
CHANGED
@@ -4,104 +4,312 @@
|
|
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
|
-
|
8
|
-
|
7
|
+
# A small utility to add aliases to network interfaces.
|
8
|
+
module Akaer
|
9
|
+
# The main Akaer application.
|
10
|
+
class Application
|
11
|
+
# The {Configuration Configuration} of this application.
|
12
|
+
attr_reader :config
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
self.to_s.rjust(num, "0")
|
13
|
-
end
|
14
|
-
end
|
14
|
+
# The arguments passed via command-line.
|
15
|
+
attr_reader :args
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
# The logger for this application.
|
18
|
+
attr_accessor :logger
|
19
|
+
|
20
|
+
# Creates a new application.
|
21
|
+
#
|
22
|
+
# @param globals [Hash] Global options.
|
23
|
+
# @param locals [Hash] Local command options.
|
24
|
+
# @param args [Array] Extra arguments.
|
25
|
+
def initialize(globals = {}, locals = {}, args = [])
|
26
|
+
@args = {
|
27
|
+
:global => globals,
|
28
|
+
:local => locals,
|
29
|
+
:args => args
|
30
|
+
}
|
31
|
+
|
32
|
+
# Setup logger
|
33
|
+
Bovem::Logger.start_time = Time.now
|
34
|
+
@logger = Bovem::Logger.create(Bovem::Logger.get_real_file(@args[:global][:log_file]) || Bovem::Logger.default_file, Logger::INFO)
|
35
|
+
|
36
|
+
# Open configuration
|
37
|
+
begin
|
38
|
+
overrides = {
|
39
|
+
:interface => @args[:global][:interface],
|
40
|
+
:addresses => @args[:global][:addresses],
|
41
|
+
:start_address => @args[:global][:"start-address"],
|
42
|
+
:aliases => @args[:global][:aliases],
|
43
|
+
:add_command => @args[:global][:"add-command"],
|
44
|
+
:remove_command => @args[:global][:"remove-command"],
|
45
|
+
:log_file => @args[:global][:"log-file"],
|
46
|
+
:log_level => @args[:global][:"log-level"],
|
47
|
+
:dry_run => @args[:global][:"dry-run"],
|
48
|
+
:quiet => @args[:global][:quiet]
|
49
|
+
}.reject {|k,v| v.nil? }
|
50
|
+
|
51
|
+
@config = Akaer::Configuration.new(@args[:global][:config], overrides, @logger)
|
52
|
+
|
53
|
+
@logger = nil
|
54
|
+
@logger = self.get_logger
|
55
|
+
rescue Bovem::Errors::InvalidConfiguration => e
|
56
|
+
@logger ? @logger.fatal(e.message) : Bovem::Logger.create("STDERR").fatal("Cannot log to #{config.log_file}. Exiting...")
|
57
|
+
raise ::SystemExit
|
58
|
+
end
|
59
|
+
|
60
|
+
self
|
20
61
|
end
|
21
62
|
|
22
|
-
|
23
|
-
|
63
|
+
# Checks if we are running on MacOS X.
|
64
|
+
# System services are only available on that platform.
|
65
|
+
#
|
66
|
+
# @return [Boolean] `true` if the current platform is MacOS X, `false` otherwise.
|
67
|
+
def is_osx?
|
68
|
+
::Config::CONFIG['host_os'] =~ /^darwin/
|
24
69
|
end
|
25
70
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
{:name => "dry-run", :short => "-n", :long => "--dry-run", :type => :bool, :help => "Do not really execute actions."},
|
36
|
-
{:name => "quiet", :short => "-q", :long => "--quiet", :type => :bool, :help => "Do not show any message", :required => false, :default => false}
|
37
|
-
]
|
71
|
+
# Checks if and address is a valid IPv4 address.
|
72
|
+
#
|
73
|
+
# @param address [String] The address to check.
|
74
|
+
# @return [Boolean] `true` if the address is a valid IPv4 address, `false` otherwise.
|
75
|
+
def is_ipv4?(address)
|
76
|
+
address = address.ensure_string
|
77
|
+
|
78
|
+
mo = /\A(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})\Z/.match(address)
|
79
|
+
rv = (mo && mo.captures.all? {|i| i.to_i < 256}) ? true : false
|
38
80
|
end
|
39
81
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
82
|
+
# Checks if and address is a valid IPv4 address.
|
83
|
+
#
|
84
|
+
# @param address [String] The address to check.
|
85
|
+
# @return [Boolean] `true` if the address is a valid IPv4 address, `false` otherwise.
|
86
|
+
def is_ipv6?(address)
|
87
|
+
address = address.ensure_string
|
88
|
+
|
89
|
+
rv = catch(:valid) do
|
90
|
+
# IPv6 (normal)
|
91
|
+
throw(:valid, true) if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*\Z/ =~ address
|
92
|
+
throw(:valid, true) if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ address
|
93
|
+
throw(:valid, true) if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*)?\Z/ =~ address
|
94
|
+
# IPv6 (IPv4 compat)
|
95
|
+
throw(:valid, true) if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:/ =~ address && self.is_ipv4?($')
|
96
|
+
throw(:valid, true) if /\A[\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ address && self.is_ipv4?($')
|
97
|
+
throw(:valid, true) if /\A::([\dA-Fa-f]{1,4}(:[\dA-Fa-f]{1,4})*:)?/ =~ address && self.is_ipv4?($')
|
98
|
+
|
99
|
+
false
|
100
|
+
end
|
44
101
|
end
|
45
102
|
|
46
|
-
def run
|
47
|
-
@logger = Akaer::Logger.create(@options_parser["log-file"], @options_parser["log-level"])
|
48
103
|
|
49
|
-
|
50
|
-
|
51
|
-
|
104
|
+
# Pads a number to make it print friendly.
|
105
|
+
#
|
106
|
+
# @param num [Fixnum] The number to pad.
|
107
|
+
# @param len [Fixnum] The minimum length of the padded string.
|
108
|
+
# @return [String] The padded number.
|
109
|
+
def pad_number(num, len = nil)
|
110
|
+
num.to_integer.to_s.rjust([len.to_integer, 2].max, "0")
|
111
|
+
end
|
52
112
|
|
53
|
-
|
54
|
-
|
113
|
+
# Gets the current logger of the application.
|
114
|
+
#
|
115
|
+
# @return [Logger] The current logger of the application.
|
116
|
+
def get_logger
|
117
|
+
@logger ||= Bovem::Logger.create(Bovem::Logger.default_file, @config.log_level, @log_formatter)
|
118
|
+
end
|
55
119
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
120
|
+
# Gets the path for the launch agent file.
|
121
|
+
#
|
122
|
+
# @param name [String] The base name for the agent.
|
123
|
+
# @return [String] The path for the launch agent file.
|
124
|
+
def launch_agent_path(name = "it.cowtech.akaer")
|
125
|
+
ENV["HOME"] + "/Library/LaunchAgents/#{name}.plist"
|
126
|
+
end
|
61
127
|
|
62
|
-
|
63
|
-
|
128
|
+
# Executes a shell command.
|
129
|
+
#
|
130
|
+
# @param command [String] The command to execute.
|
131
|
+
# @return [Boolean] `true` if command succeeded, `false` otherwise.
|
132
|
+
def execute_command(command)
|
133
|
+
Kernel.system(command)
|
134
|
+
end
|
64
135
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
136
|
+
# Computes the list of address to manage.
|
137
|
+
#
|
138
|
+
# @param type [Symbol] The type of addresses to consider. Valid values are `:ipv4`, `:ipv6`, otherwise all addresses are considered.
|
139
|
+
# @return [Array] The list of addresses to add or remove from the interface.
|
140
|
+
def compute_addresses(type = :all)
|
141
|
+
rv = []
|
70
142
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
143
|
+
if self.config.addresses.present? # We have an explicit list
|
144
|
+
rv = self.config.addresses
|
145
|
+
|
146
|
+
# Now filter the addresses
|
147
|
+
filters = [type != :ipv6 ? :ipv4 : nil, type != :ipv4 ? :ipv6 : nil].compact
|
148
|
+
rv = rv.select {|address|
|
149
|
+
filters.any? {|filter| self.send("is_#{filter}?", address) }
|
150
|
+
}.compact.uniq
|
151
|
+
else
|
152
|
+
begin
|
153
|
+
ip = IPAddr.new(self.config.start_address.ensure_string)
|
154
|
+
raise ArgumentError if (type == :ipv4 && !ip.ipv4?) || (type == :ipv6 && !ip.ipv6?)
|
155
|
+
|
156
|
+
(self.config.aliases > 0 ? self.config.aliases : 5).times do
|
157
|
+
rv << ip.to_s
|
158
|
+
ip = ip.succ
|
85
159
|
end
|
160
|
+
rescue ArgumentError
|
86
161
|
end
|
87
|
-
rescue ArgumentError => e
|
88
|
-
logger.fatal("\"#{target_address}\" is not a valid IP address.")
|
89
|
-
abort
|
90
162
|
end
|
91
163
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
164
|
+
rv
|
165
|
+
end
|
166
|
+
|
167
|
+
# Adds or removes an alias from the interface
|
168
|
+
#
|
169
|
+
# @param type [Symbol] The operation to execute. Can be `:add` or `:remove`.
|
170
|
+
# @param address [String] The address to manage.
|
171
|
+
# @return [Boolean] `true` if operation succedeed, `false` otherwise.
|
172
|
+
def manage(type, address)
|
173
|
+
rv = true
|
174
|
+
|
175
|
+
# Compute the command
|
176
|
+
command = (type == :remove) ? self.config.remove_command : self.config.add_command
|
177
|
+
|
178
|
+
# Interpolate
|
179
|
+
command = command.gsub("@INTERFACE@", self.config.interface).gsub("@ALIAS@", address) + " > /dev/null 2>&1"
|
180
|
+
|
181
|
+
# Compute the prefix
|
182
|
+
@addresses ||= self.compute_addresses
|
183
|
+
length = self.pad_number(@addresses.length)
|
184
|
+
index = (@addresses.index(address) || 0) + 1
|
185
|
+
prefix = ["[".color(:cyan), self.pad_number(index, length.length).bright, "/".color(:cyan), length.bright, "]".color(:cyan)].join("")
|
186
|
+
|
187
|
+
# Now execute
|
188
|
+
if !self.config.dry_run then
|
189
|
+
@logger.info("#{prefix} #{(type == :remove ? "Removing" : "Adding").bright} address #{address.bright} #{type != :remove ? "to" : "from"} interface #{self.config.interface.bright}...") if !self.config.quiet
|
190
|
+
rv = self.execute_command(command)
|
191
|
+
|
192
|
+
# TODO: The end badge.
|
193
|
+
else
|
194
|
+
@logger.info("#{prefix} I will #{(type == :remove ? "remove" : "add").bright} address #{address.bright} #{type != :remove ? "to" : "from"} interface #{self.config.interface.bright}.") if !self.config.quiet
|
195
|
+
end
|
196
|
+
|
197
|
+
rv
|
198
|
+
end
|
199
|
+
|
200
|
+
# Adds aliases to the interface.
|
201
|
+
#
|
202
|
+
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
203
|
+
def action_add
|
204
|
+
addresses = self.compute_addresses
|
205
|
+
|
206
|
+
if addresses.present? then
|
207
|
+
# Now, for every address, call the command
|
208
|
+
addresses.all? {|address|
|
209
|
+
self.manage(:add, address)
|
210
|
+
}
|
211
|
+
else
|
212
|
+
@logger.error("No valid addresses to add to the interface found.") if !self.config.quiet
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
# Removes aliases from the interface.
|
217
|
+
#
|
218
|
+
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
219
|
+
def action_remove
|
220
|
+
addresses = self.compute_addresses
|
221
|
+
|
222
|
+
if addresses.present? then
|
223
|
+
# Now, for every address, call the command
|
224
|
+
addresses.all? {|address|
|
225
|
+
self.manage(:remove, address)
|
226
|
+
}
|
102
227
|
else
|
103
|
-
@logger.
|
228
|
+
@logger.error("No valid addresses to remove from the interface found.") if !self.config.quiet
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
# Installs the application into the autolaunch.
|
233
|
+
#
|
234
|
+
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
235
|
+
def action_install
|
236
|
+
logger = get_logger
|
237
|
+
|
238
|
+
if !self.is_osx? then
|
239
|
+
logger.fatal("Install akaer on autolaunch is only available on MacOSX.") if !self.config.quiet
|
240
|
+
return false
|
241
|
+
end
|
242
|
+
|
243
|
+
launch_agent = self.launch_agent_path
|
244
|
+
|
245
|
+
begin
|
246
|
+
logger.info("Creating the launch agent in #{launch_agent} ...") if !self.config.quiet
|
247
|
+
|
248
|
+
args = $ARGV ? $ARGV[0, $ARGV.length - 1] : []
|
249
|
+
|
250
|
+
plist = {"KeepAlive" => false, "Label" => "it.cowtech.akaer", "Program" => (::Pathname.new(Dir.pwd) + $0).to_s, "ProgramArguments" => args, "RunAtLoad" => true}
|
251
|
+
::File.open(launch_agent, "w") {|f|
|
252
|
+
f.write(plist.to_json)
|
253
|
+
f.flush
|
254
|
+
}
|
255
|
+
self.execute_command("plutil -convert binary1 \"#{launch_agent}\"")
|
256
|
+
rescue => e
|
257
|
+
logger.error("Cannot create the launch agent.") if !self.config.quiet
|
258
|
+
return false
|
104
259
|
end
|
260
|
+
|
261
|
+
begin
|
262
|
+
logger.info("Loading the launch agent ...") if !self.config.quiet
|
263
|
+
self.execute_command("launchctl load -w \"#{launch_agent}\" > /dev/null 2>&1")
|
264
|
+
rescue => e
|
265
|
+
logger.error("Cannot load the launch agent.") if !self.config.quiet
|
266
|
+
return false
|
267
|
+
end
|
268
|
+
|
269
|
+
true
|
270
|
+
end
|
271
|
+
|
272
|
+
# Uninstalls the application from the autolaunch.
|
273
|
+
#
|
274
|
+
# @return [Boolean] `true` if action succedeed, `false` otherwise.
|
275
|
+
def action_uninstall
|
276
|
+
logger = self.get_logger
|
277
|
+
|
278
|
+
if !self.is_osx? then
|
279
|
+
logger.fatal("Install akaer on autolaunch is only available on MacOSX.") if !self.config.quiet
|
280
|
+
return false
|
281
|
+
end
|
282
|
+
|
283
|
+
launch_agent = self.launch_agent_path
|
284
|
+
|
285
|
+
# Unload the launch agent.
|
286
|
+
begin
|
287
|
+
self.execute_command("launchctl unload -w \"#{launch_agent}\" > /dev/null 2>&1")
|
288
|
+
rescue => e
|
289
|
+
logger.warn("Cannot unload the launch agent.") if !self.config.quiet
|
290
|
+
end
|
291
|
+
|
292
|
+
# Delete the launch agent.
|
293
|
+
begin
|
294
|
+
logger.info("Deleting the launch agent #{launch_agent} ...")
|
295
|
+
::File.delete(launch_agent)
|
296
|
+
rescue => e
|
297
|
+
logger.warn("Cannot delete the launch agent.") if !self.config.quiet
|
298
|
+
return false
|
299
|
+
end
|
300
|
+
|
301
|
+
true
|
302
|
+
end
|
303
|
+
|
304
|
+
# Returns a unique (singleton) instance of the application.
|
305
|
+
# @param globals [Hash] Global options.
|
306
|
+
# @param locals [Hash] Local command options.
|
307
|
+
# @param args [Array] Extra arguments.
|
308
|
+
# @param force [Boolean] If to force recreation of the instance.
|
309
|
+
# @return [Application] The unique (singleton) instance of the application.
|
310
|
+
def self.instance(globals = {}, locals = {}, args = [], force = false)
|
311
|
+
@instance = nil if force
|
312
|
+
@instance ||= Akaer::Application.new(globals, locals, args)
|
105
313
|
end
|
106
314
|
end
|
107
315
|
end
|