irrc 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -9,5 +9,11 @@ module Irrc
9
9
  def logger
10
10
  @logger ||= Logger.new(STDERR).tap {|l| l.level = Logger::WARN }
11
11
  end
12
+
13
+ class Logger < ::Logger
14
+ def add(severity, message = nil, progname = nil, &block)
15
+ super(severity, message, "(#{Thread.current[:id]}) #{progname}")
16
+ end
17
+ end
12
18
  end
13
19
  end
@@ -1,11 +1,10 @@
1
1
  module Irrc
2
2
  module Parameter
3
-
4
3
  # Public: Create a new IRRd / Whoisd client worker.
5
4
  # You can customize the logger by specifying a block.
6
5
  # The default logger is STDERR printer of more severe messages than INFO.
7
6
  #
8
- # host - FQDN of IRR / Whois. IRR / Whois name is also accespted.
7
+ # fqdn - FQDN of IRR / Whois.
9
8
  # queue - Queue object having query jobs.
10
9
  # IRR / Whois name is also accespted.
11
10
  # block - An optional block that can be used to customize the logger.
@@ -15,18 +14,19 @@ module Irrc
15
14
  # Irrc::Irrd::Client.new('jpirr.nic.ad.jp', queue) {|c|
16
15
  # c.logger = Logger.new('irrc.log')
17
16
  # }
18
- def initialize(host, queue, &block)
19
- self.host = host
17
+ def initialize(fqdn, queue, cache, &block)
18
+ self.fqdn = fqdn
20
19
  self.queue = queue
20
+ @cache = cache
21
21
  instance_eval(&block) if block_given?
22
22
  end
23
23
 
24
24
 
25
25
  private
26
26
 
27
- def host=(host)
28
- raise ArgumentError, "Missing argument." unless host
29
- @host = Irrc::Irr.host(host) || host
27
+ def fqdn=(fqdn)
28
+ raise ArgumentError, "Missing argument." unless fqdn
29
+ @fqdn = fqdn
30
30
  end
31
31
 
32
32
  def queue=(queue)
@@ -5,7 +5,7 @@ module Irrc
5
5
  private
6
6
 
7
7
  def classify_by_protocol(prefixes)
