librato 0.0.4

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