cloudability 0.0.1 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +3 -11
  5. data/LICENSE.txt +17 -18
  6. data/README.md +21 -22
  7. data/Rakefile +8 -5
  8. data/cloudability.gemspec +11 -6
  9. data/lib/cloudability.rb +7 -7
  10. data/lib/cloudability/billing.rb +35 -36
  11. data/lib/cloudability/budgets.rb +16 -10
  12. data/lib/cloudability/credentials.rb +7 -5
  13. data/lib/cloudability/organizations.rb +71 -0
  14. data/lib/cloudability/time_helper.rb +4 -5
  15. data/lib/cloudability/version.rb +1 -1
  16. data/spec/cloduability/billing_spec.rb +53 -0
  17. data/spec/cloduability/budgets_spec.rb +65 -0
  18. data/spec/cloduability/credentials_spec.rb +29 -0
  19. data/spec/cloduability/organizations_spec.rb +64 -0
  20. data/spec/fixtures/all_budgets +18 -0
  21. data/spec/fixtures/credentials +18 -0
  22. data/spec/fixtures/organization +18 -0
  23. data/spec/fixtures/organization_invitation +18 -0
  24. data/spec/fixtures/organization_invitations +18 -0
  25. data/spec/fixtures/organization_roles +18 -0
  26. data/spec/fixtures/report_by_account +18 -0
  27. data/spec/fixtures/report_by_period +18 -0
  28. data/spec/spec_helper.rb +48 -0
  29. metadata +89 -42
  30. data/test/fixtures/billing_report_by-vendor.json +0 -1
  31. data/test/fixtures/billing_report_period.json +0 -1
  32. data/test/fixtures/billing_report_year.json +0 -54
  33. data/test/fixtures/budgets.json +0 -34
  34. data/test/fixtures/credentials.json +0 -28
  35. data/test/helper.rb +0 -22
  36. data/test/lib/cloudability/test_billing.rb +0 -55
  37. data/test/lib/cloudability/test_budgets.rb +0 -44
  38. data/test/lib/cloudability/test_credentials.rb +0 -21
  39. data/test/lib/cloudability/test_time_helper.rb +0 -24
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 089d78278f2d92caf434767c88c8d04ed8c95ecc
4
+ data.tar.gz: d918cba1038ea27011947c1c18df94e714dca66b
5
+ SHA512:
6
+ metadata.gz: e03406715373ac541fbef6f58b8b525396f812be03f8999966c69ebcefadc7ef61e1d9d536a77ff9b9b0111d65689bf99780b70e9d8f8158235910ac876f60ec
7
+ data.tar.gz: cd06e24b5b8d9e7c5d68dc5f8f93d840e854a89896a2a3c214e33c62523d3c11713b8c450a388b78f898f83f4c59a630b12f24adba34f0c9b6470335543dd3cc
data/.gitignore CHANGED
@@ -2,6 +2,7 @@
2
2
  *.rbc
3
3
  .bundle
4
4
  .config
5
+ .rspec
5
6
  .yardoc
6
7
  Gemfile.lock
7
8
  InstalledFiles
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - 2.0.0
data/Gemfile CHANGED
@@ -1,12 +1,4 @@
1
- source :rubygems
2
- gem 'httparty'
3
- gem 'mash'
1
+ # Gem's dependencies are in cloudability.gemspec
2
+ source "https://rubygems.org"
3
+ gemspec
4
4
 
5
- group :test do
6
- gem 'turn'
7
- gem 'rake'
8
-
9
- gem 'shoulda'
10
- gem 'fakeweb'
11
- gem 'jnunemaker-matchy'
12
- end
@@ -1,22 +1,21 @@
1
- Copyright (c) 2012 Aaron Bento
1
+ The MIT License (MIT)
2
2
 
3
- MIT License
3
+ Copyright (c) 2012-2014 Aaron Bento & Colby Aley
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining
6
- a copy of this software and associated documentation files (the
7
- "Software"), to deal in the Software without restriction, including
8
- without limitation the rights to use, copy, modify, merge, publish,
9
- distribute, sublicense, and/or sell copies of the Software, and to
10
- permit persons to whom the Software is furnished to do so, subject to
11
- the following conditions:
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:
12
11
 
13
- The above copyright notice and this permission notice shall be
14
- included in all copies or substantial portions of the Software.
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
15
14
 
