mackerel-client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 82cd57e63e053eb6b8b4fd8c0d89c4747fba5937
4
+ data.tar.gz: 0394eeecb9618458630f2520a7af71375a4c8d12
5
+ SHA512:
6
+ metadata.gz: 453706639f925b91cfe33bd3cba00f4d797f83ba5d9522e8f608d5b5e5f15b47dfb790fb34d9432f3c2905f807ef8ce3356f8880f3a558eb2c45722c24203e1f
7
+ data.tar.gz: a87577caee432f325600cfecf4cd6e934b6f228e62d126358bb5c6a2081bbd3a9a34ccd4b9f8e8928b2f654d3d28fbd1ba1bf44ac232e123322c308b970c3a78
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ /vendor/
2
+ *.gem
3
+ *.rbc
4
+ .bundle
5
+ .config
6
+ .yardoc
7
+ Gemfile.lock
8
+ InstalledFiles
9
+ _yardoc
10
+ coverage
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'faraday'
4
+
5
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,15 @@
1
+ This software is licensed under the Apache 2 license, quoted below.
2
+
3
+ Copyright 2014 Hatena
4
+
5
+ Licensed under the Apache License, Version 2.0 (the "License");
6
+ you may not use this file except in compliance with the License.
7
+ You may obtain a copy of the License at
8
+
9
+ http://www.apache.org/licenses/LICENSE-2.0
10
+
11
+ Unless required by applicable law or agreed to in writing, software
12
+ distributed under the License is distributed on an "AS IS" BASIS,
13
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ See the License for the specific language governing permissions and
15
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # Mackerel::Client
2
+
3
+ TODO: Write a gem description
4
+
5
+
6
+ # CLI
7
+
8
+ ## Host
9
+
10
+ * Get host(s) information from hostname or service, role.
11
+ ```
12
+ mkr host info [--name foo] [--service service] [--role role]
13
+ ```
14
+
15
+ * Set status of a host
16
+ ```
17
+ mkr host status --host-id foo --status working
18
+ ```
19
+
20
+ * Get status of a host (not implemented yet)
21
+ ```
22
+ mkr host status --host-id foo
23
+ ```
24
+
25
+ ## Authentication
26
+ ```
27
+ export MACKEREL_APIKEY=foobar
28
+ ```
29
+
30
+ ## reference
31
+ * http://docs.aws.amazon.com/cli/latest/userguide/cli-chap-welcome.html
32
+ * https://github.com/aws/aws-cli
33
+
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
data/bin/mkr ADDED
@@ -0,0 +1,7 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # mkr(1)
4
+
5
+ require 'mackerel'
6
+ Mackerel::Runner.execute(ARGV)
7
+
@@ -0,0 +1,97 @@
1
+ require 'faraday'
2
+ require 'uri'
3
+
4
+ require 'json' unless defined? ::JSON
5
+ require 'mackerel/host'
6
+
7
+ module Mackerel
8
+
9
+ class Client
10
+
11
+ def initialize(args = {})
12
+ @origin = args[:mackerel_origin] || 'https://mackerel.io'
13
+ @api_key = args[:mackerel_api_key]
14
+ end
15
+
16
+ def get_host(host_id)
17
+ client = http_client
18
+
19
+ response = client.get "/api/v0/hosts/#{host_id}" do |req|
20
+ req.headers['X-Api-Key'] = @api_key
21
+ end
22
+
23
+ unless response.success?
24
+ raise "GET /api/v0/hosts/#{host_id} faild: #{response.status}"
25
+ end
26
+
27
+ data = JSON.parse(response.body)
28
+ Host.new(data['host'])
29
+ end
30
+
31
+ def update_host_status(host_id, status)
32
+ unless [:standby, :working, :maintenance, :poweroff].include?(status.to_sym)
33
+ raise "no such status: #{status}"
34
+ end
35
+
36
+ client = http_client
37
+
38
+ response = client.post "/api/v0/hosts/#{host_id}/status" do |req|
39
+ req.headers['X-Api-Key'] = @api_key
40
+ req.headers['Content-Type'] = 'application/json'
41
+ req.body = { "status" => status }.to_json
42
+ end
43
+
44
+ unless response.success?
45
+ raise "POST /api/v0/hosts/#{host_id}/status faild: #{response.status}"
46
+ end
47
+
48
+ data = JSON.parse(response.body)
49
+ end
50
+
51
+ def post_metrics(metrics)
52
+ client = http_client
53
+
54
+ response = client.post '/api/v0/tsdb' do |req|
55
+ req.headers['X-Api-Key'] = @api_key
56
+ req.headers['Content-Type'] = 'application/json'
57
+ req.body = metrics.to_json
58
+ end
59
+
60
+ unless response.success?
61
+ raise "POST /api/v0/tsdb faild: #{response.status}"
62
+ end
63
+
64
+ data = JSON.parse(response.body)
65
+ end
66
+
67
+ def get_hosts(opts = {})
68
+ client = http_client
69
+
70
+ response = client.get '/api/v0/hosts.json' do |req|
71
+ req.headers['X-Api-Key'] = @api_key
72
+ req.params['service'] = opts[:service] if opts[:service]
73
+ req.params['role'] = opts[:roles] if opts[:roles]
74
+ req.params['name'] = opts[:name] if opts[:name]
75
+ end
76
+
77
+ unless response.success?
78
+ raise "GET /api/v0/hosts.json faild: #{response.status}"
79
+ end
80
+
81
+ data = JSON.parse(response.body)
82
+ data['hosts'].map{ |host_json| Host.new(host_json) }
83
+ end
84
+
85
+ private
86
+
87
+ def http_client
88
+ Faraday.new(:url => @origin) do |faraday|
89
+ faraday.response :logger if ENV['DEBUG']
90
+ faraday.adapter Faraday.default_adapter
91
+ faraday.options.params_encoder = Faraday::FlatParamsEncoder
92
+ end
93
+ end
94
+
95
+ end
96
+
97
+ end
@@ -0,0 +1,41 @@
1
+ module Mackerel
2
+
3
+ class Host
4
+
5
+ MACKEREL_INTERFACE_NAME_PATTERN = /^eth\d/
6
+ attr_accessor :name, :type, :status, :memo, :isRetired, :id, :createdAt, :roles, :interfaces
7
+
8
+ def initialize(args = {})
9
+ @hash = args
10
+ @name = args["name"]
11
+ @meta = args["meta"]
12
+ @type = args["type"]
13
+ @status = args["status"]
14
+ @memo = args["memo"]
15
+ @isRetired = args["isRetired"]
16
+ @id = args["id"]
17
+ @createdAt = args["createdAt"]
18
+ @roles = args["roles"]
19
+ @interfaces = args["interfaces"]
20
+ end
21
+
22
+ def ip_addr
23
+ interface = @interfaces.find do |i|
24
+ MACKEREL_INTERFACE_NAME_PATTERN === i['name']
25
+ end
26
+ interface['ipAddress'] if interface
27
+ end
28
+
29
+ def mac_addr
30
+ interface = @interfaces.find do |i|
31
+ MACKEREL_INTERFACE_NAME_PATTERN === i['name']
32
+ end
33
+ interface['macAddress'] if interface
34
+ end
35
+
36
+ def to_h
37
+ return @hash
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,103 @@
1
+ require 'optparse'
2
+ require 'json' unless defined? ::JSON
3
+
4
+ module Mackerel
5
+
6
+ class Runner
7
+ attr_reader :args
8
+
9
+ def initialize(args)
10
+
11
+ args.unshift 'help' if args.empty?
12
+
13
+ @args = args
14
+ cmd = args.shift
15
+
16
+ if Runner.method_defined?(cmd) and cmd != 'run'
17
+ send(cmd, args)
18
+ else
19
+ puts "Error: `#{cmd}` command not found.\n\n"
20
+ send('help', args)
21
+ abort
22
+ end
23
+ end
24
+
25
+ # Shortcut
26
+ def self.execute(args)
27
+ new(args)
28
+ end
29
+
30
+ def help(args)
31
+ puts <<-EOS
32
+ #{$0}: Command line interface for Mackerel (https://mackerel.io/).
33
+ Get host(s) information from hostname or service, role.
34
+ mkr host info [--name foo] [--service service] [--role role]
35
+
36
+ Set status of a host
37
+ mkr host status --host-id foo --status working
38
+
39
+ Authentication
40
+ API key must be set to the environment variable as follows.
41
+ export MACKEREL_APIKEY=foobar
42
+
43
+ EOS
44
+ end
45
+
46
+ # mkr host status --host-id foo
47
+ def host(args)
48
+ mc = Mackerel::Client.new(:mackerel_api_key => ENV['MACKEREL_APIKEY'])
49
+ params = {}
50
+ opt = OptionParser.new
51
+ opt.on('--host-id HOSTID'){|v| params[:hostid] = v }
52
+
53
+ cmd = args.shift
54
+ case cmd
55
+ when 'status'
56
+ opt.on('--status STATUS'){|v| params[:status] = v }
57
+ opt.parse!(args)
58
+ if params[:status]
59
+ begin
60
+ res = mc.update_host_status(params[:hostid], params[:status])
61
+ puts "Updated to '#{params[:status]}'"
62
+ rescue => msg
63
+ abort "Error: #{msg}"
64
+ end
65
+ else
66
+ begin
67
+ res = mc.get_hosts(:hostid => params[:hostid])[0]
68
+ puts "#{res.status}"
69
+ rescue => msg
70
+ abort "Error: #{msg}"
71
+ end
72
+
73
+ end
74
+
75
+ when 'info'
76
+ opt.on('--service SERVICE'){|v| params[:service] = v }
77
+ opt.on('--role ROLE') {|v| params[:role] = v }
78
+ opt.on('--name NAME') {|v| params[:name] = v }
79
+ opt.on('--host-id HOSTID') {|v| params[:hostId] = v }
80
+ opt.parse!(args)
81
+ begin
82
+ if params[:hostid]
83
+ res = [ mc.get_host(params[:hostId]) ]
84
+ else
85
+ res = mc.get_hosts(params)
86
+ end
87
+ rescue => msg
88
+ abort "Error: #{msg}"
89
+ end
90
+ res.each do |res|
91
+ puts <<-EOS
92
+ name: #{res.name}, status: #{res.status}, id: #{res.id}, roles: #{res.roles}
93
+ EOS
94
+ end
95
+ else
96
+ abort "Error: `#{command}` command not found for host."
97
+ end
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+
data/lib/mackerel.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'mackerel/client'
2
+ require 'mackerel/runner'
3
+
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "mackerel-client"
7
+ spec.version = File.read("VERSION").strip
8
+ spec.authors = ["Mackerel developer team"]
9
+ spec.email = ["developers@mackerel.io"]
10
+ spec.summary = 'Mackerel client implemented by Ruby.'
11
+ spec.description = 'Mackerel client is a library to access Mackerel (https://mackerel.io/). CLI tool `mkr` is also provided.'
12
+ spec.homepage = "https://mackerel.io/"
13
+ spec.license = "Apache 2"
14
+ spec.files = `git ls-files -z`.split("\x0")
15
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
17
+ spec.require_paths = ["lib"]
18
+
19
+ spec.add_dependency 'faraday', '~> 0.9'
20
+
21
+ spec.add_development_dependency "rake", '~> 0'
22
+ spec.add_development_dependency "bundler", "~> 1.5"
23
+ spec.add_development_dependency "rspec", '~> 2'
24
+ end
@@ -0,0 +1,197 @@
1
+ require 'mackerel'
2
+ require 'mackerel/host'
3
+ require 'json'
4
+
5
+ describe Mackerel::Client do
6
+ let(:api_key) { 'xxxxxxxx' }
7
+ let(:client) { Mackerel::Client.new(:mackerel_api_key => api_key) }
8
+
9
+ describe '#get_host' do
10
+ let(:stubbed_response) {
11
+ [
12
+ 200,
13
+ {},
14
+ JSON.dump({'host' => host.to_h})
15
+ ]
16
+ }
17
+
18
+ let(:test_client) {
19
+ Faraday.new do |builder|
20
+ builder.adapter :test do |stubs|
21
+ stubs.get(api_path) { stubbed_response }
22
+ end
23
+ end
24
+ }
25
+
26
+ let(:hostId) { '21obeF4PhZN' }
27
+
28
+ let(:api_path) { "/api/v0/hosts/#{hostId}" }
29
+
30
+ let(:host) {
31
+ Mackerel::Host.new(
32
+ 'name' => 'db001',
33
+ 'meta' => {
34
+ 'agent-name' => 'mackerel-agent/0.6.1',
35
+ 'agent-revision' => 'bc2f9f6',
36
+ 'agent-version' => '0.6.1',
37
+ },
38
+ 'type' => 'unknown',
39
+ 'status' => 'working',
40
+ 'memo' => 'test host',
41
+ 'isRetired' => false,
42
+ 'id' => hostId,
43
+ 'createdAt' => '1401291976',
44
+ 'roles' => [
45
+ 'mackerel' => ['db']
46
+ ],
47
+ 'interfaces' => [{
48
+ "ipAddress" => "10.0.0.1",
49
+ "macAddress" => "08:00:27:ce:08:3d",
50
+ "name" => "eth0"
51
+ }],
52
+ )
53
+ }
54
+
55
+ before do
56
+ allow(client).to receive(:http_client).and_return(test_client)
57
+ end
58
+
59
+ it "successfully find host" do
60
+ expect(client.get_host(hostId).to_h).to eq(host.to_h)
61
+ end
62
+ end
63
+
64
+ describe '#update_host_status' do
65
+ let(:stubbed_response) {
66
+ [
67
+ 200,
68
+ {},
69
+ JSON.dump(response_object)
70
+ ]
71
+ }
72
+
73
+ let(:test_client) {
74
+ Faraday.new do |builder|
75
+ builder.adapter :test do |stubs|
76
+ stubs.post(api_path) { stubbed_response }
77
+ end
78
+ end
79
+ }
80
+
81
+ let(:hostId) { '21obeF4PhZN' }
82
+
83
+ let(:api_path) { "/api/v0/hosts/#{hostId}/status" }
84
+
85
+ let(:response_object) {
86
+ { 'success' => true }
87
+ }
88
+
89
+ before do
90
+ allow(client).to receive(:http_client).and_return(test_client)
91
+ end
92
+
93
+ it "successfully update host status" do
94
+ expect(client.update_host_status(hostId, :maintenance)).to eq(response_object)
95
+ end
96
+ end
97
+
98
+ describe '#post_metrics' do
99
+ let(:stubbed_response) {
100
+ [
101
+ 200,
102
+ {},
103
+ JSON.dump(response_object)
104
+ ]
105
+ }
106
+
107
+ let(:test_client) {
108
+ Faraday.new do |builder|
109
+ builder.adapter :test do |stubs|
110
+ stubs.post(api_path) { stubbed_response }
111
+ end
112
+ end
113
+ }
114
+
115
+ let(:hostId) { '21obeF4PhZN' }
116
+
117
+ let(:api_path) { "/api/v0/tsdb" }
118
+
119
+ let(:response_object) {
120
+ { 'success' => true }
121
+ }
122
+
123
+ let(:metrics) { [
124
+ { 'hostId' => hostId, 'name' => 'custom.metrics.loadavg', 'time' => 1401537844, 'value' => 1.4 },
125
+ { 'hostId' => hostId, 'name' => 'custom.metrics.uptime', 'time' => 1401537844, 'value' => 500 },
126
+ ] }
127
+
128
+ before do
129
+ allow(client).to receive(:http_client).and_return(test_client)
130
+ end
131
+
132
+ it "successfully post metrics" do
133
+ expect(client.post_metrics(metrics)).to eq(response_object)
134
+ end
135
+ end
136
+
137
+ describe '#get_hosts' do
138
+ let(:stubbed_response) {
139
+ [
140
+ 200,
141
+ {},
142
+ JSON.dump({ 'hosts' => hosts.map(&:to_h) })
143
+ ]
144
+ }
145
+
146
+ let(:test_client) {
147
+ Faraday.new do |builder|
148
+ builder.adapter :test do |stubs|
149
+ stubs.get(api_path) { stubbed_response }
150
+ end
151
+ end
152
+ }
153
+
154
+ let(:hostId) { '21obeF4PhZN' }
155
+
156
+ let(:api_path) { "/api/v0/hosts.json" }
157
+
158
+ let(:hosts) {
159
+ [
160
+ Mackerel::Host.new(
161
+ 'name' => 'mackereldb001',
162
+ 'meta' => {
163
+ 'agent-name' => 'mackerel-agent/0.6.1',
164
+ 'agent-revision' => 'bc2f9f6',
165
+ 'agent-version' => '0.6.1',
166
+ },
167
+ 'type' => 'unknown',
168
+ 'status' => 'working',
169
+ 'memo' => 'test host',
170
+ 'isRetired' => false,
171
+ 'id' => hostId,
172
+ 'createdAt' => '1401291976',
173
+ 'roles' => [
174
+ 'mackerel' => ['db']
175
+ ],
176
+ 'interfaces' => [{
177
+ "ipAddress" => "10.0.0.1",
178
+ "macAddress" => "08:00:27:ce:08:3d",
179
+ "name" => "eth0"
180
+ }],
181
+ )
182
+ ]
183
+ }
184
+
185
+ let(:opts) {
186
+ { :service => 'mackerel', :roles => 'db' }
187
+ }
188
+
189
+ before do
190
+ allow(client).to receive(:http_client).and_return(test_client)
191
+ end
192
+
193
+ it "successfully get hosts" do
194
+ expect(client.get_hosts(opts).map(&:to_h)).to eq(hosts.map(&:to_h))
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'mackerel'
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mackerel-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mackerel developer team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-13 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.9'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.9'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
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: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.5'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2'
69
+ description: Mackerel client is a library to access Mackerel (https://mackerel.io/).
70
+ CLI tool `mkr` is also provided.
71
+ email:
72
+ - developers@mackerel.io
73
+ executables:
74
+ - mkr
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - ".gitignore"
79
+ - ".rspec"
80
+ - Gemfile
81
+ - LICENSE.txt
82
+ - README.md
83
+ - Rakefile
84
+ - VERSION
85
+ - bin/mkr
86
+ - lib/mackerel.rb
87
+ - lib/mackerel/client.rb
88
+ - lib/mackerel/host.rb
89
+ - lib/mackerel/runner.rb
90
+ - mackerel-client.gemspec
91
+ - spec/mackerel/client_spec.rb
92
+ - spec/spec_helper.rb
93
+ homepage: https://mackerel.io/
94
+ licenses:
95
+ - Apache 2
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.2.2
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Mackerel client implemented by Ruby.
117
+ test_files:
118
+ - spec/mackerel/client_spec.rb
119
+ - spec/spec_helper.rb