cloudscopes 0.12.5 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 13a8c1e4fd96446ee9cfb730470ffbd144b336a2
4
- data.tar.gz: e19c5195b89ffaf6cda0805183bf61e3a6129ac4
3
+ metadata.gz: e6ef807ce48549ff5ec29abbffb020286f8d84d2
4
+ data.tar.gz: 13d1f5b6a0dd963ec5a7d50efe83f91675ec2d02
5
5
  SHA512:
6
- metadata.gz: 211373e4fe776df95c5ac33283d43f85e4f579277e525d68ba039a0b22567215244aa6bf2c47e192b442bc0534ff667eb5cd6e07874dfc9076171ce9ae5eb8f6
7
- data.tar.gz: 94479bbf4b7456bcd4c4314d4200c215f0855e3bc93bd670c0ae469a32968597b781aa1cb58c6c66ed88b918c45e06b5ad615854f19802f0588c6a256ce0cdc2
6
+ metadata.gz: 1e5e7a073fe7b08efc38a4274aeed76ec32ccacbb5d8bc4ad029317803c79cf7d6c9377e1edd718ceb8c4483c7a17b9426d27adbc726908bc38370d77376a0b9
7
+ data.tar.gz: f5e5c085f530292011c610ff48979eff7dd0a4832b74faa865c2b1688978c60ae1d90b8f6656e3526c9f80f716bdeb66267aab956d4530731b2a9b049be759c2
data/.gitignore CHANGED
@@ -5,6 +5,7 @@
5
5
  /InstalledFiles
6
6
  /pkg/
7
7
  /spec/reports/
8
+ /spec/examples.state
8
9
  /test/tmp/
9
10
  /test/version_tmp/
10
11
  /tmp/
@@ -26,7 +27,7 @@ build/
26
27
 
27
28
  # for a library or gem, you might want to ignore these files since the code is
28
29
  # intended to run in multiple environments; otherwise, check them in:
29
- # Gemfile.lock
30
+ Gemfile.lock
30
31
  # .ruby-version
31
32
  # .ruby-gemset
32
33
 
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
@@ -0,0 +1,15 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2
4
+ - 2.3
5
+ script:
6
+ - bundle exec rspec spec
7
+ - bundle exec gem build cloudscopes.gemspec
8
+ deploy:
9
+ provider: rubygems
10
+ api_key:
11
+ secure: v7NKtzbY0rS/ulmTNhrvuDI/dWiqVkOR4uknO351QUGgKDuhc/FrD8mDe/d5aRv4WhZAUymamTihafchY+L6hXTst9OrAAsVx267vGN4PkCFzxF5tpVSr0MWG2FM4C3ZZC6Ud34BZDzFKUKvVUTMOMKrwBeCYRkg2G4SzvzbeXts6/ndI6D/qb38oHQb9nKG3UO9DnA3wMJdPFY0JKIkOuGCGSyBqrHQa+3XkKCbxqswv23vBbrHycj6HN5DIhwGy5vGpjkTr1OZ9t0tBrqNg8SYzjlvMbpJlwVVfyqECbuYCfEmJesHlPkS/Wz2n3eMzV50wUyQMQ5ZSYbyvh2DrcLb3snLYGITPgcJ887IhnJGAiCHPVZFvujStjZiKG2WNCkpQdjqGLKQdV20w9at+sp5KruM7bVEz86CoS3my3tjRHsLz83jYW78Y6fb3OMbQ/5ZlhtDge7xDWLDlo4M8hEyfGyTzTb0P7Y/nUvLsunPzbJTNAYp9bGXMuHcyO0DofCd+64H830FE01xCr5QFLVezJ+lpQKIb+gneUjUvVNdUcohlwLt+EZsxNOPiz3s1lbvYazz/gLpX58slzXglopBB574CxaEODn71p5+2rAqxv+yofsSxjRYFRLPw0GKhIpLZZZOaAwxzL3trEfvMTbEaXzvMxhkXvZqUEeVjp0=
12
+ gem: cloudscopes
13
+ on:
14
+ tags: true
15
+ repo: guss77/cloudscopes
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
11
11
  spec.summary = %q{Ruby gem to report system statistics to web based monitoring services such as CloudWatch}