8
- prefixes.each_with_object(Struct.new(:ipv4, :ipv6).new([], [])) {|prefix, result|
8
+ Array(prefixes).each_with_object(Struct.new(:ipv4, :ipv6).new([], [])) {|prefix, result|
9
9
  addr = IPAddr.new(prefix)
10
10
  if addr.ipv4?
11
11
  result.ipv4 << prefix
@@ -40,6 +40,8 @@ module Irrc
40
40
  #
41
41
  # autnums - aut-num object(s) in String. Array form is also acceptable for multiple objects.
42
42
  def add_aut_num_result(autnums)
43
+ result = root.result
44
+
43
45
  @protocols.each do |protocol|
44
46
  result[protocol] ||= {}
45
47
 
@@ -56,9 +58,11 @@ module Irrc
56
58
  # protocol - Which protocol the route object(s) is for. :ipv4 or :ipv6.
57
59
  # A String or Symbol of protcol name is acceptable.
58
60
  def add_prefix_result(prefixes, autnum, protocol)
61
+ result = root.result
62
+
59
63
  result[protocol] ||= {}
60
64
  result[protocol][autnum] ||= []
61
- result[protocol][autnum] |= Array(prefixes)
65
+ result[protocol][autnum].push *Array(prefixes)
62
66
  end
63
67
 
64
68
 
@@ -9,7 +9,7 @@ module Irrc
9
9
  end
10
10
 
11
11
  def failed?
12
- @failed
12
+ @failed == true
13
13
  end
14
14
 
15
15
  def succeeded?
@@ -1,37 +1,63 @@
1
1
  module Irrc
2
2
  module Runner
3
- def run
3
+ def run(threads)
4
4
  done = []
5
5
 
6
6
  loop do
7
- if queue.empty?
8
- close
7
+ # NOTE: trick to avoid dead lock
8
+ if last_thread_of?(threads) && @queue.empty?
9
+ terminate
10
+ logger.debug "Queue #{threads - 1} guard objects"
11
+ (threads - 1).times { @queue.push nil }
12
+ return done
13
+ end
14
+
15
+ query = @queue.pop
16
+
17
+ # NOTE: trick to avoid dead lock
18
+ if query.nil?
19
+ terminate
9
20
  return done
10
21
  end
11
22
 
12
- query = queue.pop
13
23
  connect unless established?
14
24
 
15
25
  begin
16
- process query
26
+ logger.info "Processing #{query.object}"
27
+ query = process(query)
17
28
  query.success
29
+ logger.debug "Queue new #{query.children.size} queries"
30
+ query.children.each {|q| @queue << q }
18
31
  rescue
19
- logger.error $!.message
32
+ logger.error "#{$!.message} when processing #{query.object} for #{query.root.object}"
20
33
  query.fail
21
34
  end
22
35
 
23
- done << query
36
+ done << query if query.root?
24
37
  end
25
38
  end
26
39
 
27
40
 
28
41
  private
29
42
 
43
+ def cache(object, sources, &block)
44
+ @cache["#{object}:#{sources}"] ||= yield
45
+ end
46
+
30
47
  def execute(command)
31
48
  return if command.nil? || command == ''
32
49
 
33
- logger.debug "Executing: #{command}"
34
- connection.cmd(command).tap {|result| logger.debug "Returned: #{result}" }
50
+ logger.debug %(Executing "#{command}")
51
+ connection.cmd(command).tap {|result| logger.debug %(Got "#{result}") }
52
+ end
53
+
54
+ def last_thread_of?(threads)
55
+ Thread.list.reject(&:stop?).size == 1 && Thread.list.size == threads+1
56
+ end
57
+
58
+ def terminate
59
+ logger.info "No more queries"
60
+ close
35
61
  end
36
62
  end
37
63
  end
@@ -4,21 +4,64 @@ module Irrc
4
4
  #
5
5
  # object - IRR / Whois object to extract. (eg: as-set, route-set, aut-num object)
6
6
  def fork(object)
7
- Query.new(object, source: sources, protocol: protocols).tap {|q|
7
+ Query.new(object, source: @sources, protocol: @protocols).tap {|q|
8
8
  q.parent = self
9
- }
9
+ }.tap {|c| self.add_child c }
10
10
  end
11
11
 
12
12
  # Public: Returns the parent (associated) Query object, which is probably as-set.
13
13
  def parent
14
- @_parent
14
+ @parent
15
15
  end
16
16
 
17
17
  # Public: Set a parent (associated) Query object, which is probably as-set.
18
18
  #
19
19
  # parent - Parent Query object.
20
- def parent=(parent)
21
- @_parent = parent
20
+ def parent=(query)
21
+ @parent = query
22
+ end
23
+
24
+ # Public: Returns child Query objects
25
+ def children
26
+ @children ||= []
27
+ end
28
+
29
+ # Public: Add a child Query object
30
+ def add_child(query)
31
+ children << query
32
+ end
33
+
34
+ # Public: Delete a child Query object
35
+ def delete_child(query)
36
+ children.delete(query)
37
+ end
38
+
39
+ # Public: Returns the IRR object to query including those from ancestor query objects.
40
+ #
41
+ # Returns: Array of String.
42
+ def ancestor_objects
43
+ @_ancestor_objects ||= Array(parent && parent.ancestor_objects) << object
44
+ end
45
+
46
+ # Public: Returns the root IRR object of the nested query
47
+ #
48
+ # Returns: String.
49
+ def root
50
+ @_root ||= if parent
51
+ parent.root
52
+ else
53
+ self
54
+ end
55
+ end
56
+
57
+ # Public: Returns true if the query is root.
58
+ def root?
59
+ root == self
60
+ end
61
+
62
+ # Public: Returns true if object is listed in ancestor IRR objects.
63
+ def ancestor_object?(object)
64
+ ancestor_objects.include?(object)
22
65
  end
23
66
  end
24
67
  end
@@ -1,3 +1,3 @@
1
1
  module Irrc
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -20,68 +20,66 @@ module Irrc
20
20
  include Irrc::Runner
21
21
  include Irrc::Whoisd::Api
22
22
 
23
- attr_reader :host, :queue
24
-
25
23
 
26
24
  private
27
25
 
28
26
  def process(query)
29
27
  case query.object_type
30
28
  when 'as-set'
31
- query.add_aut_num_result objects_from_set(query, 'as-set')
32
- resolve_prefixes_from_aut_nums query
29
+ expand_set query, 'as-set'
33
30
  when 'route-set'
34
- resolve_prefixes_from_route_set query
31
+ expand_set query, 'route-set'
35
32
  when 'aut-num'
36
- query.add_aut_num_result query.object
37
- resolve_prefixes_from_aut_nums query
33
+ expand_aut_num query
38
34
  end
39
- end
40
35
 
41
- def objects_from_set(query, type)
42
- command = expand_set_command(query.object, query.sources, type)
43
- cache(query.object) {
44
- result = execute(command)
45
- parse_objects_from_set(result).map {|object|
46
- expand_if_necessary(query.fork(object), type)
47
- }.flatten.uniq.compact
48
- }
49
- rescue
50
- raise "'#{command}' failed on '#{host}' (#{$!.message})."
36
+ query
51
37
  end
52
38
 
53
- def expand_if_necessary(query, type)
54
- if query.object_type == type
55
- objects_from_set(query, type)
56
- else
57
- query.object
58
- end
59
- end
39
+ # Public: Expand an as-set or route-set object into any object.
40
+ def expand_set(query, type)
41
+ result = cache(query.object, query.sources) {
42
+ begin
43
+ command = expand_set_command(query.object, query.sources, type)
44
+ execute(command)
45
+ rescue
46
+ raise "'#{command}' failed on '#{@fqdn}' (#{$!.message})."
47
+ end
48
+ }
60
49
 
61
- def resolve_prefixes_from_route_set(query)
62
- prefixes = classify_by_protocol(objects_from_set(query, 'route-set'))
63
- query.protocols.each do |protocol|
64
- query.add_prefix_result prefixes[protocol], nil, protocol
65
- end
66
- end
50
+ parse_objects_from_set(result).each do |object|
51
+ next if query.ancestor_object?(object)
67
52
 
68
- def resolve_prefixes_from_aut_nums(query)
69
- unless query.protocols.empty?
70
- # ipv4 and ipv6 should have the same result so far
71
- (query.result[:ipv4] || query.result[:ipv6]).keys.each do |autnum|
72
- command = expand_aut_num_command(autnum, query.sources)
73
- result = execute(command)
53
+ child = query.fork(object)
74
54
 
55
+ case child.object_type
56
+ when 'aut-num'
57
+ query.add_aut_num_result object
58
+ when nil # it looks prefix which is a member of route-set
59
+ prefix = classify_by_protocol(object)
75
60
  query.protocols.each do |protocol|
76
- query.add_prefix_result parse_prefixes_from_aut_num(result, protocol), autnum, protocol
61
+ query.add_prefix_result prefix[protocol], nil, protocol
77
62
  end
78
63
  end
79
64
  end
80
65
  end
81
66
 
82
- def cache(object, &block)
83
- @_cache ||= {}
84
- @_cache[object] ||= yield
67
+ # Public: Expand an aut-num object into routes
68
+ def expand_aut_num(query)
69
+ return if query.protocols.empty?
70
+
71
+ result = cache(query.object, query.sources) {
72
+ begin
73
+ command = expand_aut_num_command(query.object, query.sources)
74
+ execute(command)
75
+ rescue
76
+ raise "'#{command}' failed on '#{@fqdn}' (#{$!.message})."
77
+ end
78
+ }
79
+
80
+ query.protocols.each do |protocol|
81
+ query.add_prefix_result parse_prefixes_from_aut_num(result, protocol), query.object, protocol
82
+ end
85
83
  end
86
84
  end
87
85
  end
metadata CHANGED
@@ -1,31 +1,59 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: irrc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shintaro Kojima
8
8
  autorequire:
9
- bindir: bin
9
+ bindir: exe
10
10
  cert_chain: []
11
- date: 2014-06-27 00:00:00.000000000 Z
11
+ date: 2017-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-telnet
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: bundler
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: '1.6'
33
+ version: '1.9'
20
34
  type: :development
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: '1.6'
40
+ version: '1.9'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
59
  - - ">="
@@ -56,12 +84,11 @@ files:
56
84
  - LICENSE
57
85
  - README.md
58
86
  - Rakefile
59
- - bin/irrc
87
+ - bin/console
88
+ - bin/setup
89
+ - exe/irrc
60
90
  - irrc.gemspec
61
91
  - lib/irrc.rb
62
- - lib/irrc/cli.rb
63
- - lib/irrc/cli/client.rb
64
- - lib/irrc/cli/yaml_printer.rb
65
92
  - lib/irrc/client.rb
66
93
  - lib/irrc/connecting.rb
67
94
  - lib/irrc/irr.rb
@@ -80,13 +107,6 @@ files:
80
107
  - lib/irrc/whoisd.rb
81
108
  - lib/irrc/whoisd/api.rb
82
109
  - lib/irrc/whoisd/client.rb
83
- - spec/features/irr_as_set_resolution_spec.rb
84
- - spec/features/irr_invalid_object_resolution_spec.rb
85
- - spec/features/whois_as_set_resolution_spec.rb
86
- - spec/features/whois_invalid_object_resolution_spec.rb
87
- - spec/spec_helper.rb
88
- - spec/support/contexts.rb
89
- - spec/support/query.rb
90
110
  homepage: https://github.com/codeout/irrc
91
111
  licenses:
92
112
  - MIT
@@ -99,7 +119,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
99
119
  requirements:
100
120
  - - ">="
101
121
  - !ruby/object:Gem::Version
102
- version: '0'
122
+ version: 2.0.0
103
123
  required_rubygems_version: !ruby/object:Gem::Requirement
104
124
  requirements:
105
125
  - - ">="
@@ -107,17 +127,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
127
  version: '0'
108
128
  requirements: []
109
129
  rubyforge_project:
110
- rubygems_version: 2.2.2
130
+ rubygems_version: 2.6.8
111
131
  signing_key:
112
132
  specification_version: 4
113
133
  summary: IRR / Whois client to expand as-set and route-set into a list of origin ASs
114
134
  and prefixes
115
- test_files:
116
- - spec/features/irr_as_set_resolution_spec.rb
117
- - spec/features/irr_invalid_object_resolution_spec.rb
118
- - spec/features/whois_as_set_resolution_spec.rb
119
- - spec/features/whois_invalid_object_resolution_spec.rb
120
- - spec/spec_helper.rb
121
- - spec/support/contexts.rb
122
- - spec/support/query.rb
123
- has_rdoc:
135
+ test_files: []