larrow-qingcloud 0.0.1

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