12
12
  spec.description = %q{Ruby gem to report system statistics to web based monitoring services such as CloudWatch}
13
13
  spec.homepage = "http://github.com/guss77/cloudscopes"
14
- spec.license = "GPLv3"
14
+ spec.license = "GPL-3.0"
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
@@ -25,4 +25,5 @@ Gem::Specification.new do |spec|
25
25
 
26
26
  spec.add_development_dependency "bundler", "~> 1.6"
27
27
  spec.add_development_dependency "rake", '~> 0'
28
+ spec.add_development_dependency "rspec", '~> 3'
28
29
  end
@@ -2,14 +2,14 @@ settings:
2
2
  configdir: /etc/cloudscopes/monitor.d
3
3
  interval: 60
4
4
  provider: cloudwatch
5
- key: AWS_KEY_ID
6
- secret: AWS_SECRET_KEY
5
+ #key: AWS_KEY_ID
6
+ #secret: AWS_SECRET_KEY
7
7
  region: us-west-2
8
8
  dimensions:
9
9
  InstanceId: "#{ec2.availability_zone}.#{ec2.instance_id}"
10
10
 
11
11
  metrics:
12
- Systems:
12
+ Systems:
13
13
  - name: Load Per CPU
14
14
  unit: Percent
15
15
  value: 100 * system.loadavg5 / system.cpucount
@@ -26,16 +26,16 @@ metrics:
26
26
  unit: Count
27
27
  value: system.ps.select { |p| p.exe_name == 'myservice' }.size
28
28
 
29
- Queues:
29
+ Queues:
30
30
  - name: Pending Resque Items
31
31
  unit: Count
32
32
  value: redis.resque_size("some_queue")
33
33
  requires: system.service('redis-server')
34
-
34
+
35
35
  Services:
36
36
  - name: My service status
37
37
  value: if system.service('my-service') then 1 else 0 end
38
- requires: File.exists?('/usr/sbin/my-service')
38
+ requires: File.exists?('/usr/sbin/my-service')
39
39
  - name: Nginx Running
40
40
  value: if network.port_open?(80) then 1 else 0 end
41
41
  requires: File.exists?(Dir.glob("/etc/nginx/sites-enabled/*").first || "")
@@ -1,43 +1,32 @@
1
1
  module Cloudscopes
2
2
 
3
- attr_reader :should_publish, :usage_requested
4
-
5
- def self.init
6
- @opts = Cloudscopes::Options.new
7
- usage if usage_requested
8
- configuration = {}
9
- (@opts.files.empty?? [ STDIN ] : @opts.files.collect { |fn| File.new(fn) }).each do |configfile|
10
- configuration.merge! YAML.load(configfile.read)
3
+ class << self
4
+ def init
5
+ @opts = Cloudscopes::Options.new
6
+ configuration = {}
7
+ (@opts.files.empty?? [ STDIN ] : @opts.files.collect { |fn| File.new(fn) }).each do |configfile|
8
+ configuration.merge! YAML.load(configfile.read)
9
+ end
10
+ @settings = configuration['settings']
11
+ configuration['metrics']
11
12
  end
12
- @settings = configuration['settings']
13
- configuration['metrics']
14
- end
15
-
16
- def self.usage_requested
17
- @opts.usage
18
- end
19
13
 
20
- def self.should_publish
21
- @opts.publish != false
22
- end
23
-
24
- def self.usage
25
- puts "#{@opts}"
26
- exit 5
27
- end
14
+ def should_publish
15
+ @opts.publish
16
+ end
28
17
 
29
- def self.client
30
- @client ||= initClient
31
- end
18
+ def client
19
+ @client ||= initClient
20
+ end
32
21
 
33
- def self.initClient
34
- AWS::CloudWatch.new access_key_id: @settings['aws-key'],
35
- secret_access_key: @settings['aws-secret'],
36
- region: @settings['region']
37
- end
22
+ def initClient
23
+ AWS::CloudWatch.new access_key_id: @settings['aws-key'],
24
+ secret_access_key: @settings['aws-secret'],
25
+ region: @settings['region']
26
+ end
38
27
 
