librato 0.0.4

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: 1707f2f2a1bbbff7b5f2a67486d95cc5ef8d4ef5
4
+ data.tar.gz: fd26e6fca1abaaebe9e5e3e8dd72d86e04b3791b
5
+ SHA512:
6
+ metadata.gz: 7067d0df4a6666860a88be476bc3ad680fb3f8cf41a47635ecd1af5f8d0b5bfac122f6a46e4e8375ccaefc8803ade6dfd7b18170f8580f0e500dfd1249148c9d
7
+ data.tar.gz: dfc753a3f123bf03490374b0f35c8ff41194703c34f313c6f7b5b7ec78a87c7544504315ba8be1eb95f5a83cc645f641bc9a48c06308e4cbf71c9223e790c01a
data/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT LICENSE
2
+
3
+ Copyright (c) Sven Fuchs <me@svenfuchs.com>
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.
data/README.md ADDED
@@ -0,0 +1,73 @@
1
+ # Librato Sync
2
+
3
+ Minimalistic library that does two things:
4
+
5
+ * Pull a space from a Librato account, and store JSON data in a local
6
+ directory.
7
+ * Push the space to a Librato account, from the JSON data stored locally.
8
+
9
+ I use this for these purposes:
10
+
11
+ * Fetch a space, review its definition for inconsistencies, edit it locally,
12
+ and push it back up to Librato.
13
+ * Fetch a space from one account, and push a copy of it to another account.
14
+ * Copy charts from one space to another, and edit definitions locally.
15
+
16
+ Uses a config file `.librato.yml` if present. The config file name, and the
17
+ data directory can be specified as command line options.
18
+
19
+ Usage:
20
+
21
+ ```
22
+ $ librato pull [account]
23
+ $ librato pull [account] --space "Space 1" --space "Space 2" --config librato.yml --dir ./librato
24
+ $ librato push [account]
25
+ $ librato push [account] --space "Space 1" --space "Space 2" --config librato.yml --dir ./librato
26
+ ```
27
+
28
+ Account credentials (user/email and token) can be be included in the config
29
+ file, or set as env vars per account:
30
+
31
+ ```
32
+ export LIBRATO_USER_ACCOUNT_1=[email]
33
+ export LIBRATO_TOKEN_ACCOUNT_1=[token]
34
+ ```
35
+
36
+ The Librato API returns charts in an unordered fashion. You can work around
37
+ this by specifying a chart order in the config file.
38
+
39
+ Certain keys and names will be uniq to one account, and need to be changed for
40
+ another account. Account configuration can therefor specify variable names and
41
+ values. Variable names will be replaced with the value specific to the account
42
+ when pushing a space to an account.
43
+
44
+ A full config file has this structure. Each bit of configuration is optional,
45
+ but the chart order and template vars cannot be specified via command line
46
+ options.
47
+
48
+ ```
49
+ dir: ./var/librato
50
+
51
+ spaces:
52
+ -
53
+ name: Space 1
54
+ order:
55
+ - chart_1
56
+ - chart_2
57
+ - chart_3
58
+
59
+ accounts:
60
+ name_1:
61
+ user: user_1@email.com
62
+ token: token_1
63
+ vars:
64
+ app: app_1
65
+ db_name: foo
66
+
67
+ name_2:
68
+ user: user_2@email.com
69
+ token: token_2
70
+ vars:
71
+ app: app_2
72
+ db_name: bar
73
+ ```
data/bin/librato ADDED
@@ -0,0 +1,37 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $: << File.expand_path('../../lib', __FILE__)
4
+
5
+ require 'librato'
6
+ require 'optparse'
7
+
8
+ def usage(msg)
9
+ puts msg
10
+ puts 'Usage: librato [pull|push] ACCOUNT'
11
+ exit
12
+ end
13
+
14
+ action, account = ARGV.shift, ARGV.shift
15
+ usage("Unknown action: #{action}") if !['pull', 'push'].include?(action) || account.nil?
16
+
17
+ def options(options = {})
18
+ OptionParser.new do |o|
19
+ o.on('-c', '--config FILE', 'Config file (default: ./.librato.yml)') do |config|
20
+ options[:config] = config
21
+ end
22
+
23
+ o.on('-d', '--dir DIR', 'Data directory (default: ./var/librato)') do |dir|
24
+ options[:dir] = dir
25
+ end
26
+
27
+ o.on('-s', '--space SPACE', 'Space name') do |space|
28
+ options[:spaces] ||= []
29
+ options[:spaces] << space
30
+ end
31
+ end.parse!(ARGV)
32
+
33
+ options
34
+ end
35
+
36
+ librato = Librato::Cli.new(account, options)
37
+ librato.send(action)
@@ -0,0 +1,21 @@
1
+ class Hash
2
+ EXCEPT = ->(object, *keys) do
3
+ case object
4
+ when Hash
5
+ object.inject({}) { |hash, (k, v)| keys.include?(k) ? hash : hash.merge(k => EXCEPT.call(v, *keys)) }
6
+ when Array
7
+ object.map { |object| EXCEPT.call(object, *keys) }
8
+ else
9
+ object
10
+ end
11
+ end
12
+
13
+ def deep_except(*keys)
14
+ EXCEPT.call(self, *keys)
15
+ end
16
+
17
+ def symbolize_keys
18
+ inject({}) { |hash, (k, v)| hash.merge(k.to_sym => v) }
19
+ end
20
+ end
21
+
data/lib/librato.rb ADDED
@@ -0,0 +1 @@
1
+ require 'librato/cli'
@@ -0,0 +1,31 @@
1
+ module Librato
2
+ class Chart < Struct.new(:client, :space, :data)
3
+ def id
4
+ data['id'] ||= find_id
5
+ end
6
+
7
+ def name
8
+ data['name']
9
+ end
10
+
11
+ def push
12
+ client.post(space.path, data)
13
+ end
14
+
15
+ def delete
16
+ client.delete(path)
17
+ end
18
+
19
+ private
20
+
21
+ def path
22
+ "/v1/spaces/#{space.id}/charts/#{id}"
23
+ end
24
+
25
+ def find_id
26
+ chart = space.charts.detect { |chart| chart.name == name }
27
+ chart || fail("Can't find chart")
28
+ chart.id
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,37 @@
1
+ require 'librato/client'
2
+ require 'librato/config'
3
+ require 'librato/spaces'
4
+
5
+ module Librato
6
+ class Cli < Struct.new(:account, :options)
7
+ require 'librato/cli/command'
8
+ require 'librato/cli/pull'
9
+ require 'librato/cli/push'
10
+
11
+ def pull
12
+ spaces.each do |space|
13
+ Pull.new(client, account, space, config).run
14
+ end
15
+ end
16
+
17
+ def push
18
+ spaces.each do |space|
19
+ Push.new(client, account, space, config).run
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def spaces
26
+ @spaces ||= Spaces.new(client, account).find_all(config.spaces)
27
+ end
28
+
29
+ def client
30
+ Client.new(*config.account(account).values_at('user', 'token'))
31
+ end
32
+
33
+ def config
34
+ @config ||= Config.new(options)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ require 'librato/store'
2
+
3
+ module Librato
4
+ class Cli
5
+ class Command < Struct.new(:client, :account, :space, :config)
6
+ def store
7
+ Store.new(space, dir: config['dir'], vars: config.account(account)['vars'])
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ module Librato
2
+ class Cli
3
+ class Pull < Command
4
+ def run
5
+ clear_charts
6
+ write_charts
7
+ end
8
+
9
+ private
10
+
11
+ def clear_charts
12
+ store.clear
13
+ end
14
+
15
+ def write_charts
16
+ space.charts.each do |chart|
17
+ store.write(chart.data)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,28 @@
1
+ require 'librato/chart'
2
+
3
+ module Librato
4
+ class Cli
5
+ class Push < Command
6
+ def run
7
+ remove_charts
8
+ push_charts
9
+ end
10
+
11
+ private
12
+
13
+ def remove_charts
14
+ space.charts.each do |chart|
15
+ puts "Removing existing chart #{chart.name.inspect} on #{account}"
16
+ Chart.new(client, space, chart.data).delete
17
+ end
18
+ end
19
+
20
+ def push_charts
21
+ store.read.each do |data|
22
+ puts "Pushing chart #{data['name'].inspect} to #{account}."
23
+ Chart.new(client, space, data).push
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,30 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module Librato
5
+ class Client < Struct.new(:user, :token)
6
+ HOST = 'https://metrics-api.librato.com'
7
+
8
+ [:get, :put, :post, :delete].each do |method|
9
+ define_method(method) { |*args| request(method, *args) }
10
+ end
11
+
12
+ private
13
+
14
+ def request(method, path, data = nil)
15
+ # puts "#{method.to_s.upcase} #{path}"
16
+ args = [method, path]
17
+ args << JSON.dump(data) if data
18
+ response = client.send(*args) { |r| r.headers['Content-Type'] = 'application/json' }
19
+ fail "#{response.status} #{response.body}" if response.status >= 299
20
+ response
21
+ end
22
+
23
+ def client
24
+ Faraday.new(HOST) do |c|
25
+ c.basic_auth(user, token)
26
+ c.use Faraday::Adapter::NetHttp
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,56 @@
1
+ require 'yaml'
2
+
3
+ module Librato
4
+ class Config < Struct.new(:options)
5
+ def [](key)
6
+ data[key]
7
+ end
8
+
9
+ def spaces
10
+ spaces = options[:spaces] || data['spaces'] || []
11
+ spaces.map { |space| space.is_a?(Hash) ? space : { 'name' => space } }
12
+ end
13
+
14
+ def account(name)
15
+ env(name).merge(accounts[name] || {}).tap do |account|
16
+ validate(account, name)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def data
23
+ @data ||= read.tap do |data|
24
+ data['dir'] = options[:dir] if options[:dir]
25
+ end
26
+ end
27
+
28
+ def read
29
+ File.exist?(path) ? YAML.load_file(path) : {}
30
+ end
31
+
32
+ def path
33
+ options[:config] || '.librato.yml'
34
+ end
35
+
36
+ def accounts
37
+ data['accounts'] || {}
38
+ end
39
+
40
+ def env(name)
41
+ { 'user' => var(:user, name), 'token' => var(:token, name) }
42
+ end
43
+
44
+ def var(account, name)
45
+ ENV["LIBRATO_#{account.upcase}_#{name.upcase}"]
46
+ end
47
+
48
+ def validate(account, name)
49
+ %w(user token).each { |key| validate_presence(account, name, key) }
50
+ end
51
+
52
+ def validate_presence(hash, name, key)
53
+ hash[key] || fail("Unknown #{key} for #{name}.")
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,28 @@
1
+ require 'json'
2
+ require 'librato/chart'
3
+
4
+ module Librato
5
+ class Space < Struct.new(:client, :data, :config)
6
+ def id
7
+ data['id'] || fail("Unknown id: #{data}")
8
+ end
9
+
10
+ def name
11
+ data['name']
12
+ end
13
+
14
+ def charts
15
+ @charts ||= fetch.map { |data| Chart.new(client, self, data) }
16
+ end
17
+
18
+ def path
19
+ "/v1/spaces/#{data['id']}/charts"
20
+ end
21
+
22
+ private
23
+
24
+ def fetch
25
+ JSON.parse(client.get(path).body)
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,37 @@
1
+ require 'json'
2
+ require 'librato/space'
3
+
4
+ module Librato
5
+ class Spaces < Struct.new(:client, :account)
6
+ def find_all(config)
7
+ config.map do |config|
8
+ find(config['name']).tap { |space| space.config = config }
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def all
15
+ @all ||= fetch['spaces'].map do |data|
16
+ Space.new(client, normalize(data))
17
+ end
18
+ end
19
+
20
+ def find(name)
21
+ space = all.detect { |space| space.name == name }
22
+ space || fail("Could not find space #{name}")
23
+ end
24
+
25
+ def fetch
26
+ JSON.parse(client.get(path).body)
27
+ end
28
+
29
+ def path
30
+ '/v1/spaces'
31
+ end
32
+
33
+ def normalize(data)
34
+ data.merge('name' => data['name'].sub(/\s*\(#{account}\)\s*/, ''))
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,55 @@
1
+ require 'fileutils'
2
+ require 'json'
3
+ require 'core_ext/hash'
4
+ require 'librato/template'
5
+
6
+ module Librato
7
+ class Store < Struct.new(:space, :options)
8
+ def clear
9
+ puts "Clearing existing chart data in #{dir}."
10
+ FileUtils.rm_r(dir) if File.directory?(dir)
11
+ end
12
+
13
+ def write(chart)
14
+ FileUtils.mkdir_p(dir)
15
+ json = JSON.pretty_generate(chart.deep_except('id'))
16
+ tmpl = Template.new(json, vars).generate
17
+ path = path(chart['name'])
18
+ puts "Storing chart data to #{path}."
19
+ File.open(path, 'w+') { |f| f.write(tmpl) }
20
+ end
21
+
22
+ def read
23
+ puts "Reading chart data from #{dir}."
24
+ Dir["#{dir}/*.json"].sort.map do |path|
25
+ tmpl = File.read(path)
26
+ json = Template.new(tmpl, vars).render
27
+ JSON.parse(json)
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def path(name)
34
+ name = name.gsub(/[\W]+/, ' ').downcase.strip.gsub(' ', '_')
35
+ num = order.index(name) || 0
36
+ path = "#{dir}/#{num.to_s.rjust(2, '0')}_chart_#{name}.json"
37
+ end
38
+
39
+ def order
40
+ space.config['order'] || []
41
+ end
42
+
43
+ def vars
44
+ options[:vars] || {}
45
+ end
46
+
47
+ def dir
48
+ [options[:dir] || './var/librato', dir_name(space.name)].join('/')
49
+ end
50
+
51
+ def dir_name(string)
52
+ string.gsub(/[\W]/, ' ').strip.gsub(' ', ' ').gsub(' ', '_').downcase
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,13 @@
1
+ module Librato
2
+ class Template < Struct.new(:string, :vars)
3
+ def generate
4
+ vars.inject(string) do |string, (name, value)|
5
+ string.gsub(value, "%{#{name}}")
6
+ end
7
+ end
8
+
9
+ def render
10
+ string % vars.symbolize_keys
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,3 @@
1
+ module Librato
2
+ VERSION = "0.0.4"
3
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: librato
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.4
5
+ platform: ruby
6
+ authors:
7
+ - Sven Fuchs
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-10-02 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Simple cli tool for storing and syncing librato spaces..
14
+ email:
15
+ - me@svenfuchs.com
16
+ executables:
17
+ - librato
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - MIT-LICENSE
22
+ - README.md
23
+ - bin/librato
24
+ - lib/core_ext/hash.rb
25
+ - lib/librato.rb
26
+ - lib/librato/chart.rb
27
+ - lib/librato/cli.rb
28
+ - lib/librato/cli/command.rb
29
+ - lib/librato/cli/pull.rb
30
+ - lib/librato/cli/push.rb
31
+ - lib/librato/client.rb
32
+ - lib/librato/config.rb
33
+ - lib/librato/space.rb
34
+ - lib/librato/spaces.rb
35
+ - lib/librato/store.rb
36
+ - lib/librato/template.rb
37
+ - lib/librato/version.rb
38
+ homepage: https://github.com/svenfuchs/librato
39
+ licenses:
40
+ - MIT
41
+ metadata: {}
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: '0'
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ requirements: []
57
+ rubyforge_project:
58
+ rubygems_version: 2.4.5
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Simple cli tool for storing and syncing librato spaces.
62
+ test_files: []
63
+ has_rdoc: