irrc 0.1.0 → 0.2.0

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.
@@ -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: []