larrow-qingcloud 0.0.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d61865ed5e80afc2c62df279a97e2bf6953f103
4
+ data.tar.gz: d868ff45b35ca34d55e4abeef07cbf9babc8f9b8
5
+ SHA512:
6
+ metadata.gz: f137a8bd083ceaf964f1bfb55daba5fee8e078f6ff1d696553eae4b3d4205cbc7a3b1799d91fb39aa702a235588ea099155a386ced6b795dd2923219127541f0
7
+ data.tar.gz: 9e150feb1132e7c6be0cf25e1f8120ccbc3530513ddc9752dd8f73f5b0fbcc91a191262ff3aade2c4473c6b4c753ce74fb148e3583a6fc51fa29e28cac9ba062
data/.gitignore ADDED
@@ -0,0 +1,21 @@
1
+ *.gem
2
+ *.rbc
3
+ *.log
4
+ **/*.swp
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ *.keys
9
+ *.csv
10
+ InstalledFiles
11
+ _yardoc
12
+ coverage
13
+ doc/
14
+ lib/bundler/man
15
+ pkg
16
+ rdoc
17
+ spec/reports
18
+ test/tmp
19
+ test/version_tmp
20
+ tmp
21
+ tags
data/.rspec ADDED
@@ -0,0 +1,4 @@
1
+ --colour
2
+ --format documentation
3
+ --fail-fast
4
+
data/.rubocop.yml ADDED
@@ -0,0 +1,60 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2014-07-01 20:41:04 +0800 using RuboCop version 0.24.0.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 1
9
+ Lint/AmbiguousOperator:
10
+ Enabled: true
11
+
12
+ # Offense count: 1
13
+ Lint/Debugger:
14
+ Enabled: true
15
+
16
+ # Offense count: 4
17
+ Lint/Void:
18
+ Enabled: true
19
+
20
+ # Offense count: 1
21
+ Style/ClassVars:
22
+ Enabled: true
23
+
24
+ # Offense count: 13
25
+ Style/Documentation:
26
+ Enabled: false
27
+
28
+ # Offense count: 1
29
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
30
+ Style/DotPosition:
31
+ Enabled: true
32
+
33
+ # Offense count: 4
34
+ # Configuration parameters: EnforcedStyle, SupportedStyles.
35
+ Style/FormatString:
36
+ Enabled: true
37
+
38
+ # Offense count: 1
39
+ # Configuration parameters: AllowedVariables.
40
+ Style/GlobalVars:
41
+ Enabled: true
42
+
43
+ # Offense count: 1
44
+ # Configuration parameters: AllowURI.
45
+ Style/LineLength:
46
+ Max: 136
47
+
48
+ # Offense count: 7
49
+ # Configuration parameters: CountComments.
50
+ Style/MethodLength:
51
+ Max: 24
52
+
53
+ # Offense count: 1
54
+ # Configuration parameters: CountKeywordArgs.
55
+ Style/ParameterLists:
56
+ Max: 7
57
+
58
+ # Offense count: 2
59
+ Style/RegexpLiteral:
60
+ MaxSlashes: 0
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.1
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in larrow-qingcloud.gemspec
4
+ gemspec
5
+ group :test do
6
+ gem 'rspec'
7
+ gem 'pry'
8
+ gem 'pry-nav'
9
+ gem 'simplecov'
10
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,69 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ larrow-qingcloud (0.0.1)
5
+ promising (~> 0.3)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activesupport (4.1.0)
11
+ i18n (~> 0.6, >= 0.6.9)
12
+ json (~> 1.7, >= 1.7.7)
13
+ minitest (~> 5.1)
14
+ thread_safe (~> 0.1)
15
+ tzinfo (~> 1.1)
16
+ coderay (1.1.0)
17
+ diff-lcs (1.2.5)
18
+ docile (1.1.3)
19
+ faraday (0.9.0)
20
+ multipart-post (>= 1.2, < 3)
21
+ i18n (0.6.9)
22
+ json (1.8.1)
23
+ method_source (0.8.2)
24
+ minitest (5.3.3)
25
+ multi_json (1.9.3)
26
+ multipart-post (2.0.0)
27
+ promising (0.3.1)
28
+ pry (0.9.12.6)
29
+ coderay (~> 1.0)
30
+ method_source (~> 0.8)
31
+ slop (~> 3.4)
32
+ pry-nav (0.2.3)
33
+ pry (~> 0.9.10)
34
+ rake (0.9.6)
35
+ rspec (3.0.0)
36
+ rspec-core (~> 3.0.0)
37
+ rspec-expectations (~> 3.0.0)
38
+ rspec-mocks (~> 3.0.0)
39
+ rspec-core (3.0.3)
40
+ rspec-support (~> 3.0.0)
41
+ rspec-expectations (3.0.3)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.0.0)
44
+ rspec-mocks (3.0.3)
45
+ rspec-support (~> 3.0.0)
46
+ rspec-support (3.0.3)
47
+ simplecov (0.8.2)
48
+ docile (~> 1.1.0)
49
+ multi_json
50
+ simplecov-html (~> 0.8.0)
51
+ simplecov-html (0.8.0)
52
+ slop (3.5.0)
53
+ thread_safe (0.3.3)
54
+ tzinfo (1.1.0)
55
+ thread_safe (~> 0.1)
56
+
57
+ PLATFORMS
58
+ ruby
59
+
60
+ DEPENDENCIES
61
+ activesupport (~> 4.1)
62
+ bundler (~> 1.5)
63
+ faraday (~> 0)
64
+ larrow-qingcloud!
65
+ pry
66
+ pry-nav
67
+ rake (~> 0)
68
+ rspec
69
+ simplecov
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 lifu
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,39 @@
1
+ # Larrow::Qingcloud
2
+
3
+ A simple wrapper for Qingcloud(IAAS)
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'larrow-qingcloud'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install larrow-qingcloud
18
+
19
+ ## Sample
20
+ before use Qingcloud API, you should establish connection first:
21
+
22
+ Qingcloud.establish_connection <your_access_id>, <your_secret_key>
23
+
24
+ * list images
25
+
26
+ images = Qingcloud::Image.describe
27
+
28
+ * create and destroy instance
29
+
30
+ objs = Qingcloud::Instance.create count: 1
31
+ Qingcloud::Instance.destroy instance_ids: objs.map(&:instance_id)
32
+
33
+ ## Contributing
34
+
35
+ 1. Fork it ( http://github.com/<my-github-username>/larrow-qingcloud/fork )
36
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
37
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
38
+ 4. Push to the branch (`git push origin my-new-feature`)
39
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'larrow/qingcloud/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'larrow-qingcloud'
8
+ spec.version = Larrow::Qingcloud::VERSION
9
+ spec.authors = ['fsword']
10
+ spec.email = ['li.jianye@gmail.com']
11
+ spec.summary = "qingcloud's ruby sdk, unofficial version"
12
+ spec.description = 'access qingcloud with a simple way for ruby programmer'
13
+ spec.homepage = 'http://github.com/fsword/larrow-qingcloud'
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_dependency 'promising', '~> 0.3'
22
+ spec.add_development_dependency 'bundler', '~> 1.5'
23
+ spec.add_development_dependency 'rake', '~> 0'
24
+ spec.add_development_dependency 'activesupport', '~> 4.1'
25
+ spec.add_development_dependency 'faraday', '~> 0'
26
+ end
@@ -0,0 +1,139 @@
1
+ require 'timeout'
2
+ module Larrow
3
+ module Qingcloud
4
+ # base class for Qingcloud model
5
+ class Base
6
+ include Logger
7
+ attr_accessor :id, :status, :delegator
8
+
9
+ DESTROY_STATUSES = [:deleted, :ceased,:released]
10
+
11
+ def initialize(id,options={})
12
+ self.id = id
13
+ options.each_pair do |k,v|
14
+ self.send "#{k}=",v
15
+ end
16
+ end
17
+
18
+ # status always be symbol
19
+ def status= status
20
+ @status = status.nil? ? nil : status.to_sym
21
+ end
22
+
23
+ def conn
24
+ self.class.conn
25
+ end
26
+
27
+ def model_name
28
+ self.class.model_name
29
+ end
30
+
31
+ def show(params = {})
32
+ self.class.describe([self.id],params).first
33
+ end
34
+
35
+ # block method, should be delayed at caller function
36
+ def wait_for(status)
37
+ loop do
38
+ data = show
39
+ if data['status'].to_sym == status
40
+ info "#{model_name} status changed: #{id} - #{status}"
41
+ self.status = status
42
+ yield data if block_given?
43
+ break self
44
+ else
45
+ debug "#{model_name} wait for status: #{id} - #{data['status']}"
46
+ end
47
+ sleep 2
48
+ end
49
+ end
50
+
51
+ def self.conn
52
+ Qingcloud.connection
53
+ end
54
+
55
+ # just for state access, such as:
56
+ # model.running?
57
+ # do not affect `respond_to?`
58
+ def method_missing(method, *args, &block)
59
+ if method.to_s.last == '?'
60
+ status == method.to_s[0..-2].to_sym
61
+ else
62
+ super
63
+ end
64
+ end
65
+
66
+ # multi names( used as param_name )
67
+ # KeyPair -> keypair -> keypairs
68
+ def self.model_name
69
+ name.split(/::/).last
70
+ end
71
+ def self.singular_name
72
+ name.split(/::/).last.downcase
73
+ end
74
+ def self.plural_name
75
+ name.split(/::/).last.downcase.pluralize
76
+ end
77
+
78
+ def param_by(*args)
79
+ self.class.param_by(*args)
80
+ end
81
+
82
+ def self.param_by(ids, init_params={})
83
+ ids.each_with_index.reduce(init_params) do |result, (id, index)|
84
+ result.update :"#{plural_name}.#{index + 1}" => id
85
+ end
86
+ end
87
+
88
+ # convert hash data to object when block given
89
+ def self.describe(ids, params)
90
+ params = param_by(ids, params)
91
+ datas = conn.service(
92
+ 'get', "Describe#{model_name}s", params
93
+ )["#{singular_name}_set"]
94
+ if block_given?
95
+ datas.map do |data|
96
+ yield data
97
+ end
98
+ else
99
+ datas
100
+ end
101
+ end
102
+
103
+ # destroy method generator
104
+ #
105
+ # destroy can be called by end user, so it will return a future
106
+ def self.destroy_action(action)
107
+ define_method :destroy do
108
+ params = self.class.param_by [id]
109
+ future(timeout:90) do
110
+ loop do
111
+ begin
112
+ result = conn.get action, params
113
+ info "destroy #{self.class.name}: #{result}"
114
+ break result['ret_code'] == 0
115
+ rescue ServiceError => e
116
+ if e.message =~ /has already been deleted/
117
+ break :already_deleted
118
+ else
119
+ sleep 2
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ define_method :ensure_destroy do
126
+ params = self.class.param_by [id]
127
+ future(timeout:90) do
128
+ loop do
129
+ break true if DESTROY_STATUSES.include?(@status)
130
+ conn.get action, params rescue nil
131
+ sleep 2
132
+ @status = show['status'].to_sym
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end
@@ -0,0 +1,61 @@
1
+ require 'faraday'
2
+ require 'cgi'
3
+ require 'openssl'
4
+ require 'base64'
5
+ require 'json'
6
+
7
+ module Larrow
8
+ module Qingcloud
9
+ # Connection delegator for Qingcloud
10
+ class Connection
11
+ include Logger
12
+ URL_TEMPLATE = 'https://api.qingcloud.com/iaas/?%s&signature=%s'
13
+ attr_accessor :access_key, :secret_key, :zone_id
14
+
15
+ def initialize(access_key, secret_key, zone_id)
16
+ self.access_key = access_key
17
+ self.secret_key = secret_key
18
+ self.zone_id = zone_id
19
+ end
20
+
21
+ def service(method, action, params = {})
22
+ # Time.new.iso8601 cannot be recognized
23
+ time_stamp = Time.new.utc.strftime '%Y-%m-%dT%TZ'
24
+ params.update(
25
+ zone: zone_id,
26
+ action: action,
27
+ time_stamp: time_stamp,
28
+ access_key_id: access_key,
29
+ version: 1,
30
+ signature_method: 'HmacSHA256',
31
+ signature_version: 1
32
+ )
33
+
34
+ request_str = params.keys.sort.map do |k|
35
+ "#{CGI.escape k.to_s}=#{CGI.escape params[k].to_s}"
36
+ end.join('&')
37
+
38
+ signed_text = format "%s\n/iaas/\n%s", method.upcase, request_str
39
+
40
+ signature = Base64.encode64(OpenSSL::HMAC.digest(
41
+ OpenSSL::Digest.new('sha256'), secret_key||'', signed_text
42
+ )).strip
43
+
44
+ url = format URL_TEMPLATE, request_str, CGI.escape(signature)
45
+ resp = Faraday.send(method.to_sym, url)
46
+ debug "API #{action} #{request_str}"
47
+
48
+ JSON.parse(resp.body).tap do |obj|
49
+ if obj['ret_code'] != 0
50
+ debug "Service Error(#{obj['ret_code']}): #{obj['message']}"
51
+ fail ServiceError, obj['message']
52
+ end
53
+ end
54
+ end
55
+
56
+ def get action, params = {}
57
+ service 'get', action, params
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,41 @@
1
+ module Larrow
2
+ module Qingcloud
3
+ # External address
4
+ class Eip < Base
5
+ attr_accessor :address
6
+ destroy_action 'ReleaseEips'
7
+
8
+ def self.create(bandwidth:1, count:1)
9
+ result = conn.service 'get', 'AllocateEips',
10
+ bandwidth: bandwidth,
11
+ count: count
12
+
13
+ info "EIP added: #{result['eips']}"
14
+ result['eips'].map do |id|
15
+ promise(timeout:60){ new(id).wait_for :available }
16
+ end
17
+ end
18
+
19
+ def wait_for(status)
20
+ super do |data|
21
+ self.address = data['eip_addr']
22
+ end
23
+ end
24
+
25
+ def associate(instance_id)
26
+ conn.service 'get', 'AssociateEip',
27
+ instance: instance_id,
28
+ eip: id
29
+ promise(timeout:60){ wait_for :associated }
30
+ end
31
+
32
+ # cannot support batch dissociating
33
+ def dissociate(instance_id)
34
+ conn.service 'get', 'DissociateEips',
35
+ :instance => instance_id,
36
+ :'eips.1' => id
37
+ promise(timeout:60){ wait_for :available }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,3 @@
1
+ module Larrow::Qingcloud
2
+ ServiceError = Class.new(StandardError)
3
+ end
@@ -0,0 +1,38 @@
1
+ module Larrow
2
+ module Qingcloud
3
+ class Image < Base
4
+ attr_accessor :platform, :provider
5
+ destroy_action 'DeleteImages'
6
+
7
+ def self.list(provider=:system,ids:[])
8
+ describe(ids,{:provider => provider,:'status.1' => :available}) do |hash|
9
+ new hash['image_id'],
10
+ hash.slice('status','platform','provider')
11
+ end
12
+ end
13
+
14
+ def self.create instance_id
15
+ result = conn.get 'CaptureInstance', instance: instance_id
16
+ info "image created(instance: #{instance_id}): #{result}"
17
+ image = new result['image_id']
18
+ promise(timeout:90){ image.wait_for :available }
19
+ end
20
+
21
+ def self.create_from_snapshot snapshot_id
22
+ result = conn.get 'CaptureInstanceFromSnapshot', snapshot: snapshot_id
23
+ info "image created(snapshot: #{snapshot_id}): #{result}"
24
+ image = new result['image_id']
25
+ promise(timeout:90){ image.wait_for :available }
26
+ end
27
+
28
+ def wait_for status
29
+ super do |data|
30
+ self.status = status
31
+ self.platform = data['platform']
32
+ self.provider = data['provider']
33
+ end
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,78 @@
1
+ module Larrow
2
+ module Qingcloud
3
+ class Instance < Base
4
+ attr_accessor :vxnet_id, :keypair_id
5
+
6
+ destroy_action 'TerminateInstances'
7
+
8
+ # return an array(running instance)
9
+ def self.create(image_id:nil,
10
+ cpu:1,
11
+ memory:1024,
12
+ count:1,
13
+ login_mode: 'passwd',
14
+ passwd:'1qaz@WSX',
15
+ keypair_id:nil,
16
+ vxnet_id:'vxnet-0')
17
+ err 'The default password is weak, you should change it'
18
+
19
+ image_id ||= 'trustysrvx64b'
20
+
21
+ result = conn.service 'get', 'RunInstances',
22
+ :image_id => image_id,
23
+ :cpu => cpu,
24
+ :memory => memory,
25
+ :count => count,
26
+ :login_mode => login_mode,
27
+ :login_passwd => passwd,
28
+ :'login_keypair' => keypair_id,
29
+ :'vxnets.n' => vxnet_id
30
+
31
+ info "instance added: #{result['instances']}"
32
+ result['instances'].map do |id|
33
+ instance = new id,keypair_id: keypair_id,vxnet_id:vxnet_id
34
+ promise(timeout:90){ instance.wait_for :running }
35
+ end
36
+ end
37
+
38
+ def attach_keypair(keypair_id)
39
+ return self if self.keypair_id
40
+ conn.service 'get', 'AttachKeyPairs',
41
+ :'instances.1' => id,
42
+ :'keypairs.1' => keypair_id
43
+ loop do
44
+ if show(verbose: 1)['keypair_ids'].count > 0
45
+ self.keypair_id = keypair_id
46
+ info "instance attach keypair: #{id}"
47
+ break self
48
+ end
49
+ sleep 2
50
+ end
51
+ end
52
+
53
+ def join_vxnet(vxnet_id = 'vxnet-0')
54
+ return self if self.vxnet_id
55
+ params = param_by [id], vxnet: vxnet_id
56
+ conn.service 'get', 'JoinVxnet', params
57
+ loop do
58
+ if show['vxnets'].size > 0
59
+ self.vxnet_id = vxnet_id
60
+ info "instance joined vxnet: #{id}"
61
+ break self
62
+ end
63
+ sleep 2
64
+ end
65
+ end
66
+
67
+ # return a delayed instance object
68
+ def stop force=nil
69
+ if force
70
+ conn.get 'StopInstances', :'instances.1' => id, :force => 1
71
+ else
72
+ conn.get 'StopInstances', :'instances.1' => id
73
+ end
74
+ promise(timeout:60){ wait_for :stopped }
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,17 @@
1
+ module Larrow
2
+ module Qingcloud
3
+ class KeyPair < Base
4
+ attr_accessor :id, :name
5
+ def self.list()
6
+ describe([],{}) do |hash|
7
+ new hash['keypair_id'],hash['keypair_name']
8
+ end
9
+ end
10
+
11
+ def initialize id,name
12
+ self.id = id
13
+ self.name = name
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,51 @@
1
+ require 'logger'
2
+ module Larrow
3
+ module Qingcloud
4
+ def self.logger= logger
5
+ @@logger = logger
6
+ end
7
+ # Qingcloud logger
8
+ # default log file: $current_dir/qingcloud.log
9
+ module Logger
10
+ def self.included(base)
11
+ base.extend ClassMethods
12
+ end
13
+
14
+ module ClassMethods
15
+ def logger
16
+ @logger ||= begin
17
+ if Qingcloud.class_variable_defined? '@@logger'
18
+ Qingcloud.class_variable_get '@@logger'
19
+ else
20
+ ::Logger.new('qingcloud.log')
21
+ end
22
+ end
23
+ end
24
+
25
+ def debug(msg)
26
+ logger.debug msg
27
+ end
28
+
29
+ def info(msg)
30
+ logger.info msg
31
+ end
32
+
33
+ def err(msg)
34
+ logger.error msg
35
+ end
36
+ end
37
+
38
+ def debug(msg)
39
+ self.class.debug msg
40
+ end
41
+
42
+ def info(msg)
43
+ self.class.info msg
44
+ end
45
+
46
+ def err(msg)
47
+ self.class.err msg
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,23 @@
1
+ module Larrow
2
+ module Qingcloud
3
+ class Snapshot < Base
4
+ attr_accessor :resource
5
+
6
+ destroy_action 'DeleteSnapshots'
7
+
8
+ def self.list()
9
+ describe([],{:'status.1' => :available}) do |hash|
10
+ new hash['snapshot_id'], hash.slice('status','resource')
11
+ end
12
+ end
13
+
14
+ def self.create resource_id
15
+ result = conn.get 'CreateSnapshots', :'resources.1' => resource_id
16
+ info "snapshot added: #{result}"
17
+ result['snapshots'].map do |id|
18
+ promise(timeout:90){ new(id).wait_for :available }
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module Larrow
2
+ module Qingcloud
3
+ VERSION = '0.0.1'
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ require 'active_support/deprecation'
2
+ require 'active_support/core_ext/string'
3
+ require 'active_support/core_ext/hash'
4
+ require 'promising'
5
+
6
+ module Larrow
7
+ # Qingcloud ruby sdk
8
+ module Qingcloud
9
+ def self.establish_connection(access_key, secret_key, zone_id)
10
+ @connection ||= Connection.new access_key, secret_key, zone_id
11
+ end
12
+
13
+ def self.remove_connection
14
+ @connection = nil
15
+ end
16
+
17
+ class << self
18
+ attr_reader :connection
19
+ end
20
+ autoload :Instance, 'larrow/qingcloud/instance'
21
+ autoload :Eip, 'larrow/qingcloud/eip'
22
+ autoload :Image, 'larrow/qingcloud/image'
23
+ autoload :Snapshot, 'larrow/qingcloud/snapshot'
24
+ autoload :KeyPair, 'larrow/qingcloud/key_pair'
25
+ end
26
+ end
27
+
28
+ require 'larrow/qingcloud/version'
29
+ require 'larrow/qingcloud/logger'
30
+ require 'larrow/qingcloud/errors'
31
+ require 'larrow/qingcloud/connection'
32
+ require 'larrow/qingcloud/base'
data/spec/base_spec.rb ADDED
@@ -0,0 +1,17 @@
1
+ require 'spec_helper.rb'
2
+
3
+ module Larrow
4
+ module Qingcloud
5
+ describe Base do
6
+ it 'param_by' do
7
+ expect(Base.param_by %w(a b c),
8
+ key: 'somevalue'
9
+ ).to eq(:'bases.1' => 'a',
10
+ :'bases.2' => 'b',
11
+ :'bases.3' => 'c',
12
+ :key => 'somevalue'
13
+ )
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,40 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module Larrow::Qingcloud
4
+ describe Image do
5
+
6
+ let(:base_image) do
7
+ Image.list.select do |i|
8
+ i.status == :available and i.platform == 'linux'
9
+ end.first
10
+ end
11
+
12
+ it 'list not empty' do
13
+ expect(Image.list).not_to be_empty
14
+ end
15
+
16
+ it 'capture instance' do
17
+ instance = Instance.
18
+ create(image_id: base_image.id).
19
+ first.
20
+ stop(true)
21
+ new_image = Image.create instance.id
22
+ expect(new_image.status).to eq :available
23
+
24
+ expect(instance.destroy).to be true
25
+ expect(new_image.destroy).to be true
26
+ end
27
+
28
+ it 'create from snapshot' do
29
+ instance = Instance.
30
+ create(image_id: base_image.id).
31
+ first
32
+ snapshot = Snapshot.create(instance.id).first
33
+ new_image = Image.create_from_snapshot snapshot.id
34
+
35
+ expect(instance.destroy).to be true
36
+ expect(snapshot.destroy).to be true
37
+ expect(new_image.destroy).to be true
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,11 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module Larrow::Qingcloud
4
+ describe KeyPair do
5
+
6
+ it 'list not empty' do
7
+ expect(KeyPair.list).not_to be_empty
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper.rb'
2
+
3
+ module Larrow::Qingcloud
4
+ describe 'simple story' do
5
+ it 'use_instance_by_password' do
6
+ # create instance and eip
7
+ instance = Instance.create.first
8
+ eip = Eip.create.first
9
+
10
+ # bind eip to instance
11
+ eip = eip.associate instance.id
12
+ eip = eip.dissociate instance.id
13
+
14
+ # destroy instance and eip
15
+ expect(instance.destroy.force).to be true
16
+ expect(eip.ensure_destroy).to be true
17
+ expect(eip.destroy).to eq(:already_deleted)
18
+ expect(eip.ensure_destroy).to be true
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'spec_helper'
2
+
3
+ module Larrow::Qingcloud
4
+ describe Snapshot do
5
+ let(:base_image) do
6
+ Image.list.select do |i|
7
+ i.status == :available and i.platform == 'linux'
8
+ end.first
9
+ end
10
+
11
+ it 'list not fail' do
12
+ expect{Snapshot.list}.not_to raise_error
13
+ end
14
+
15
+ it 'create snapshot' do
16
+ instance = Instance.
17
+ create(image_id: base_image.id).
18
+ first
19
+ snapshot = Snapshot.create(instance.id).first
20
+ expect(snapshot.status).to eq :available
21
+
22
+ expect(instance.destroy).to be true
23
+ expect(snapshot.destroy).to be true
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ $LOAD_PATH << File.expand_path('../../lib', __FILE__)
2
+ require 'larrow/qingcloud'
3
+ require 'pry'
4
+ require 'pry-nav'
5
+ require 'simplecov'
6
+ require 'yaml'
7
+ SimpleCov.start
8
+
9
+ module Helpers
10
+ extend self
11
+ include Larrow
12
+
13
+ def load_by_default
14
+ args = read_content_as_hash
15
+ [args['qy_access_key_id'],
16
+ args['qy_secret_access_key'],
17
+ args['zone_id']]
18
+ end
19
+
20
+ def read_content_as_hash
21
+ file = "#{ENV['HOME']}/.larrow"
22
+ fail "cannot find keyfile: #{file}" unless File.exist?(file)
23
+ YAML.load(File.read file)['qingcloud']
24
+ end
25
+
26
+ def establish_connection
27
+ access, secret, zone_id = load_by_default
28
+ Qingcloud.establish_connection access, secret, zone_id
29
+ end
30
+ end
31
+
32
+ Helpers.establish_connection
metadata ADDED
@@ -0,0 +1,147 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: larrow-qingcloud
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - fsword
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-10-06 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: promising
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.1'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: access qingcloud with a simple way for ruby programmer
84
+ email:
85
+ - li.jianye@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".rubocop.yml"
93
+ - ".ruby-version"
94
+ - Gemfile
95
+ - Gemfile.lock
96
+ - LICENSE.txt
97
+ - README.md
98
+ - Rakefile
99
+ - larrow-qingcloud.gemspec
100
+ - lib/larrow/qingcloud.rb
101
+ - lib/larrow/qingcloud/base.rb
102
+ - lib/larrow/qingcloud/connection.rb
103
+ - lib/larrow/qingcloud/eip.rb
104
+ - lib/larrow/qingcloud/errors.rb
105
+ - lib/larrow/qingcloud/image.rb
106
+ - lib/larrow/qingcloud/instance.rb
107
+ - lib/larrow/qingcloud/key_pair.rb
108
+ - lib/larrow/qingcloud/logger.rb
109
+ - lib/larrow/qingcloud/snapshot.rb
110
+ - lib/larrow/qingcloud/version.rb
111
+ - spec/base_spec.rb
112
+ - spec/image_spec.rb
113
+ - spec/key_pair_spec.rb
114
+ - spec/simple_story_spec.rb
115
+ - spec/snapshot_spec.rb
116
+ - spec/spec_helper.rb
117
+ homepage: http://github.com/fsword/larrow-qingcloud
118
+ licenses:
119
+ - MIT
120
+ metadata: {}
121
+ post_install_message:
122
+ rdoc_options: []
123
+ require_paths:
124
+ - lib
125
+ required_ruby_version: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: '0'
130
+ required_rubygems_version: !ruby/object:Gem::Requirement
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ version: '0'
135
+ requirements: []
136
+ rubyforge_project:
137
+ rubygems_version: 2.2.2
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: qingcloud's ruby sdk, unofficial version
141
+ test_files:
142
+ - spec/base_spec.rb
143
+ - spec/image_spec.rb
144
+ - spec/key_pair_spec.rb
145
+ - spec/simple_story_spec.rb
146
+ - spec/snapshot_spec.rb
147
+ - spec/spec_helper.rb