39
- def self.data_dimensions
40
- @settings['dimensions'] || ({ 'InstanceId' => '#{ec2.instance_id}' })
28
+ def data_dimensions
29
+ @settings['dimensions'] || ({ 'InstanceId' => '#{ec2.instance_id}' })
30
+ end
41
31
  end
42
-
43
- end
32
+ end
@@ -1,19 +1,34 @@
1
1
  require 'net/http'
2
2
 
3
3
  module Cloudscopes
4
-
4
+
5
5
  class Ec2
6
-
6
+
7
7
  @@baseurl = 'http://169.254.169.254/latest/meta-data'
8
-
8
+
9
+ HYPERVISOR_UUID_PATH = '/sys/hypervisor/uuid'.freeze
10
+ DMI_PRODUCT_UUID_PATH = '/sys/devices/virtual/dmi/id/product_uuid'.freeze
11
+
12
+ # see https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/identify_ec2_instances.html for
13
+ # details
14
+ def self.runs_on_ec2?
15
+ path =
16
+ if File.exists?(HYPERVISOR_UUID_PATH)
17
+ HYPERVISOR_UUID_PATH
18
+ elsif File.exists?(DMI_PRODUCT_UUID_PATH)
19
+ DMI_PRODUCT_UUID_PATH
20
+ end
21
+ !!path && File.read(path).downcase.start_with?('ec2')
22
+ end
23
+
9
24
  def instance_id
10
25
  @@instanceid ||= Net::HTTP.get(URI("#{@@baseurl}/instance-id"))
11
26
  end
12
-
27
+
13
28
  def availability_zone
14
29
  @@az ||= Net::HTTP.get(URI("#{@@baseurl}/placement/availability-zone"))
15
30
  end
16
-
31
+
17
32
  end
18
-
33
+
19
34
  end
@@ -1,5 +1,5 @@
1
1
  module Cloudscopes
2
-
2
+
3
3
  module StatFs
4
4
  # The result of a statfs operation, see "man statfs" for more information
5
5
  # on each field. We add some helper methods that deal in bytes.
@@ -8,13 +8,13 @@ module Cloudscopes
8
8
  def free; bfree * bsize; end
9
9
  def avail; bavail * bsize; end
10
10
  end
11
-
11
+
12
12
  module Lib
13
13
  extend FFI::Library
14
14
  ffi_lib FFI::Library::LIBC
15
15
  attach_function 'statfs64', [:string, :pointer], :int
16
16
  end
17
-
17
+
18
18
  # Drives the interface to the C library, returns a StatFs::Result object
19
19
  # to show filesystem information for the given path.
20
20
  #
@@ -29,19 +29,16 @@ module Cloudscopes
29
29
  end
30
30
  end
31
31
  end
32
-
32
+
33
33
  class Filesystem
34
-
35
- @@mountpoints = File.read("/proc/mounts").split("\n").grep(/(?:xv|s)d/).collect { |l| l.split(/\s+/)[1] }
36
-
37
34
  def mountpoints
38
- @@mountpoints
35
+ @@mountpoints ||=
36
+ File.read("/proc/mounts").split("\n").grep(/(?:xv|s)d/).collect { |l| l.split(/\s+/)[1] }
39
37
  end
40
-
38
+
41
39
  def df(path)
42
40
  StatFs.statfs(path)
43
41
  end
44
-
45
42
  end
46
43
 
47
44
  end
@@ -3,12 +3,14 @@
3
3
  #
4
4
 
5
5
  def publish(samples)
6
- raise "Not running in EC2, so won't publish!" unless File.executable?("/usr/bin/ec2metadata")
6
+ raise "Not running in EC2, so won't publish!" unless Cloudscopes::Ec2.runs_on_ec2?
7
7
  samples.each do |type,metric_samples|
8
8
  begin
9
9
  valid_data = metric_samples.select(&:valid)
10
10
  next if valid_data.empty?
