bixby-client 0.1.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.
@@ -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