cloudscopes 0.12.5 → 0.13.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.
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