qubell_api 0.0.2

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