11
- valid_data.each_slice(4) do |slice| # slice metrics to chunks - the actual limit is 20, but CloudWatch starts misbehaving if I put too much data
11
+ # slice metrics to chunks
12
+ # put_metric_data is limited to 40KB per POST request
13
+ valid_data.each_slice(4) do |slice|
12
14
  Cloudscopes.client.put_metric_data namespace: type,
13
15
  metric_data: slice.collect(&:to_cloudwatch_metric_data)
14
16
  end
@@ -1,22 +1,29 @@
1
1
  module Cloudscopes
2
-
3
2
  class Memory
3
+ def initialize
4
+ @@data ||= (
5
+ raw_meminfo = File.read('/proc/meminfo')
6
+ names_and_values = raw_meminfo.split("\n").
7
+ map {|line| line =~ /(\w+):\s+(\d+)/ and [$1, $2.to_i] }.compact
8
+ Hash[names_and_values]
9
+ )
10
+ end
4
11
 
5
- File.read('/proc/meminfo').split("\n").collect do |line|
6
- line =~ /(\w+):\s+(\d+)/ and { name: $1, value: $2.to_i }
7
- end.each do |data|
8
- next if data.nil?
9
- define_method(data[:name]) { data[:value] }
12
+ def method_missing(method, *args)
13
+ method_name = method.to_s
14
+ if @@data.include?(method_name)
15
+ @@data[method_name]
16
+ else
17
+ super
18
+ end
10
19
  end
11
-
20
+
12
21
  def MemAvailable
13
22
  return self.MemFree + self.Buffers + self.Cached
14
23
  end
15
-
24
+
16
25
  def MemUsed
17
26
  return self.MemTotal - self.MemFree - self.Buffers - self.Cached
18
27
  end
19
-
20
28
  end
21
-
22
29
  end
@@ -1,17 +1,20 @@
1
1
  module Cloudscopes
2
-
2
+
3
3
  class Options
4
4
 
5
- attr_reader :publish, :usage, :files
6
-
5
+ attr_reader :publish, :files
6
+
7
7
  def initialize
8
8
  @publish = true
9
9
  @files = OptionParser.new do |opts|
10
10
  opts.banner = "Usage: #{$0} [options] [<config.yaml>]\n\nOptions:"
11
11
  opts.on("-t", "dump samples to the console instead of publishing, for testing") { @publish = false }
12
- opts.on_tail("-?", "-h", "--help", "Show this message") { @usage = true }
12
+ opts.on_tail("-?", "-h", "--help", "Show this message") do
13
+ puts(opts)
14
+ exit
15
+ end
13
16
  end.parse!
14
17
  end
15
18
  end
16
-
19
+
17
20
  end
@@ -1,22 +1,20 @@
1
1
  require 'etc'
2
2
 
3
3
  module Cloudscopes
4
-
4
+
5
5
  class Process
6
-
6
+
7
7
  class SystemProcess
8
-
9
- @@maxpid = File.read('/proc/sys/kernel/pid_max').to_i
10
-
11
8
  def initialize(id)
12
9
  @id = id.to_i
10
+ @@maxpid ||= File.read('/proc/sys/kernel/pid_max').to_i
13
11
  raise "Invalid system process id #{id}" unless @id > 0 && @id < @@maxpid
14
12
  end
15
-
13
+
16
14
  def procpath(field = nil)
17
15
  "/proc/#{@id}/#{field}"
18
16
  end
19
-
17
+
20
18
  def method_missing(name, *args)
21
19
  raise ArgumentError.new("wrong number of arguments (#{args.length} for 0)") unless args.length == 0
22
20
  begin
@@ -28,7 +26,7 @@ module Cloudscopes
28
26
  ''
29
27
  end
30
28
  end
31
-
29
+
32
30
  def exe
33
31
  begin
34
32
  File.readlink(procpath('exe'))
@@ -39,11 +37,11 @@ module Cloudscopes
39
37
  ''
40
38
  end
41
39
  end
42
-
40
+
43
41
  def exe_name
44
42
  File.basename(exe)
45
43
  end
46
-
44
+
47
45
  def uid
48
46
  begin
49
47
  File.stat(procpath('mem')).uid