16
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
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 CHANGED
@@ -1,6 +1,6 @@
1
- # Cloudability
1
+ [![Build Status](https://travis-ci.org/ColbyAley/cloudability.png?branch=master)](https://travis-ci.org/ColbyAley/cloudability)
2
2
 
3
- Ruby wrapper for the Cloudability API using httparty.
3
+ Ruby wrapper for the [Cloudability API](http://developers.cloudability.com/).
4
4
 
5
5
  ## Installation
6
6
 
@@ -18,38 +18,37 @@ Or install it yourself as:
18
18
 
19
19
  ## Usage
20
20
 
21
- Covers endpoints:
22
- * credentials
23
- * budgets
24
- * and partial billing_reports
25
-
21
+ Supported endpoints:
22
+ * Credentials
23
+ * Budgets
24
+ * Reporting
25
+ * Organizations (Including invitations and roles.)
26
26
 
27
- ### Credential Endpoint:
28
- Caputure an array containing all your Cloud Accounts
27
+ Feel free to shoot me an email at colby@cloudability.com if you have any questions or need help.
28
+
29
+ ### Credentials
30
+ Retrieve an array containing all your Cloud Accounts.
29
31
 
30
- credentials = Cloudability::Credentials.new(:auth_token => 'xxxxxxxxxxxxxxxxxxxx')
32
+ credentials = Cloudability::Credentials.new(auth_token: 'xxxxxxxxxxxxxxxxxxxx')
31
33
  all_credentials = credentials.find_all
32
- first_account = all_credentials.first
33
34
 
34
35
  puts first_account.account_created_at
35
36
  puts first_account.account_identifier
36
37
  puts first_account.created_at
37
38
  puts first_account.has_auth
38
39
  puts first_account.has_estimate
39
- puts first_account.id
40
- puts first_account.is_duplicate
41
- puts first_account.nickname
42
- puts first_account.state
43
- puts first_account.updated_at
44
- puts first_account.vendor_id
45
- puts first_account.vendor_key
46
40
 
41
+ ### Organizations
47
42
 
48
- ## TODO:
49
- * finish report by and filter by options.
50
- * Refactor!
51
- * More Docs!
43
+ c = Cloudability::Organizations.new(auth_token: 'xxxxxxxxxxxxxxxxxxxx')
44
+ c.invite_user(email: 'colby@cloudability.com', name: 'Colby Aley')
45
+ c.roles
46
+ c.invitations
52
47
 
48
+ ## TODO:
49
+ * More tests!
50
+ * More endpoints!
51
+ * More awesomeness!
53
52
 
54
53
  ## Contributing
55
54
 
data/Rakefile CHANGED
@@ -1,9 +1,12 @@
1
1
  require 'bundler/gem_tasks'
2
- require 'rake/testtask'
3
2
 
4
- Rake::TestTask.new do |t|
5
- t.test_files = FileList['test/lib/cloudability/test_*.rb']
6
- t.verbose = true
3
+ task :default => :spec
4
+ desc 'run Rspec specs'
5
+ task :spec do
6
+ sh 'rspec'
7
7
  end
8
8
 
9
- task :default => :test
9
+ task :irb do
10
+ require File.expand_path('../lib/cloudability.rb', __FILE__)
11
+ sh 'irb -r ./lib/cloudability.rb'
12
+ end
@@ -6,16 +6,21 @@ require 'cloudability/version'
6
6
  Gem::Specification.new do |gem|
7
7
  gem.name = "cloudability"
8
8
  gem.version = Cloudability::VERSION
9
- gem.authors = ["Aaron Bento"]
10
- gem.email = ["abento+github@gmail.com"]
9
+ gem.licenses = ['MIT']
10
+ gem.authors = ["Colby Aley", "Aaron Bento"]
11
+ gem.email = ["colby@cloudability.com", "abento+github@gmail.com"]
11
12
  gem.description = %q{Ruby wrapper for the Cloudability API}
12
- gem.summary = %q{Ruby wrapper for the Cloudability API using httparty}
13
- gem.homepage = ""
13
+ gem.summary = %q{Ruby wrapper for the Cloudability API built with HTTParty}
14
+ gem.homepage = "https://github.com/colbyaley/cloudability"
14
15
 
15
16
  gem.files = `git ls-files`.split($/)
16
17
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
18
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
19
  gem.require_paths = ["lib"]
19
- gem.add_dependency('httparty')
20
- gem.add_dependency('mash')
20
+ gem.add_dependency('httparty', "~> 0.9.0")
21
+ gem.add_dependency('hashie')
22
+
23
+ gem.add_development_dependency('rspec')
24
+ gem.add_development_dependency('fakeweb')
25
+ gem.add_development_dependency('rake', '~> 0.6')
21
26
  end
@@ -1,9 +1,9 @@
1
- require_relative "cloudability/version"
2
1
  require 'httparty'
3
- require 'mash'
2
+ require 'hashie'
4
3
 
5
- module Cloudability
6
- Dir[File.dirname(__FILE__) + '/cloudability/*.rb'].each do |file|
7
- require file
8
- end
9
- end
4
+ require 'cloudability/billing'
5
+ require 'cloudability/budgets'
6
+ require 'cloudability/credentials'
7
+ require 'cloudability/organizations'
8
+
9
+ require 'cloudability/version'
@@ -7,60 +7,59 @@ module Cloudability
7
7
  attr_accessor :auth_token
8
8
 
9
9
  def initialize(options={})
10
+ raise ArgumentError, "You must provide an auth token" if options[:auth_token].nil?
11
+
10
12
  @auth_token = options[:auth_token]
11
13
  @params=[]
12
14
  end
13
15
 
14
- # Option #1 is a hash with parameter value
15
- # {:param1 => "period", }
16
- def report_by(options={})
17
-
18
- # TODO ::
19
- # - by= : period, vendor, service, credential, account
20
- # https://app.cloudability.com/api/0/billing_reports?auth_token=VZSaZ65u87X2p7HqgpJv&by=vendor
21
- # [{"vendor_id":1,"vendor_name":"Amazon","spend":"149744.69"}]
22
- @params << "&by=account" if options == :account
23
- @params << "&by=credential" if options == :credential
24
- @params << "&by=period" if options == :period
25
- @params << "&by=service" if options == :service
26
- @params << "&by=vendor" if options == :vendor
16
+ # Define which dimension the billing report will return.
17
+ #
18
+ # @param [Symbol] dimension to report on.
19
+ # @return [Array] array of Hashie::Mashes
20
+ def report_by(dimension)
21
+ case dimension
22
+ when :account
23
+ @params << "&by=account"
24
+ when :credential
25
+ @params << "&by=credential"
26
+ when :period
27
+ @params << "&by=period"
28
+ when :service
29
+ @params << "&by=service"
30
+ when :vendor
31
+ @params << "&by=vendor"
32
+ else
33
+ raise ArgumentError, "You must provide a valid dimension to report on."
34
+ end
27
35
 
28
- billing = get_url(@params)
29
- convert_to_mashes(billing)
36
+ billings = get_url(@params)
37
+ billings.map { |b| Hashie::Mash.new(b) }
30
38
  end
31
39
 
32
40
  # Find a particular period, based on its month.
33
41
  # Period must be in YY-MM-01 format with the date always 01.
34
42
  def filter_by_period(period)
35
- billing = get_billing_report(period)
36
- convert_to_mash(billing)
37
- end
43
+ unless period =~ /^[0-9]{2}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/
44
+ raise ArgumentError, "You must provide a valid date in the form of 'YY-MM-DD'."
45
+ end
38
46
 
39
- private
47
+ @params << "&period=#{period}"
48
+ single_billing = get_url(@params).first
40
49
 
41
- def get_billing_report(period)
42
- response = self.class.get("/billing_reports?auth_token=#{@auth_token}&period=#{period}")
43
- response.success? ? response : raise(response.response)
50
+ Hashie::Mash.new(single_billing)
44
51
  end
45
52
 
53
+ private
54
+
55
+ # GET a URL with HTTParty
56
+ #
57
+ # @param [Array] array of URL params to pass to HTTParty
46
58
  def get_url(params)
47
59
  joined_param = params.join
48
- url = "/billing_reports?auth_token=#{@auth_token}#{joined_param}"
49
60
  response = self.class.get("/billing_reports?auth_token=#{@auth_token}#{joined_param}")
50
61
  response.success? ? response : raise(response.response)
51
62
  end
52
63
 
53
- # Convert the json into a Mash.
54
- def convert_to_mash(response)
55
- mash = Mash.new(response.first)
56
- end
57
-
58
- # Convert the json into an Array of Mashes.
59
- def convert_to_mashes(response)
60
- billings =[]
61
- response.each { |b| billings << Mash.new(b)}
62
- return billings
63
- end
64
-
65
64
  end
66
- end
65
+ end
@@ -7,6 +7,7 @@ module Cloudability
7
7
  attr_accessor :auth_token
8
8
 
9
9
  def initialize(options={})
10
+ raise ArgumentError, "You must provide an auth token" if options[:auth_token].nil?
10
11
  @auth_token = options[:auth_token]
11
12
  end
12
13
 
@@ -17,14 +18,16 @@ module Cloudability
17
18
 
18
19
  # Find a particular budget, based on its id, and return a mash.
19
20
  def find_by_id(id)
20
- all_budgets = find_all
21
- budget = all_budgets.select {|r| r.id == id}.first
21
+ find_all.select {|b| b.id == id}.first
22
22
  end
23
23
 
24
24
  # Find a particular budget, based on its subject, and return a mash.
25
25
  def find_by_subject(subject)
26
- all_budgets = find_all
27
- budget = all_budgets.select {|r| r.subject == subject}.first
26
+ unless subject.length == 14
27
+ raise ArgumentError, "You must provide a valid subject such as 1234-5678-9101."
28
+ end
29
+
30
+ find_all.select {|b| b.subject == subject}.first
28
31
  end
29
32
 
30
33
  # Find a particular budget, based on a key, and return a mash.
@@ -34,22 +37,25 @@ module Cloudability
34
37
  budget = find_by_id(options[:value])
35
38
  when :subject
36
39
  budget = find_by_subject(options[:value])
40
+ else
41
+ raise ArgumentError, "You must provide a valid key."
37
42
  end
38
43
  end
39
44
 
40
45
  private
41
46
 
42
47
  def get_budgets
43
- response = self.class.get("/budgets/index?auth_token=#{self.auth_token}")
48
+ response = self.class.get("/budgets/index?auth_token=#{@auth_token}")
44
49
  response.success? ? response : raise(response.response)
45
50
  end
46
51
 
47
- # Convert the json into an Array of Mashes.
52
+ # Convert the JSON into an Array of Mashes.
53
+ #
54
+ # @param [String] JSON array
55
+ # @return [Array] array of Hashie::Mashes
48
56
  def convert_to_mashes(response)
49
- budgets =[]
50
- response.each { |b| budgets << Mash.new(b)}
51
- return budgets
57
+ response.map { |budget| Hashie::Mash.new(budget) }
52
58
  end
53
59
 
54
60
  end
55
- end
61
+ end
@@ -7,6 +7,7 @@ module Cloudability
7
7
  attr_accessor :auth_token
8
8
 
9
9
  def initialize(options={})
10
+ raise ArgumentError, "You must provide an auth token" if options[:auth_token].nil?
10
11
  @auth_token = options[:auth_token]
11
12
  end
12
13
 
@@ -17,15 +18,16 @@ module Cloudability
17
18
  private
18
19
 
19
20
  def get_credentials
20
- response = self.class.get("/credentials/index?auth_token=#{self.auth_token}")
21
+ response = self.class.get("/credentials/index?auth_token=#{@auth_token}")
21
22
  response.success? ? response : raise(response.response)
22
23
  end
23
24
 
24
- # Convert the json into an Array of Mashes.
25
+ # Convert the JSON into an Array of Mashes.
26
+ #
27
+ # @param [String] JSON array
28
+ # @return [Array] array of Hashie::Mashes
25
29
  def convert_to_mashes(response)
26
- credentials = []
27
- mashes = response.each { |c| credentials << Mash.new(c) }
28
- return credentials
30
+ response.map { |credential| Hashie::Mash.new(credential) }
29
31
  end
30
32
 
31
33
  end
@@ -0,0 +1,71 @@
1
+ module Cloudability
2
+ class Organizations
3
+ include HTTParty
4
+ base_uri "https://app.cloudability.com/api/1"
5
+ format :json
6
+
7
+ attr_accessor :auth_token
8
+
9
+ def initialize(options={})
10
+ raise ArgumentError, "You must provide an auth token" if options[:auth_token].nil?
11
+
12
+ @auth_token = options[:auth_token]
13
+ end
14
+
15
+ def my_organization
16
+ response = get_url("/organizations?auth_token=#{@auth_token}")
17
+ Hashie::Mash.new(response)
18
+ end
19
+
20
+ def invitations
21
+ response = get_url("/organizations/invitations?auth_token=#{@auth_token}")
22
+ convert_to_mashes(response)
23
+ end
24
+
25
+ def roles
26
+ response = get_url("/organizations/roles?auth_token=#{@auth_token}")
27
+ convert_to_mashes(response)
28
+ end
29
+
30
+ # Invite a user to your organization
31
+ #
32
+ # @param [Hash] args to pass to HTTParty
33
+ # @option [String] email (required)
34
+ # @option [String] name
35
+ # @option [String] role_id
36
+ def invite_user(args)
37
+ raise ArgumentError, "You must provide an email" if args[:email].nil?
38
+
39
+ response = post_url("/organizations/invitations?auth_token=#{@auth_token}", args)
40
+ Hashie::Mash.new(response)
41
+ end
42
+
43
+ private
44
+
45
+ # POST a URL with HTTParty
46
+ #
47
+ # @param [String] URL to post
48
+ # @param [Hash] params to pass to HTTParty
49
+ def post_url(url, params={})
50
+ response = self.class.post(url, query: params)
51
+ response.success? ? response : raise(response.response)
52
+ end
53
+
54
+ # GET a URL with HTTParty
55
+ #
56
+ # @param [String] URL to get
57
+ def get_url(url)
58
+ response = self.class.get(url)
59
+ response.success? ? response : raise(response.response)
60
+ end
61
+
62
+ # Convert the JSON into an Array of Mashes.
63
+ #
64
+ # @param [String] JSON array
65
+ # @return [Array] array of Hashie::Mashes
66
+ def convert_to_mashes(response)
67
+ response.map { |budget| Hashie::Mash.new(budget) }
68
+ end
69
+
70
+ end
71
+ end