mackerel-client 0.0.1

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 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