@@ -51,11 +49,11 @@ module Cloudscopes
51
49
  nil
52
50
  end
53
51
  end
54
-
52
+
55
53
  def user
56
54
  Etc.getpwuid(uid || 0).name
57
55
  end
58
-
56
+
59
57
  def mem_usage_rss
60
58
  statm.strip.split(/\s+/)[1].to_i * Etc.sysconf(Etc::SC_PAGESIZE)
61
59
  end
@@ -64,7 +62,7 @@ module Cloudscopes
64
62
  end
65
63
  alias mem_usage mem_usage_virt
66
64
  end
67
-
65
+
68
66
  def list
69
67
  list = Dir["/proc/[0-9]*[0-9]"].collect{|dir| SystemProcess.new(File.basename(dir).to_i) }
70
68
  list.define_singleton_method(:method_missing) do |name, *args|
@@ -72,7 +70,7 @@ module Cloudscopes
72
70
  when /^by_(.*)/
73
71
  field = $1.to_sym
74
72
  raise ArgumentError.new("wrong number of arguments (#{args.length} for 1)") unless args.length == 1
75
- select do |ps|
73
+ select do |ps|
76
74
  case ps.send(field)
77
75
  when args.first
78
76
  true
@@ -86,8 +84,8 @@ module Cloudscopes
86
84
  end
87
85
  list
88
86
  end
89
-
87
+
90
88
  end
91
-
89
+
92
90
  end
93
91
 
@@ -1,3 +1,3 @@
1
1
  module Cloudscopes
2
- VERSION = "0.12.5"
2
+ VERSION = "0.13.0"
3
3
  end
@@ -0,0 +1,21 @@
1
+ require 'cloudscopes'
2
+
3
+ RSpec.configure do |config|
4
+ config.expect_with :rspec do |expectations|
5
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
6
+ end
7
+
8
+ config.mock_with :rspec do |mocks|
9
+ mocks.verify_partial_doubles = true
10
+ end
11
+
12
+ config.shared_context_metadata_behavior = :apply_to_host_groups
13
+
14
+ config.disable_monkey_patching!
15
+ config.example_status_persistence_file_path = File.expand_path("../examples.state", __FILE__)
16
+ config.default_formatter = 'doc' if config.files_to_run.one?
17
+ config.order = :random
18
+ Kernel.srand(config.seed)
19
+ # uncomment for profiling slow examples
20
+ #config.profile_examples = 10
21
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudscopes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.5
4
+ version: 0.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Oded Arbel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-28 00:00:00.000000000 Z
11
+ date: 2017-07-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -72,6 +72,20 @@ dependencies:
72
72
  - - "~>"
73
73
  - !ruby/object:Gem::Version
74
74
  version: '0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: rspec
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '3'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '3'
75
89
  description: Ruby gem to report system statistics to web based monitoring services
76
90
  such as CloudWatch
77
91
  email:
@@ -86,6 +100,8 @@ files:
86
100
  - ".buildpath"
87
101
  - ".gitignore"
88
102
  - ".project"
103
+ - ".rspec"
104
+ - ".travis.yml"
89
105
  - Gemfile
90
106
  - LICENSE
91
107
  - README.md
@@ -108,9 +124,10 @@ files:
108
124
  - lib/cloudscopes/sample.rb
109
125
  - lib/cloudscopes/system.rb
110
126
  - lib/cloudscopes/version.rb
127
+ - spec/spec_helper.rb
111
128
  homepage: http://github.com/guss77/cloudscopes
112
129
  licenses:
113
- - GPLv3
130
+ - GPL-3.0
114
131
  metadata: {}
115
132
  post_install_message:
116
133
  rdoc_options: []
@@ -128,9 +145,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
145
  version: '0'
129
146
  requirements: []
130
147
  rubyforge_project:
131
- rubygems_version: 2.5.1
148
+ rubygems_version: 2.6.11
132
149
  signing_key:
133
150
  specification_version: 4
134
151
  summary: Ruby gem to report system statistics to web based monitoring services such
135
152
  as CloudWatch
136
- test_files: []
153
+ test_files:
154
+ - spec/spec_helper.rb