bixby-client 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,104 @@
1
+
2
+ require "curb"
3
+ require "httpi"
4
+ require "api-auth"
5
+
6
+ module Bixby
7
+
8
+ # Implements the Bixby client API
9
+ class Client
10
+
11
+ # Create a new Client
12
+ #
13
+ # @param [String] access_key
14
+ # @param [String] secret_key
15
+ def initialize(access_key, secret_key)
16
+ @access_key = access_key
17
+ @secret_key = secret_key
18
+ end
19
+
20
+ # Execute the given API request on the manager
21
+ #
22
+ # @param [String] operation Name of operation
23
+ # @param [Array] params Array of parameters; must ve valid JSON types
24
+ #
25
+ # @return [JsonResponse]
26
+ def exec(op, params)
27
+ exec_api(JsonRequest.new(op, params))
28
+ end
29
+
30
+ # Execute the given API download request
31
+ #
32
+ # @param [String] download_path Absolute filename to download requested file to
33
+ # @param [String] operation Name of operation
34
+ # @param [Array] params Array of parameters; must ve valid JSON types
35
+ #
36
+ # @return [JsonResponse]
37
+ def exec_download(download_path, op, params)
38
+ exec_api_download(JsonRequest.new(op, params), download_path)
39
+ end
40
+
41
+ # Execute the given API request on the manager
42
+ #
43
+ # @param [JsonRequest] json_req
44
+ # @return [JsonResponse]
45
+ def exec_api(json_req)
46
+ begin
47
+ req = sign_request(json_req)
48
+ res = HTTPI.post(req).body
49
+ return JsonResponse.from_json(res)
50
+ rescue Curl::Err::CurlError => ex
51
+ return JsonResponse.new("fail", ex.message)
52
+ end
53
+ end
54
+
55
+ # Execute the given API download request
56
+ #
57
+ # @param [JsonRequest] json_req Request to download a file
58
+ # @param [String] download_path Absolute filename to download requested file to
59
+ # @return [JsonResponse]
60
+ def exec_api_download(json_req, download_path)
61
+ begin
62
+ req = sign_request(json_req)
63
+ File.open(download_path, "w") do |io|
64
+ req.on_body { |d| io << d; d.length }
65
+ HTTPI.post(req)
66
+ end
67
+ return JsonResponse.new("success")
68
+ rescue Curl::Err::CurlError => ex
69
+ return JsonResponse.new("fail", ex.message)
70
+ end
71
+ end
72
+
73
+
74
+ private
75
+
76
+ # Create a signed request
77
+ #
78
+ # @param [JsonRequest] json_req
79
+ #
80
+ # @return [HTTPI::Request]
81
+ def sign_request(json_req)
82
+ post = json_req.to_json
83
+ req = HTTPI::Request.new(:url => api_uri, :body => post)
84
+ req.headers["Content-Type"] = "application/json"
85
+
86
+ if crypto_enabled? and not @secret_key.nil? then
87
+ ApiAuth.sign!(req, @access_key, @secret_key)
88
+ end
89
+
90
+ return req
91
+ end
92
+
93
+ def api_uri
94
+ URI.join(Bixby.manager_uri, "/api").to_s
95
+ end
96
+
97
+ def crypto_enabled?
98
+ b = ENV["BIXBY_NOCRYPTO"]
99
+ !(b and %w{1 true yes}.include? b)
100
+ end
101
+
102
+ end # Client
103
+
104
+ end # Bixby
@@ -0,0 +1,36 @@
1
+
2
+ require "digest"
3
+ require "fileutils"
4
+
5
+ require "mixlib/shellout"
6
+
7
+ module Bixby
8
+ class Command
9
+
10
+ include Bixby::Log
11
+ include Bixby::PlatformUtil
12
+ include Bixby::ScriptUtil
13
+
14
+ def initialize()
15
+ end
16
+
17
+ # retrieve all loaded subclasses of this classs
18
+ #
19
+ # @return [Array<Class>] List of subclasses
20
+ def self.subclasses
21
+ @subclasses
22
+ end
23
+
24
+ private
25
+
26
+ def self.inherited(subclass)
27
+ if superclass.respond_to? :inherited
28
+ superclass.inherited(subclass)
29
+ end
30
+ @subclasses ||= []
31
+ @subclasses << subclass
32
+ end
33
+
34
+ end # Command
35
+ end # Bixby
36
+
@@ -0,0 +1,4 @@
1
+
2
+ require "bixby-client/modules/inventory"
3
+ require "bixby-client/modules/metrics"
4
+ require "bixby-client/modules/repository"
@@ -0,0 +1,23 @@
1
+
2
+ module Bixby
3
+ module Inventory
4
+
5
+ # Register an agent with the manager
6
+ #
7
+ # @param [String] uuid
8
+ # @param [String] public_key
9
+ # @param [String] hostname
10
+ # @param [FixNum] port
11
+ # @param [String] tenant Name of the tenant
12
+ # @param [String] password Password for registering an Agent with the server
13
+ #
14
+ # @return [JsonResponse]
15
+ def self.register_agent(uuid, public_key, hostname, port, tenant, password)
16
+ # TODO these params should probably be a keyed hash instead
17
+ params = [ uuid, public_key, hostname, port, tenant, password ]
18
+ req = JsonRequest.new("inventory:register_agent", params)
19
+ return Bixby::Client.new(nil, nil).exec_api(req)
20
+ end
21
+
22
+ end # Inventory
23
+ end # Bixby
@@ -0,0 +1,43 @@
1
+
2
+ module Bixby
3
+ module Metrics
4
+
5
+ # Store the results of one or more Checks. Each result may contain multiple metrics.
6
+ #
7
+ # Fires the :put_check_result hook on completion, passing results as the only param.
8
+ #
9
+ # @param [Array<Hash>] results An array of results from one or more checks
10
+ # @option results [Fixnum] :check_id
11
+ # @option results [String] :key base key name
12
+ # @option results [String] :status OK, WARNING, CRITICAL, UNKNOWN, TIMEOUT
13
+ # @option results [Fixnum] :timestamp
14
+ # @option results [Array] :metrics
15
+ # * [Hash] :metrics key/value pairs
16
+ # * [Hash] :metadata key/value pairs
17
+ # @option results [Array<String>] :errors list of errors, if any
18
+ #
19
+ # @return [void]
20
+ #
21
+ # Example input:
22
+ #
23
+ # {
24
+ # "status" => "OK",
25
+ # "timestamp" => 1329775841,
26
+ # "key" => "hardware.storage.disk",
27
+ # "check_id" => "77",
28
+ # "metrics" => [
29
+ # {
30
+ # "metrics" => { "size"=>297, "used"=>202, "free"=>94, "usage"=>69 },
31
+ # "metadata" => { "mount"=>"/", "type"=>"hfs" }
32
+ # }
33
+ # ],
34
+ # "errors"=>[]
35
+ # }
36
+ #
37
+ def self.put_check_result(results)
38
+ req = JsonRequest.new("metrics:put_check_result", [ results ])
39
+ return Bixby.client.exec_api(req)
40
+ end
41
+
42
+ end # Metrics
43
+ end # Bixby
@@ -0,0 +1,63 @@
1
+
2
+ module Bixby
3
+ module Repository
4
+
5
+ # Retrieve a file listing for the given Bundle
6
+ #
7
+ # @param [CommandSpec] cmd CommandSpec representing the Bundle to list
8
+ #
9
+ # @return [Array<Hash>]
10
+ # * file [String] Relative path of file
11
+ # * digest [String] SHA256 digest of file
12
+ def self.list_files(cmd)
13
+ req = JsonRequest.new("provisioning:list_files", cmd.to_hash)
14
+ res = Bixby.client.exec_api(req)
15
+ return res.data
16
+ end
17
+
18
+ # Download athe given list of files
19
+ #
20
+ # @param [CommandSpec] cmd CommandSpec representing the Bundle to which the files belong
21
+ # @param [Hash] files Hash, returned from #list_files
22
+ def self.download_files(cmd, files)
23
+ return if files.nil? or files.empty?
24
+
25
+ local_path = cmd.bundle_dir
26
+ digest = cmd.load_digest
27
+ files.each do |f|
28
+
29
+ fetch = true
30
+ if not digest then
31
+ fetch = true
32
+ elsif df = digest["files"].find{ |h| h["file"] == f["file"] } then
33
+ # compare digest w/ stored one if we have it
34
+ fetch = (df["digest"] != f["digest"])
35
+ else
36
+ fetch = true
37
+ end
38
+
39
+ next if not fetch
40
+
41
+ params = cmd.to_hash
42
+ params.delete(:digest)
43
+
44
+ filename = File.join(local_path, f['file'])
45
+ path = File.dirname(filename)
46
+ if not File.exist? path then
47
+ FileUtils.mkdir_p(path)
48
+ end
49
+
50
+ req = JsonRequest.new("provisioning:fetch_file", [ params, f['file'] ])
51
+ Bixby.client.exec_api_download(req, filename)
52
+ if f['file'] =~ /^bin/ then
53
+ # correct permissions for executables
54
+ FileUtils.chmod(0755, filename)
55
+ end
56
+ end # files.each
57
+
58
+ cmd.update_digest
59
+ end
60
+
61
+
62
+ end
63
+ end
@@ -0,0 +1,16 @@
1
+
2
+ require "mixlib/shellout"
3
+
4
+ module Mixlib
5
+ class ShellOut
6
+
7
+ def success?
8
+ exitstatus == 0
9
+ end
10
+
11
+ def fail?
12
+ ! success?
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module Bixby
3
+ module PlatformUtil
4
+
5
+ def uname
6
+ RUBY_PLATFORM
7
+ end
8
+
9
+ def osx?
10
+ uname =~ /darwin/
11
+ end
12
+ alias :darwin? :osx?
13
+ alias :mac? :osx?
14
+
15
+ def linux?
16
+ uname =~ /linux/
17
+ end
18
+
19
+ def win?
20
+
21
+ end
22
+ alias :windows? :win?
23
+
24
+ end # PlatformUtil
25
+ end # Bixby
@@ -0,0 +1,18 @@
1
+
2
+ require "bixby-client"
3
+ require "fileutils"
4
+ require "mixlib/shellout"
5
+
6
+ Bixby::Log.setup_logger()
7
+
8
+ class Object
9
+ include Bixby::PlatformUtil
10
+ include Bixby::ScriptUtil
11
+ include Bixby::Log
12
+
13
+ # override to create logger based on script name
14
+ def log
15
+ @log ||= Logging.logger[File.basename($0)]
16
+ end
17
+
18
+ end
@@ -0,0 +1,73 @@
1
+
2
+ require "bixby-client/patch/shellout"
3
+
4
+ module Bixby
5
+
6
+ module ScriptUtil
7
+
8
+ module UseBundle
9
+
10
+ # Load the libraries for the given bundle. Searches all available
11
+ # repositories.
12
+ def use_bundle(name)
13
+ repos = Dir.glob(File.join(Bixby.repo_path, "*"))
14
+ repos.each do |repo|
15
+ next if not File.directory? repo
16
+
17
+ lib = File.join(repo, name, "lib")
18
+ $: << lib
19
+ if File.directory? lib then
20
+ Dir.glob(File.join(lib, "*.rb")).each{ |f| require f }
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ include UseBundle
27
+
28
+ # Reads JSON data from STDIN
29
+ #
30
+ # @return [Object] data found on STDIN (can be Hash, Array, String, etc)
31
+ def get_json_input
32
+ input = read_stdin()
33
+ input.strip! if input
34
+ (input.nil? or input.empty?) ? {} : MultiJson.load(input)
35
+ end
36
+
37
+ # Read all available data on STDIN without blocking
38
+ # (i.e., if no data is available, none will be returned)
39
+ #
40
+ # @return [String] data
41
+ def read_stdin
42
+ buff = []
43
+ while true do
44
+ begin
45
+ buff << STDIN.read_nonblock(64000)
46
+ rescue
47
+ break
48
+ end
49
+ end
50
+ return buff.join('')
51
+ end
52
+
53
+ # Simple wrapper around Mixlib::ShellOut
54
+ #
55
+ # @param [Array] args
56
+ #
57
+ # @return [Mixlib::ShellOut]
58
+ def systemu(*args)
59
+ cmd = Mixlib::ShellOut.new(*args)
60
+ cmd.run_command
61
+ cmd
62
+ end
63
+
64
+ end # ScriptUtil
65
+ end # Bixby
66
+
67
+ module Bixby
68
+ extend Bixby::ScriptUtil::UseBundle
69
+ end
70
+
71
+ class Object
72
+ include Bixby::ScriptUtil::UseBundle
73
+ end
@@ -0,0 +1,15 @@
1
+
2
+ require 'jeweler'
3
+
4
+ Jeweler::Tasks.new do |gemspec|
5
+ gemspec.name = "bixby-client"
6
+ gemspec.summary = "Bixby Client"
7
+ gemspec.description = "Bixby Client"
8
+ gemspec.email = "chetan@pixelcop.net"
9
+ gemspec.homepage = "http://github.com/chetan/bixby-client"
10
+ gemspec.authors = ["Chetan Sarva"]
11
+
12
+ gemspec.executables = %w{ bixby }
13
+
14
+ end
15
+ Jeweler::RubygemsDotOrgTasks.new
data/tasks/test.rake ADDED
@@ -0,0 +1,16 @@
1
+
2
+ require 'rake/testtask'
3
+ Rake::TestTask.new(:test) do |test|
4
+ test.libs << 'lib' << 'test'
5
+ test.pattern = 'test/**/test_*.rb'
6
+ end
7
+
8
+ task :default => :test
9
+
10
+ begin
11
+ require 'single_test'
12
+ SingleTest.load_tasks
13
+
14
+ rescue LoadError
15
+ warn "single_test not available"
16
+ end