get_server_data 1.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d6a4fc3a1fa1e36268c55c984545b847bf679092
4
+ data.tar.gz: 19a9056ae273e2a1abdbf7fa20013e3e73939c30
5
+ SHA512:
6
+ metadata.gz: 4f681f56698668814dc5f150de67e857558feaa791baa920ec7dcc66ba45fc66fc64c5115517c179bfb1677e9409d61d9af7ea52c37be70998d0f9f7a3da34e9
7
+ data.tar.gz: 727403f4821c545eb6f8e217f9502e1700c6130ecd150c260ae6da6dde379f95a77666ce2ac3f7140c48125afdfa2b61c0dfbb16bec5e06614148b812e058b79
data/bin/gsd ADDED
@@ -0,0 +1,184 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Copyright (c) 2015, Sean Malloy
4
+ # All rights reserved.
5
+ #
6
+ # Redistribution and use in source and binary forms, with or without
7
+ # modification, are permitted provided that the following conditions are met:
8
+ #
9
+ # 1. Redistributions of source code must retain the above copyright
10
+ # notice, this list of conditions and the following disclaimer.
11
+ #
12
+ # 2. Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # 3. Neither the name of the copyright holder nor the names of its contributors
17
+ # may be used to endorse or promote products derived from this software without
18
+ # specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
21
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
22
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
26
+ # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27
+ # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+ require 'csv'
30
+ require 'get_server_data'
31
+ require 'json'
32
+ require 'resolv'
33
+ require 'table_print'
34
+ require 'thor'
35
+
36
+
37
+ class GetServerDataCli < Thor
38
+ class_option :format, :default => "text", :type => :string, :aliases => '-f',
39
+ :desc => "Use FORMAT as the output format. FORMAT can be one of csv, json, or text"
40
+ class_option :sort, :default => true, :type => :boolean, :aliases => '-s',
41
+ :desc => "Sort output by hostname"
42
+ class_option :unique, :default => true, :type => :boolean, :aliases => '-u',
43
+ :desc => "Remove duplicate hostnames"
44
+
45
+ def initialize(a, b, c)
46
+ super
47
+ @results = []
48
+
49
+ # validate --format option
50
+ if options[:format] != "csv" and options[:format] != "json" and options[:format] != "text"
51
+ puts "Invalid option: \"--format #{options[:format]}\""
52
+ puts ""
53
+ puts "Valid parameters for --format are: \"csv\" \"json\" \"text\""
54
+ exit 1
55
+ end
56
+ end
57
+
58
+ desc "dns [OPTION...] HOSTNAME...", "Get information about hosts from DNS"
59
+ long_desc <<-LONGDESC
60
+ Gets information from DNS for one or more hosts. Collects the IP address
61
+ and DNS record type.
62
+
63
+ $ gsd dns www.google.com
64
+ \x5$ gsd dns www.openbsd.org www.google.com
65
+ LONGDESC
66
+ def dns(*args)
67
+ hostnames = self.build_hostname_list(options[:unique], args)
68
+ threads = []
69
+ hostnames.each do |hostname|
70
+ threads << Thread.new {
71
+ server = ServerData.new(hostname)
72
+ @results << { :hostname => server.hostname, :ip => server.get_ip, :dns => server.get_dns_type }
73
+ }
74
+ end
75
+ threads.each { |thr| thr.join }
76
+
77
+ # display results
78
+ if options[:sort]
79
+ @results.sort! { |x,y| x[:hostname] <=> y[:hostname] }
80
+ end
81
+ self.print_results(options[:format])
82
+ end
83
+
84
+ desc "ping [OPTION...] HOSTNAME...", "Get information about hosts from ICMP(ping)"
85
+ long_desc <<-LONGDESC
86
+ Gets information from ICMP(ping) for one or more hosts. Collects the IP address
87
+ and ICMP pings the hosts.
88
+
89
+ $ gsd ping www.google.com
90
+ \x5$ gsd ping --timeout 3 www.google.com
91
+ \x5$ gsd ping www.openbsd.org www.google.com
92
+ LONGDESC
93
+ option :timeout, :default => 1, :type => :numeric, :aliases => '-t', :desc => "Set ICMP tiemout to N seconds"
94
+ def ping(*args)
95
+ hostnames = self.build_hostname_list(options[:unique], args)
96
+ threads = []
97
+ hostnames.each do |hostname|
98
+ threads << Thread.new {
99
+ server = ServerData.new(hostname)
100
+ @results << { :hostname => server.hostname, :ip => server.get_ip, :ping => server.ping }
101
+ }
102
+ end
103
+ threads.each { |thr| thr.join }
104
+
105
+ # display results
106
+ if options[:sort]
107
+ @results.sort! { |x,y| x[:hostname] <=> y[:hostname] }
108
+ end
109
+ self.print_results(options[:format])
110
+ end
111
+
112
+ desc "tcp [OPTION...] HOSTNAME...", "Get information about a TCP port for hosts"
113
+ long_desc <<-LONGDESC
114
+ Tests TCP port connection to one or more hosts. Collects the IP address
115
+ and tests TCP port connection to the hosts.
116
+
117
+ $ gsd tcp www.google.com
118
+ \x5$ gsd tcp --timeout 3 www.google.com
119
+ \x5$ gsd tcp --port 21 www.openbsd.org
120
+ LONGDESC
121
+ option :port, :default => 22, :type => :numeric, :aliases => '-p', :desc => "TCP port to test"
122
+ option :timeout, :default => 1, :type => :numeric, :aliases => '-t', :desc => "Set TCP timeout to N seconds"
123
+ def tcp(*args)
124
+ hostnames = self.build_hostname_list(options[:unique], args)
125
+ threads = []
126
+ hostnames.each do |hostname|
127
+ threads << Thread.new {
128
+ server = ServerData.new(hostname, options[:port])
129
+ @results << { :hostname => server.hostname, :ip => server.get_ip, :port => options[:port], :port_result => server.get_port_status }
130
+ }
131
+ end
132
+ threads.each { |thr| thr.join }
133
+
134
+ # display results
135
+ if options[:sort]
136
+ @results.sort! { |x,y| x[:hostname] <=> y[:hostname] }
137
+ end
138
+ self.print_results(options[:format])
139
+ end
140
+
141
+ protected
142
+ def print_results(format)
143
+ if !@results.empty?
144
+ if format == "csv"
145
+ puts @results[0].keys.to_csv
146
+ @results.each do |data|
147
+ puts data.values.to_csv
148
+ end
149
+ elsif format == "json"
150
+ puts @results.to_json
151
+ elsif format == "text"
152
+ tp @results
153
+ end
154
+ end
155
+ end
156
+
157
+ # Get hosts from command line
158
+ def build_hostname_list(unique, hosts)
159
+ hostnames = []
160
+ if $stdin.tty?
161
+ # reading hostnames from command line
162
+ hosts.each do |hostname|
163
+ hostnames.push(ServerData.to_hostname(hostname))
164
+ end
165
+ else
166
+ # reading hostnames from a pipe
167
+ STDIN.each do |hostname|
168
+ if hostname != "\n"
169
+ hostname.chomp!
170
+ hostnames.push(ServerData.to_hostname(hostname))
171
+ end
172
+ end
173
+ end
174
+
175
+ # remove duplicate hostnames
176
+ if unique
177
+ hostnames.uniq!
178
+ end
179
+ hostnames
180
+ end
181
+ end
182
+
183
+ GetServerDataCli.start(ARGV)
184
+
@@ -0,0 +1,158 @@
1
+ # Copyright (c) 2015, Sean Malloy
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ #
10
+ # 2. Redistributions in binary form must reproduce the above copyright
11
+ # notice, this list of conditions and the following disclaimer in the
12
+ # documentation and/or other materials provided with the distribution.
13
+ #
14
+ # 3. Neither the name of the copyright holder nor the names of its contributors
15
+ # may be used to endorse or promote products derived from this software without
16
+ # specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24
+ # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25
+ # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+
27
+ require 'net/ping'
28
+ require 'resolv'
29
+ require 'socket'
30
+ require 'timeout'
31
+
32
+ # Models server data (hostname, port, IP address, etc.)
33
+ class ServerData
34
+ # Create ServerData object
35
+ #
36
+ # @param h [String] hostname
37
+ # @param p [Integer] port number
38
+ def initialize(h, p = 22)
39
+ @dns_record_type = nil
40
+ @hostname = h
41
+ @ip = nil
42
+ @port = p
43
+ @ping_status = nil
44
+ @port_status = nil
45
+ end
46
+
47
+ # @!attribute [r] dns_record_type
48
+ # @return [String] dns record type, "A" or "CNAME"
49
+ attr_reader :dns_record_type
50
+
51
+ # @!attribute [r] hostname
52
+ # @return [String] hostname
53
+ attr_reader :hostname
54
+
55
+ # @!attribute [r] ip
56
+ # @return [String] IP address
57
+ attr_reader :ip
58
+
59
+ # @!attribute [r] port
60
+ # @return [Integer] port number
61
+ attr_reader :port
62
+
63
+ # @!attribute [r] ping_status
64
+ # @return [Boolean] result of ping test
65
+ attr_reader :ping_status
66
+
67
+ # @!attribute [r] port_status
68
+ # @return [Boolean] result of TCP port test
69
+ attr_reader :port_status
70
+
71
+ # Convert IP address to hostname
72
+ #
73
+ # @param input [String] IP address
74
+ # @return [String] hostname from DNS
75
+ def self.to_hostname(input)
76
+ if input =~ /^\d+\.\d+\.\d+.\d+$/
77
+ begin
78
+ return Resolv.getname(input)
79
+ rescue Resolv::ResolvError
80
+ return input
81
+ end
82
+ else
83
+ return input
84
+ end
85
+ end
86
+
87
+ # Check TCP port connectivity
88
+ #
89
+ # @param timeout [Integer] TCP timeout in seconds
90
+ # @return [Boolean] success for failure of TCP connection
91
+ def get_port_status(timeout = 1)
92
+ begin
93
+ Timeout::timeout(timeout) do
94
+ begin
95
+ s = TCPSocket.new(@hostname, @port)
96
+ s.close
97
+ return @port_status = true
98
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
99
+ return @port_status = false
100
+ end
101
+ end
102
+ rescue Timeout::Error
103
+ end
104
+ @port_status = false
105
+ end
106
+
107
+ # Lookup server IP from DNS
108
+ #
109
+ # @return [String] IP address of the server
110
+ def get_ip
111
+ begin
112
+ @ip = Resolv.getaddress(@hostname)
113
+ rescue Resolv::ResolvError
114
+ @ip = ""
115
+ end
116
+ @ip
117
+ end
118
+
119
+ # Lookup DNS record type
120
+ #
121
+ # @return [String] record type, "A" or "CNAME"
122
+ def get_dns_type
123
+ resolver = Resolv::DNS.new
124
+ begin
125
+ resolver.getresource(@hostname, Resolv::DNS::Resource::IN::CNAME)
126
+ rescue Resolv::ResolvError
127
+ # do nothing
128
+ else
129
+ @dns_record_type = 'CNAME'
130
+ end
131
+
132
+ if @dns_record_type.nil?
133
+ begin
134
+ resolver.getresource(@hostname, Resolv::DNS::Resource::IN::A)
135
+ rescue Resolv::ResolvError
136
+ @dns_record_type = ""
137
+ else
138
+ @dns_record_type = 'A'
139
+ end
140
+ end
141
+ @dns_record_type
142
+ end
143
+
144
+ # Check ICMP connectivity
145
+ #
146
+ # @param timeout [Integer] ICMP timeout in seconds
147
+ # @return [Boolean] success or failure of ICMP test
148
+ def ping(timeout = 1)
149
+ ping = Net::Ping::External.new(@hostname, 7, timeout)
150
+ if ping.ping.nil?
151
+ @ping_status = false
152
+ else
153
+ @ping_status = ping.ping
154
+ end
155
+ @ping_status
156
+ end
157
+ end
158
+
@@ -0,0 +1,148 @@
1
+ # Copyright (c) 2015, Sean Malloy
2
+ # All rights reserved.
3
+ #
4
+ # Redistribution and use in source and binary forms, with or without
5
+ # modification, are permitted provided that the following conditions are met:
6
+ #
7
+ # 1. Redistributions of source code must retain the above copyright
8
+ # notice, this list of conditions and the following disclaimer.
9
+ #
10
+ # 2. Redistributions in binary form must reproduce the above copyright
11
+ # notice, this list of conditions and the following disclaimer in the
12
+ # documentation and/or other materials provided with the distribution.
13
+ #
14
+ # 3. Neither the name of the copyright holder nor the names of its contributors
15
+ # may be used to endorse or promote products derived from this software without
16
+ # specific prior written permission.
17
+ #
18
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19
+ # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
+ # AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21
+ # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
+ # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+ # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24
+ # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25
+ # OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
+
27
+ require 'coveralls'
28
+ Coveralls.wear!
29
+
30
+ gem 'minitest'
31
+ require 'get_server_data'
32
+ require 'minitest/autorun'
33
+ require 'resolv'
34
+
35
+ class TestServerData < Minitest::Test
36
+ def setup
37
+ @server = ServerData.new('foohost.spmalloy.com')
38
+ end
39
+
40
+ def test_constructor
41
+ assert_instance_of ServerData, @server, 'ServerData.new creates instances of type ServerData'
42
+ assert_nil @server.dns_record_type, 'ServerData.new sets dns_record_type to nil'
43
+ assert_equal 'foohost.spmalloy.com', @server.hostname, 'ServerData.new sets hostsname'
44
+ assert_nil @server.ip, 'ServerData.new sets ip to nil'
45
+ assert_nil @server.ping_status, 'ServerData.new sets ping_status to nil'
46
+ assert_equal 22, @server.port, 'ServerData.new sets port to 22'
47
+ assert_nil @server.port_status, 'ServerData.new sets port_status to nil'
48
+
49
+ test_http_port = ServerData.new('foohost.spmalloy.com', 80)
50
+ assert_equal 80, test_http_port.port, 'ServerData.new can set port'
51
+ end
52
+
53
+ def test_method_hostname
54
+ assert_respond_to @server, 'hostname', 'ServerData instance responds to hostname'
55
+ end
56
+
57
+ def test_method_port
58
+ assert_respond_to @server, 'port', 'ServerData instance responds to port'
59
+ end
60
+
61
+ def test_method_port_status
62
+ assert_respond_to @server, 'port_status', 'ServerData instance responds to port_status'
63
+ assert_respond_to @server, 'get_port_status', 'ServerData instance responds to get_port_status'
64
+
65
+ # open port on a host that exists
66
+ host = ServerData.new('www.google.com', 80)
67
+ host.get_port_status
68
+ assert host.port_status, 'verify port 80 status to www.google.com'
69
+ assert host.get_port_status, 'verify get_port_status returns true'
70
+
71
+ # closed port on a host that exists
72
+ host = ServerData.new('www.google.com', 22)
73
+ host.get_port_status
74
+ refute host.port_status, 'verify port 22 status to www.google.com'
75
+ refute_nil host.port_status, 'verify port_status is not nil when connection fails'
76
+ refute host.get_port_status, 'verify get_port_status returns false'
77
+ refute_nil host.get_port_status, 'verify get_port_status return value is not nil when connection fails'
78
+
79
+ # host does not exist
80
+ @server.get_port_status
81
+ refute @server.port_status, 'verify port_status when connecting to host not in DNS'
82
+ refute_nil @server.port_status, 'verify port_status is not nil when connecting to host not in dns'
83
+ refute @server.get_port_status, 'verify get_port_status return value when connecting to host not in DNS'
84
+ refute_nil @server.get_port_status, 'verify get_port_status return value is not nil when connecting to host not in dns'
85
+ end
86
+
87
+ def test_method_ip
88
+ assert_respond_to @server, 'ip', 'ServerData instance responds to ip'
89
+ assert_respond_to @server, 'get_ip', 'ServerData instance responds to get_ip'
90
+
91
+
92
+ # hostname not in dns
93
+ assert_equal "", @server.get_ip, 'verify ip for a hostname not in dns'
94
+ refute_nil @server.ip, 'verify ip is not nil for a hostname not in dns'
95
+
96
+ # hostname in dns
97
+ host = ServerData.new('localhost', 80)
98
+ host.get_ip
99
+ refute_nil host.ip, 'verify ip for localhost'
100
+ assert(host.ip =~ Resolv::IPv4::Regex || host.ip =~ Resolv::IPv6::Regex, 'verify ip regex for localhost')
101
+ end
102
+
103
+ def test_method_dns_record_type
104
+ assert_respond_to @server, 'dns_record_type', 'ServerData instance responds to dns_record_type'
105
+ assert_respond_to @server, 'get_dns_type', 'ServerData instance responds to get_dns_type'
106
+
107
+ # hosts not in DNS will be false
108
+ @server.get_dns_type
109
+ assert_equal "", @server.dns_record_type, 'verify dns_record_type for host not in dns'
110
+ refute_nil @server.dns_record_type, 'verify dns_record_type is not nil for host not in dns'
111
+
112
+ # DNS A Record
113
+ arecord = ServerData.new('spmalloy.com', 22)
114
+ arecord.get_dns_type
115
+ assert_equal 'A', arecord.dns_record_type, 'verify dns_record_type for a dns A record'
116
+
117
+ # DNS CNAME
118
+ if ENV['TRAVIS_CI_BUILD']
119
+ skip 'skipping CNAME tests in Travis CI'
120
+ else
121
+ cname = ServerData.new('www.spmalloy.com', 22)
122
+ cname.get_dns_type
123
+ assert_equal 'CNAME', cname.dns_record_type, 'verify dns_record_type for a dns CNAME record'
124
+ end
125
+ end
126
+
127
+ def test_ping_status
128
+ assert_respond_to @server, 'ping_status', 'ServerData instance responds to ping_status'
129
+ assert_respond_to @server, 'ping', 'ServerData instance responds to ping'
130
+
131
+ # test result on a server not in dns
132
+ @server.get_ip
133
+ @server.ping
134
+ refute @server.ping_status, 'verify ping_status for host not in dns'
135
+ refute_nil @server.ping_status, 'verify ping_status is not nil for host not in dns'
136
+
137
+ # test result from successful ping
138
+ if ENV['TRAVIS_CI_BUILD']
139
+ skip 'skipping local ping_status test in Travis CI'
140
+ else
141
+ host = ServerData.new('localhost')
142
+ host.get_ip
143
+ host.ping
144
+ assert host.ping_status, 'verify ping_status for localhost'
145
+ end
146
+ end
147
+ end
148
+
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: get_server_data
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Sean Malloy
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: net-ping
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: table_print
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: thor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0.19'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0.19'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: coveralls
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.8'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.8'
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.5'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '5.5'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.4'
111
+ - !ruby/object:Gem::Dependency
112
+ name: travis-lint
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: yard
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: 0.8.7.6
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: 0.8.7.6
139
+ description: CLI tool to get server data from various sources
140
+ email: spinelli85@gmail.com
141
+ executables:
142
+ - gsd
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - bin/gsd
147
+ - lib/get_server_data.rb
148
+ - test/get_server_data_test.rb
149
+ homepage: https://github.com/seanmalloy/get-server-data
150
+ licenses:
151
+ - BSD
152
+ metadata: {}
153
+ post_install_message:
154
+ rdoc_options: []
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ requirements:
159
+ - - ">="
160
+ - !ruby/object:Gem::Version
161
+ version: 2.0.0
162
+ required_rubygems_version: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ requirements: []
168
+ rubyforge_project:
169
+ rubygems_version: 2.4.5
170
+ signing_key:
171
+ specification_version: 4
172
+ summary: Get Server Data
173
+ test_files: []
174
+ has_rdoc: