host_status 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.5.1
4
+ - 2.4.3
5
+ - 2.3.7
6
+ - 2.2.9
7
+ before_install: gem install bundler
@@ -0,0 +1,4 @@
1
+ --protected
2
+ --no-private
3
+ --embed-mixin ClassMethods
4
+ --embed-mixin Sym::Extensions::InstanceMethods
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in host_status.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Konstantin Gredeskoul
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,61 @@
1
+ [![Build Status](https://travis-ci.org/kigster/host_status.svg?branch=master)](https://travis-ci.org/kigster/host_status)
2
+
3
+ # HostStatus — Work In Progress...
4
+
5
+ This gem provides a consistent interface for a concept of a host or a container running a particular application. It expresses application throughput, error rate, response time, and host cpu/ram/disk metrics in a consistent way, while allowing various pluggable adapters to aquire the data.
6
+
7
+ For instance, a NewRelic adapter would query the run-time status of a given host using a REST API call.
8
+
9
+ An HAProxy adapter may attempt to connect to the haproxy stats port and fetch the data from there.
10
+
11
+ Once configured, the client of this gem should be able to reliably fetch various metrics about the host.
12
+
13
+ > **MOTIVATION**: This gem is motivated by a concept of a Canary Deployment, where it's important to be able to compare metrics of a "canary" host with new application code to that of the rest of the running servers.
14
+
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'host_status'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ Or install it yourself as:
29
+
30
+ $ gem install host_status
31
+
32
+ ## Usage
33
+
34
+ ```ruby
35
+ HostStatus.configure do |c|
36
+ c.adapters << :newrelic
37
+ end
38
+
39
+ HostStatus::NewRelic.configure do |c|
40
+ c.api_key = '092358902850934580'
41
+ end
42
+
43
+ ```
44
+
45
+ ## Development
46
+
47
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. Run `bundle exec host_status` to use the gem in this directory, ignoring other installed copies of this gem.
48
+
49
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version,
50
+ update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
51
+
52
+ ## Contributing
53
+
54
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kigster/host_status.
55
+
56
+
57
+ ## License
58
+
59
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
60
+
61
+
@@ -0,0 +1,38 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'yard'
4
+ require 'timeout'
5
+
6
+ def shell(*args)
7
+ puts "running: #{args.join(' ')}"
8
+ system(args.join(' '))
9
+ end
10
+
11
+ task :clean do
12
+ shell('rm -rf pkg/ tmp/ coverage/ doc/ ' )
13
+ end
14
+
15
+ task :gem => [:build] do
16
+ shell('gem install pkg/*')
17
+ end
18
+
19
+ task :permissions => [ :clean ] do
20
+ shell("chmod -v o+r,g+r * */* */*/* */*/*/* */*/*/*/* */*/*/*/*/*")
21
+ shell("find . -type d -exec chmod o+x,g+x {} \\;")
22
+ end
23
+
24
+ task :build => :permissions
25
+
26
+ YARD::Rake::YardocTask.new(:doc) do |t|
27
+ t.files = %w(lib/**/*.rb exe/*.rb - README.md LICENSE)
28
+ t.options.unshift('--title','Host Status')
29
+ t.after = ->() { exec('open doc/index.html') }
30
+ end
31
+
32
+ RSpec::Core::RakeTask.new(:spec)
33
+
34
+ task :default => :spec
35
+
36
+
37
+
38
+
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "host_status"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "host_status"
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'host_status/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'host_status'
8
+ spec.version = HostStatus::VERSION
9
+ spec.authors = ['Konstantin Gredeskoul']
10
+ spec.email = %w(kigster@gmail.com)
11
+
12
+ spec.summary = %q{A generalized interface for obtaining a status of an application running on a given host, intended to be used in Canary Deploys. Supports any number of backend adapters such as NewRelic.}
13
+ spec.description = %q{A generalized facade that aggregates metrics for a given host running a particular application using any number of adapters and plugins including third-party APIs.}
14
+ spec.homepage = 'https://github.com/kigster/host_status'
15
+ spec.license = 'MIT'
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = 'bin'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_dependency 'dry-configurable'
23
+ spec.add_dependency 'dry-types'
24
+ spec.add_dependency 'dry-struct'
25
+ spec.add_dependency 'activesupport', '> 3'
26
+
27
+ spec.add_dependency 'hashie'
28
+
29
+ spec.add_development_dependency 'bundler'
30
+ spec.add_development_dependency 'rake'
31
+ spec.add_development_dependency 'rspec'
32
+ spec.add_development_dependency 'rspec-its'
33
+ spec.add_development_dependency 'awesome_print'
34
+ end
@@ -0,0 +1,29 @@
1
+ require 'dry-configurable'
2
+ require 'logger'
3
+
4
+ module HostStatus
5
+ class << self
6
+ attr_accessor :debug
7
+ attr_writer :logger, :adapters
8
+
9
+ alias debug? debug
10
+
11
+ def log(lvl = :info, *messages)
12
+ messages.each { |m| logger.send(lvl, m) }
13
+ end
14
+
15
+ private
16
+
17
+ def logger
18
+ @logger ||= :Logger.new(STDOUT)
19
+ end
20
+ end
21
+
22
+ extend ::Dry::Configurable
23
+ setting :adapters, []
24
+ end
25
+
26
+ require_relative 'host_status/version'
27
+ require_relative 'host_status/types'
28
+ require_relative 'host_status/host'
29
+
@@ -0,0 +1,44 @@
1
+ require 'dry-struct'
2
+ require 'host_status/types'
3
+
4
+ module HostStatus
5
+ class Application < Dry::Struct
6
+ transform_keys(&:to_sym)
7
+
8
+ attribute :name, HostStatus::Types::Strict::String
9
+ attribute :id, Types::Optional
10
+ attribute :url, Types::Url
11
+ attribute :api_url, Types::Url
12
+ attribute :language, Types::Optional
13
+ attribute :process_count, Types::Count
14
+ attribute :online, Types::IsUp
15
+
16
+ # all numbers are per minute
17
+ attribute :errors, Types::RatePerMinute
18
+ attribute :throughput, Types::RatePerMinute
19
+ attribute :latency_p50, Types::RatePerMinute
20
+ attribute :latency_p90, Types::RatePerMinute
21
+
22
+ class Proxy
23
+ attr_accessor :app
24
+
25
+ def initialize(**opts, &block)
26
+ options = transform_arguments(**opts)
27
+ self.app = Application.new(**options, &block)
28
+ end
29
+
30
+ def method_missing(method, *args, &block)
31
+ if app&.respond_to?(method)
32
+ app&.send(method, *args, &block)
33
+ else
34
+ super(method, *args, &block)
35
+ end
36
+ end
37
+
38
+ def transform_arguments(**opts)
39
+ opts
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,29 @@
1
+ require 'dry-struct'
2
+ require 'dry-types'
3
+ require 'host_status/types'
4
+ require 'host_status/application'
5
+ require 'host_status/resources'
6
+
7
+ module HostStatus
8
+ # {
9
+ # "id": 90952626,
10
+ # "application_name": "G3 Homebase Production",
11
+ # "host": "crn001-a.prod.homebase.systems",
12
+ # "language": "ruby",
13
+ # "health_status": "green",
14
+ # "application_summary": {
15
+ # "response_time": 0,
16
+ # "throughput": 0,
17
+ # "error_rate": 0,
18
+ # "apdex_score": null,
19
+ # "instance_count": 3
20
+ # },
21
+ #
22
+ class Host < ::Dry::Struct
23
+ attribute :name, HostStatus::Types::Strict::String
24
+ attribute :id, HostStatus::Types::Strict::String.optional
25
+ attribute :resources, HostStatus::Resources
26
+ attribute :applications, Types::Strict::Array.of(HostStatus::Application).default([])
27
+ end
28
+ end
29
+
@@ -0,0 +1,8 @@
1
+ require 'dry-configurable'
2
+
3
+ module HostStatus
4
+ module NewRelic
5
+ extend Dry::Configurable
6
+ setting :api_key, ENV['NEWRELIC_API_KEY'], required: true
7
+ end
8
+ end
@@ -0,0 +1,26 @@
1
+ require 'hashie'
2
+ require 'dry-struct'
3
+ require 'host_status/types'
4
+ require 'host_status/application'
5
+
6
+ module HostStatus
7
+ module NewRelic
8
+ class APM < ::HostStatus::Application::Proxy
9
+ DEFAULTS = {
10
+ response_time: nil,
11
+ error_rate: nil,
12
+ instance_count: nil,
13
+ apdex_score: nil,
14
+ }.freeze
15
+
16
+ def transform_arguments(**opts)
17
+ Hashie::Extensions::SymbolizeKeys.symbolize_keys!(opts)
18
+ options = DEFAULTS.merge(opts)
19
+ options[:latency_p50] = options.delete(:response_time)
20
+ options[:errors] = options.delete(:error_rate)
21
+ options[:process_count] = options.delete(:instance_count)
22
+ options
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,18 @@
1
+ require 'dry-struct'
2
+ require 'host_status/types'
3
+ require 'host_status/application'
4
+
5
+ module HostStatus
6
+ class Resources < ::Dry::Struct
7
+ attribute :pct_cpu_free, HostStatus::Types::Percent.optional
8
+ attribute :pct_ram_free, HostStatus::Types::Percent.optional
9
+ attribute :pct_disk_free, HostStatus::Types::Percent.optional
10
+
11
+ # all sizes are in Megabytes
12
+ attribute :mb_ram_free, HostStatus::Types::Megabyte.optional
13
+ attribute :mb_ram_total, HostStatus::Types::Megabyte.optional
14
+ attribute :mb_disk_free, HostStatus::Types::Megabyte.optional
15
+ attribute :mb_disk_total, HostStatus::Types::Megabyte.optional
16
+ end
17
+ end
18
+
@@ -0,0 +1,14 @@
1
+ require 'dry-types'
2
+ module HostStatus
3
+ module Types
4
+ include ::Dry::Types.module
5
+
6
+ Optional = String.optional.default(nil)
7
+ Url = String.optional.default(nil).constrained format: URI::regexp(%w(http https))
8
+ Percent = Coercible::Float.optional.constrained gteq: 0.0, lteq: 100.0
9
+ Megabyte = Coercible::Float.optional
10
+ RatePerMinute = Coercible::Float.optional.default(nil).constrained gteq: 0.0
11
+ IsUp = Bool.optional.default(nil)
12
+ Count = Coercible::Integer.optional.default(nil).constrained gteq: 0
13
+ end
14
+ end
@@ -0,0 +1,3 @@
1
+ module HostStatus
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,209 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: host_status
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Konstantin Gredeskoul
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-09-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: dry-configurable
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'
27
+ - !ruby/object:Gem::Dependency
28
+ name: dry-types
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-struct
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">"
60
+ - !ruby/object:Gem::Version
61
+ version: '3'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">"
67
+ - !ruby/object:Gem::Version
68
+ version: '3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: hashie
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: bundler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rspec-its
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: awesome_print
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: A generalized facade that aggregates metrics for a given host running
154
+ a particular application using any number of adapters and plugins including third-party
155
+ APIs.
156
+ email:
157
+ - kigster@gmail.com
158
+ executables: []
159
+ extensions: []
160
+ extra_rdoc_files: []
161
+ files:
162
+ - ".gitignore"
163
+ - ".rspec"
164
+ - ".rubocop.yml"
165
+ - ".travis.yml"
166
+ - ".yardopts"
167
+ - Gemfile
168
+ - LICENSE
169
+ - README.md
170
+ - Rakefile
171
+ - bin/console
172
+ - bin/host_status
173
+ - bin/setup
174
+ - host_status.gemspec
175
+ - lib/host_status.rb
176
+ - lib/host_status/application.rb
177
+ - lib/host_status/host.rb
178
+ - lib/host_status/new_relic.rb
179
+ - lib/host_status/new_relic/apm.rb
180
+ - lib/host_status/resources.rb
181
+ - lib/host_status/types.rb
182
+ - lib/host_status/version.rb
183
+ homepage: https://github.com/kigster/host_status
184
+ licenses:
185
+ - MIT
186
+ metadata: {}
187
+ post_install_message:
188
+ rdoc_options: []
189
+ require_paths:
190
+ - lib
191
+ required_ruby_version: !ruby/object:Gem::Requirement
192
+ requirements:
193
+ - - ">="
194
+ - !ruby/object:Gem::Version
195
+ version: '0'
196
+ required_rubygems_version: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ requirements: []
202
+ rubyforge_project:
203
+ rubygems_version: 2.6.14
204
+ signing_key:
205
+ specification_version: 4
206
+ summary: A generalized interface for obtaining a status of an application running
207
+ on a given host, intended to be used in Canary Deploys. Supports any number of backend
208
+ adapters such as NewRelic.
209
+ test_files: []