qubell_api 0.0.2

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: 146dae04948ecfbec091e7ec069a3531bbb64393
4
+ data.tar.gz: c213ce1c5079a8678a9268566e83f4289415d3ee
5
+ SHA512:
6
+ metadata.gz: 8b814e2fb22a16bac6dfc60c2c609d4a74ed8237d13cce9575213bc793939aa1a54cb61e0855fa38633d808999fae357dda21866c2952ec871f79d38188b9d7c
7
+ data.tar.gz: f6422d2ad4d981005e66a6ea4ae13744d387d75512827e37030ea822d6f7460b794fa7c47622ecf3d3e2cc792494bd55526f84ff40bcc8a18521b4014b116375
data/.gitignore ADDED
@@ -0,0 +1,37 @@
1
+ /.idea/
2
+ *.gem
3
+ *.rbc
4
+ /.config
5
+ /coverage/
6
+ /InstalledFiles
7
+ /pkg/
8
+ /spec/reports/
9
+ /test/tmp/
10
+ /test/version_tmp/
11
+ /tmp/
12
+ /out/
13
+ /vendor/
14
+
15
+ ## Specific to RubyMotion:
16
+ .dat*
17
+ .repl_history
18
+ build/
19
+
20
+ ## Documentation cache and generated files:
21
+ /.yardoc/
22
+ /_yardoc/
23
+ /doc/
24
+ /rdoc/
25
+
26
+ ## Environment normalisation:
27
+ /.bundle/
28
+ /lib/bundler/man/
29
+
30
+ # for a library or gem, you might want to ignore these files since the code is
31
+ # intended to run in multiple environments; otherwise, check them in:
32
+ Gemfile.lock
33
+ .ruby-version
34
+ # .ruby-gemset
35
+
36
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
37
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.rubocop.yml ADDED
@@ -0,0 +1,5 @@
1
+ AllCops:
2
+ Exclude:
3
+ - test/**/*
4
+ - vendor/**/*
5
+ - tmp/**/*
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.3.0
4
+ install:
5
+ - bundle install --path vendor/bundle
6
+ script:
7
+ - bundle exec rake
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rest-client', '~> 2.0.0'
4
+
5
+ group :development do
6
+ gem 'rake', '~> 11.2.0'
7
+ gem 'webmock', '~> 2.1.0'
8
+ gem 'rspec', '~> 3.5.0'
9
+ gem 'rubocop', '~> 0.41.0'
10
+ gem 'yard', '~> 0.9.0'
11
+ gem 'factory_girl', '~> 4.7.0'
12
+ gem 'simplecov', '~> 0.12.0'
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Nikolay Yurin
2
+
3
+ MIT License
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:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
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.
data/README.md ADDED
@@ -0,0 +1,6 @@
1
+ Ruby Qubell API
2
+ ===============
3
+
4
+ Qubell API wrapper on Ruby
5
+
6
+ [![Build Status](https://api.travis-ci.org/yurinnick/qubell-ruby-api.svg)](https://travis-ci.org/yurinnick/qubell-ruby-api)
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ # Encoding: utf-8
2
+
3
+ require 'bundler'
4
+ require 'bundler/gem_tasks'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts 'Run `bundle install` to install missing gems'
9
+ $stderr.puts e.message
10
+ exit e.status_code
11
+ end
12
+
13
+ require 'rake'
14
+ require 'rspec/core'
15
+ require 'rspec/core/rake_task'
16
+ require 'rubocop/rake_task'
17
+
18
+ RSpec::Core::RakeTask.new(:spec) do |spec|
19
+ spec.pattern = FileList['test/spec/**/*_spec.rb']
20
+ end
21
+
22
+ desc 'Run RSpec with code coverage'
23
+ task :coverage do
24
+ ENV['COVERAGE'] = 'true'
25
+ Rake::Task['spec'].execute
26
+ end
27
+
28
+ desc 'Run RuboCop over itself'
29
+ RuboCop::RakeTask.new(:code_style) do |task|
30
+ task.fail_on_error = false
31
+ end
32
+
33
+ task default: [:spec, :code_style]
@@ -0,0 +1,46 @@
1
+ require 'yaml'
2
+ require 'qubell/errors'
3
+
4
+ module Qubell
5
+ # Implements Qubell API HTTP call helpers
6
+ class APICall
7
+ %w(get post put delete).each do |http_method|
8
+ define_singleton_method(http_method.to_sym) do |path, *args|
9
+ Qubell.configure do |config|
10
+ RestClient::Resource.new(
11
+ "#{config.endpoint}#{path}",
12
+ config.username,
13
+ config.password
14
+ ).send(http_method.to_sym, *args) do |response|
15
+ handle_response(response)
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ # @param [String] data
22
+ def self.handle_response(response)
23
+ if response.code == 200
24
+ case response.headers[:content_type]
25
+ when 'application/json' then JSON.parse(response, symbolize_names: true)
26
+ when 'application/x-yaml' then YAML.load response
27
+ else response.empty? ? nil : response
28
+ end
29
+ else
30
+ handle_error(response.code)
31
+ end
32
+ end
33
+
34
+ # @param [String] response
35
+ def self.handle_error(code)
36
+ case code
37
+ when 400 then raise Qubell::ExecutionError
38
+ when 401 then raise Qubell::AuthenticationError
39
+ when 403 then raise Qubell::PermissionsDeniedError
40
+ when 404 then raise Qubell::ResourceUnavaliable
41
+ when 409 then raise Qubell::WorkflowError
42
+ else raise Qubell::BaseError, code
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,71 @@
1
+ # Encoding: utf-8
2
+ # Qubell application class
3
+ # @author Nikolay Yurin <yurinnick@outlook.com>
4
+
5
+ require 'qubell/base'
6
+ require 'qubell/revision'
7
+ require 'qubell/api_call'
8
+ require 'qubell/instance'
9
+ require 'qubell/organization'
10
+
11
+ # Main Qubell module
12
+ module Qubell
13
+ # Qubell application class
14
+ class Application < Base
15
+ attr_reader :organization
16
+
17
+ def initialize(args)
18
+ super
19
+ @organization = args[:organization]
20
+ end
21
+
22
+ # Get list of all revisions for given application.
23
+ # @return [Array<Qubell::Revision>] revisions info
24
+ def revisions
25
+ Qubell::APICall.get("/applications/#{@id}/revisions").map do |rev|
26
+ Qubell::Revision.new(rev)
27
+ end
28
+ end
29
+
30
+ # Get list of all instances for given application.
31
+ # @return [Array<Qubell::Instance>] revisions info
32
+ def instances
33
+ # Qubell public API is too enterprise for just getting list of instances
34
+ # by application ID. Actually there is no method for this yet.
35
+ # So, store ID of organization in Application class and to get a list of
36
+ # instances we init new organization class, get all environments in this
37
+ # organization, get all instances in this environment and finally
38
+ # filter them by application.
39
+ # Like in one russian fairytail: "his death is at the end of the needle,
40
+ # that needle is in the egg, then egg is in a duck, that duck is in a
41
+ # hare, the hare is in the trunk, and the trunk stands on a high oak"
42
+ Qubell::Organization.new(id: @organization).environments
43
+ .map(&:instances).flatten.select do |instance|
44
+ instance.instance_of_app?(self)
45
+ end
46
+ end
47
+
48
+ # Get the application instance status.
49
+ # @param [String] content new manifest content
50
+ # @return [String] instances status info
51
+ def update(content)
52
+ Qubell::APICall.put("/applications/#{@id}/manifest",
53
+ content,
54
+ content_type: 'application/x-yaml')[:version]
55
+ rescue Qubell::ExecutionError
56
+ raise Qubell::FormatError, 'currect manifest is incorrect'
57
+ end
58
+
59
+ # Launch new instance of given application.
60
+ # @param [Hash<String => String>] args map of configuration parameters
61
+ # @return [Qubell::Instance] revisions info
62
+ def launch(args)
63
+ id = Qubell::APICall.put("/applications/#{@id}/launch",
64
+ args.to_json,
65
+ content_type: 'application/json')[:id]
66
+ instances.select { |instance| instance.id == id }.first
67
+ rescue Qubell::ExecutionError
68
+ raise Qubell::FormatError, 'currect manifest is incorrect'
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,44 @@
1
+ # Encoding: utf-8
2
+ # Qubell API wrapper
3
+ # @author Nikolay Yurin <yurinnick@outlook.com>
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ require 'json'
8
+
9
+ # Main Qubell module
10
+ module Qubell
11
+ # Class wrapper for HTTP requests
12
+ class Base
13
+ # @return [String] object id
14
+ attr_reader :id
15
+ # @return [String] object name
16
+ attr_reader :name
17
+
18
+ def initialize(args)
19
+ @id = if args[:id].nil?
20
+ raise ArgumentError,
21
+ "can't initialize #{self.class.name} without id"
22
+ else
23
+ args[:id]
24
+ end
25
+ @name = args[:name]
26
+ end
27
+
28
+ def to_json(options)
29
+ to_hash.to_json(options)
30
+ end
31
+
32
+ def to_s
33
+ %("id": "#{@id}", "name": "#{@name}")
34
+ end
35
+
36
+ def to_hash
37
+ { id: @id, name: @name }
38
+ end
39
+
40
+ def ==(other)
41
+ other.instance_of?(self.class) && id == other.id && name == other.name
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ # Main Qubell module
2
+ module Qubell
3
+ class << self
4
+ attr_writer :configuration
5
+ end
6
+
7
+ def self.configuration
8
+ @configuration ||= Configuration.new
9
+ end
10
+
11
+ def self.configure
12
+ yield configuration
13
+ end
14
+
15
+ # Store configuration settings
16
+ class Configuration
17
+ attr_accessor :domain, :api_version, :username, :password
18
+ attr_reader :endpoint
19
+
20
+ def initialize
21
+ @domain = 'https://express.tonomi.com'
22
+ @api_version = '1'
23
+ end
24
+
25
+ def endpoint
26
+ "#{@domain}/api/#{@api_version}"
27
+ end
28
+
29
+ def to_s
30
+ %({"domain": "#{@domain}","api_version": "#{@api_version}",) +
31
+ %("username": "#{@username}","password": "#{@password}"})
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,64 @@
1
+ # Encoding: utf-8
2
+ # Qubell application class
3
+ # @author Nikolay Yurin <yurinnick@outlook.com>
4
+
5
+ require 'yaml'
6
+ require 'qubell/base'
7
+ require 'qubell/api_call'
8
+ require 'qubell/instance'
9
+
10
+ module Qubell
11
+ # Implements Qubell environment interface
12
+ class Environment < Base
13
+ attr_reader :is_default
14
+
15
+ def initialize(args)
16
+ super
17
+ @is_default = args[:isDefault]
18
+ end
19
+
20
+ def policies
21
+ Qubell::APICall.get("/environments/#{@id}")[:policies]
22
+ end
23
+
24
+ # noinspection RubyStringKeysInHashInspection
25
+ def policies=(value)
26
+ Qubell::APICall.put("/environments/#{@id}",
27
+ { policies: value }.to_yaml,
28
+ content_type: 'application/x-yaml')
29
+ rescue Qubell::ExecutionError
30
+ raise Qubell::FormatError
31
+ end
32
+
33
+ def markers
34
+ Qubell::APICall
35
+ .get("/environments/#{@id}/markers")[:markers].map { |m| m[:name] }
36
+ end
37
+
38
+ def markers=(value)
39
+ Qubell::APICall.put("/environments/#{@id}/markers",
40
+ { markers: value.each { |v| { name: v } } }.to_json,
41
+ content_type: 'application/json')
42
+ rescue Qubell::ExecutionError
43
+ raise Qubell::FormatError
44
+ end
45
+
46
+ def properties
47
+ Qubell::APICall.get("/environments/#{@id}/properties")[:properties]
48
+ end
49
+
50
+ def properties=(value)
51
+ Qubell::APICall.put("/environments/#{@id}/properties",
52
+ { properties: value }.to_json,
53
+ content_type: 'application/json')
54
+ rescue Qubell::ExecutionError
55
+ raise Qubell::FormatError
56
+ end
57
+
58
+ def instances
59
+ Qubell::APICall.get("/environments/#{@id}/instances").map do |inst|
60
+ Qubell::Instance.new(inst)
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,62 @@
1
+ # Encoding: utf-8
2
+
3
+ module Qubell
4
+ # Base exception for Qubell module
5
+ class BaseError < StandardError
6
+ attr_reader :error_code
7
+
8
+ def initialize(error_code, msg = 'unknown status code')
9
+ super msg
10
+ @error_code = error_code
11
+ end
12
+ end
13
+
14
+ # Common Qubell API exception
15
+ class ExecutionError < Qubell::BaseError
16
+ def initialize(msg = 'instance is a submodule or active')
17
+ super '400', msg
18
+ end
19
+ end
20
+
21
+ # Authentication exception for Qubell module
22
+ class AuthenticationError < Qubell::BaseError
23
+ def initialize(msg = 'invalid credentials')
24
+ super '401', msg
25
+ end
26
+ end
27
+
28
+ # Invalid permissions exception for Qubell module
29
+ class PermissionsDeniedError < Qubell::BaseError
30
+ def initialize(msg = 'insufficient privileges')
31
+ super '403', msg
32
+ end
33
+ end
34
+
35
+ # Unavaliable resource exception for Qubell module
36
+ class ResourceUnavaliable < Qubell::BaseError
37
+ def initialize(msg = 'resource doesn’t exist')
38
+ super '404', msg
39
+ end
40
+ end
41
+
42
+ # Workflow exception for Qubell module
43
+ class WorkflowError < Qubell::BaseError
44
+ def initialize(msg = 'another workflow is already running')
45
+ super '409', msg
46
+ end
47
+ end
48
+
49
+ # Invalid input exception for Qubell module
50
+ class FormatError < ExecutionError
51
+ def initialize(msg = 'incorrect format or data')
52
+ super
53
+ end
54
+ end
55
+
56
+ # Instance destoy exception for Qubell module
57
+ class DestroyError < ExecutionError
58
+ def initialize(msg = 'specified instance is either a submodule or active')
59
+ super
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,64 @@
1
+ # Encoding: utf-8
2
+ # Qubell application class
3
+ # @author Nikolay Yurin <yurinnick@outlook.com>
4
+
5
+ require 'qubell/base'
6
+
7
+ module Qubell
8
+ # Implement Qubell application interface
9
+ class Instance < Base
10
+ attr_reader :environment
11
+ attr_reader :revision
12
+
13
+ def initialize(args)
14
+ super
15
+ @environment = args[:environment]
16
+ @revision = args[:revision]
17
+ end
18
+
19
+ # Runs the specified application instance workflow.
20
+ # @param [String] workflow instance workflow name
21
+ # @param [Hash{String => String}] workflow instance workflow name
22
+ # @return [Hashes{String => String}] instance id
23
+ def launch_workflow(workflow, _args)
24
+ Qubell::APICall.get("/instances/#{@id}/#{workflow}")
25
+ end
26
+
27
+ # Associates user data with the instance.
28
+ # @param [String] data JSON-encoded user data
29
+ # @return [#void]
30
+ def userdata(data)
31
+ Qubell::APICall.put("/instances/#{@id}/userData", data)
32
+ rescue Qubell::ExecutionError
33
+ raise Qubell::FormatError
34
+ end
35
+
36
+ # Destroy an application
37
+ # @param [String] force specifies whether the instance should be deleted
38
+ # @return [#void]
39
+ def destroy(force = false)
40
+ status = force ? '1' : '0'
41
+ begin
42
+ Qubell::APICall.delete("/instances/#{@id}?#{status}")
43
+ rescue Qubell::ExecutionError
44
+ raise Qubell::DestroyError
45
+ end
46
+ end
47
+
48
+ def instance_of_app?(app)
49
+ global_info[:applicationId] == app.id
50
+ end
51
+
52
+ %w(version parameters status).each do |method_name|
53
+ define_method(method_name.to_sym) do
54
+ global_info[method_name]
55
+ end
56
+ end
57
+
58
+ private
59
+
60
+ def global_info
61
+ Qubell::APICall.get("/instances/#{@id}")
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,26 @@
1
+ # Encoding: utf-8
2
+ # Qubell API wrapper
3
+ # @author Nikolay Yurin <yurinnick@outlook.com>
4
+
5
+ require 'qubell/base'
6
+ require 'qubell/application'
7
+ require 'qubell/environment'
8
+ require 'qubell/api_call'
9
+
10
+ module Qubell
11
+ # Implements Qubell organization interface
12
+ class Organization < Base
13
+ def applications
14
+ Qubell::APICall.get("/organizations/#{@id}/applications").map do |app|
15
+ app['organization_id'] = @id
16
+ Qubell::Application.new(app)
17
+ end
18
+ end
19
+
20
+ def environments
21
+ Qubell::APICall.get("/organizations/#{@id}/environments").map do |app|
22
+ Qubell::Environment.new(app)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,12 @@
1
+ require 'qubell/base'
2
+
3
+ module Qubell
4
+ # Qubell revision class
5
+ class Revision < Base
6
+ def instances
7
+ Qubell::APICall.get("/revisions/#{id}/instances").map do |instance|
8
+ Qubell::Instance.new(instance)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ # Main Qubell module
2
+ module Qubell
3
+ VERSION = '0.0.2'.freeze
4
+ end
data/lib/qubell_api.rb ADDED
@@ -0,0 +1,45 @@
1
+ # Encoding: utf-8
2
+ # Qubell API wrapper
3
+ # @author Nikolay Yurin <yurinnick@outlook.com>
4
+
5
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
6
+
7
+ require 'json'
8
+ require 'base64'
9
+ require 'rest_client'
10
+
11
+ require 'qubell/base'
12
+ require 'qubell/errors'
13
+ require 'qubell/application'
14
+ require 'qubell/organization'
15
+ require 'qubell/configuration'
16
+ require 'qubell/revision'
17
+ require 'qubell/environment'
18
+
19
+ # Main Qubell module
20
+ module Qubell
21
+ # Implements wrapper for Qubell API
22
+ class API < Base
23
+ # @param [HashMap<String => String>] key
24
+ def initialize(options = {})
25
+ options.each do |key|
26
+ Qubell.configuration.send("#{key[0]}=", key[1])
27
+ end
28
+ end
29
+
30
+ # Get list of all organizations that current user belong to.
31
+ # @return [Array<Qubell::Organization>] organizations info
32
+ def organizations
33
+ Qubell::APICall.get('/organizations').map do |org|
34
+ Qubell::Organization.new(org)
35
+ end
36
+ end
37
+
38
+ # Get list of instances launched in given environment.
39
+ # @=irnparam [String] env_id queried environment id
40
+ # @return [Array<Hash{String => String}>] instances info
41
+ # def instances(env_id)
42
+ # get("/environments/#{env_id}/instances")
43
+ # end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'qubell/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'qubell_api'
8
+ spec.version = Qubell::VERSION
9
+ spec.authors = ['Nikolay Yurin']
10
+ spec.email = ['yurinnick@outlook.com']
11
+ spec.summary = 'Qubell API wrapper'
12
+ spec.description = 'Qubell API wrapper'
13
+ spec.homepage = 'https://github.com/yurinnick/qubell-ruby-api'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{/^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{/^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_runtime_dependency 'rest-client', '~> 2.0.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.11.0'
24
+ spec.add_development_dependency 'rake', '~> 11.2.0'
25
+ spec.add_development_dependency 'webmock', '~> 2.1.0'
26
+ spec.add_development_dependency 'rspec', '~> 3.5.0'
27
+ spec.add_development_dependency 'rubocop', '~> 0.41.0'
28
+ spec.add_development_dependency 'yard', '~> 0.9.0'
29
+ spec.add_development_dependency 'factory_girl', '~> 4.7.0'
30
+ spec.add_development_dependency 'simplecov', '~> 0.12.0'
31
+ end