qc.rb 0.0.1 → 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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +126 -0
  3. data/bin/qc +36 -7
  4. data/lib/qc.rb +135 -43
  5. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4580a07ef6b2a0ce936e3044b00dc5d1d6d1b777
4
- data.tar.gz: 5eb71554537db1e81fef56c5e337dc7a72859c06
3
+ metadata.gz: 5dccf331efcb29098e651c3865f5d4d63f019586
4
+ data.tar.gz: 066553273f56fcbd831063096393b7bced68ce9c
5
5
  SHA512:
6
- metadata.gz: 673d374b1847215fea439935597aadde90e9b25b7ac29b347dbc889203752f1a12d22712ef443ca3651c400210859ff17177fa6257a10841afc7ba962bfe1c8c
7
- data.tar.gz: fa0e2d2b7bdb3dd6133745e72517451a6b73c177d95ea3e8145f88d5ccda80e14a0babd3bcb49928d5b261bd4d2dd961a441af08dc7e2fba31631dfc6e6d1681
6
+ metadata.gz: 1a25f3e039f696056512a592178509232ade5119662f25eb12f1473d4a1c722d89813cbf809b8f648364ee5f467cf84d5a3c1ecd2269ed14ab443a0700b08077
7
+ data.tar.gz: 4060d4ae2a012ec7ad54ba05763cd7b0a12812948b31730f929be7cbc6714ee843b607af14e8ed93c659d9751800f5e0d6d9f251088c1b5d3f8db55a25ced1fb
data/README.md CHANGED
@@ -2,3 +2,129 @@ qc.rb
2
2
  =====
3
3
 
4
4
  QingCloud API Library to handle instances, networks, etc. on QingCloud.com
5
+
6
+ ### Installation
7
+
8
+ You can install *qc.rb* via RubyGems:
9
+
10
+ ```bash
11
+ gem install qc.rb
12
+ ```
13
+
14
+ ### Important Notice
15
+
16
+ I'm not a native chinese speaker! Yet the complete documentation of QingCloud.com is in chinese! Due to that it is reasonable to expect that my understanding of the API might not be 100% correct! You are very welcome to improve the code!
17
+
18
+ ### Usage
19
+
20
+ You can use *qc.rb* via *qc* as a CLI or direct as a Ruby library.
21
+
22
+ #### SSH
23
+
24
+ Get all public keys:
25
+
26
+ CLI Version:
27
+
28
+ ```bash
29
+ qc ssh describe
30
+ ```
31
+
32
+ .rb Version:
33
+
34
+ ```ruby
35
+ # Each Public Key is available in *s*
36
+ QC::KeyPair.describe {|s| puts s}
37
+ ```
38
+
39
+ #### Instances
40
+
41
+ Get all instances:
42
+
43
+ CLI Version:
44
+
45
+ ```bash
46
+ qc ins describe
47
+ ```
48
+
49
+ .rb Version:
50
+
51
+ ```ruby
52
+ # Each instance is available in *i*
53
+ QC::Instance.describe {|i| puts i}
54
+ ```
55
+
56
+ Create new Instance:
57
+
58
+ ```ruby
59
+ QC::Instance.run instance_name: 'NameOfInstance', login_keypair: 'kp-sadasd67' # => instance_id
60
+ ```
61
+
62
+ Delete Instance:
63
+
64
+ ```ruby
65
+ i = QC::Instance.load 'i-adssad7'
66
+ i.terminate! # => {"action"=>"TerminateInstancesResponse", "job_id"=>"j-asd7djk", "ret_code"=>0}
67
+ ```
68
+
69
+ Add IP device to Instance:
70
+
71
+ ```ruby
72
+ i = QC::Instance.load 'i-adssad7'
73
+ i.ip = 'eip-sadjkdsa7' # => 'eip-sadjkdsa7'
74
+ ```
75
+
76
+ #### IPs
77
+
78
+ Get all IPs:
79
+
80
+ CLI Version:
81
+
82
+ ```bash
83
+ qc ip describe
84
+ ```
85
+
86
+ .rb Version:
87
+
88
+ ```ruby
89
+ # Each IP is available in *i*
90
+ QC::Eip.describe {|i| puts i}
91
+ ```
92
+
93
+ Allocate new IP:
94
+
95
+ ```ruby
96
+ # Create IP width bandwidth 3MB
97
+ Eip.allocate bandwidth: 3 # => eip_id
98
+ ```
99
+
100
+ Release IP:
101
+
102
+ ```ruby
103
+ # Release IP with ID 'eip-12djpg8q'
104
+ Eip.load('eip-12djpg8q').release! # => true | false
105
+ ```
106
+
107
+ Change Bandwidth:
108
+
109
+ ```ruby
110
+ # Change bandwidth of IP with ID 'eip-12djpg8q' to 2MB
111
+ ip = Eip.load('eip-12djpg8q')
112
+ ip.bandwidth = 2 # => 2
113
+ ```
114
+
115
+ #### Volumes
116
+
117
+ Get all Volumes:
118
+
119
+ CLI Version:
120
+
121
+ ```bash
122
+ qc vol describe
123
+ ```
124
+
125
+ .rb Version:
126
+
127
+ ```ruby
128
+ # Each Volume is available in *v*
129
+ QC::Volume.describe {|v| puts v}
130
+ ```
data/bin/qc CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'qc'
3
+ require "#{File.dirname(__FILE__)}/../lib/qc.rb"
4
4
 
5
5
  def help_header cmd, options
6
6
  <<HEADER
@@ -16,24 +16,53 @@ HEADER
16
16
  end
17
17
 
18
18
  case ARGV[0]
19
+ when 'vol'
20
+ case ARGV[1]
21
+ when 'describe'
22
+ QC::Volume.describe {|v| puts v}
23
+ else
24
+ puts help_header('vol [option]', <<HELP)
25
+ describe List all volumes
26
+ HELP
27
+ end
19
28
  when 'ssh'
20
29
  case ARGV[1]
21
- when 'list'
22
- QC::SSH.each {|s| puts s}
30
+ when 'describe'
31
+ QC::KeyPair.describe {|s| puts s}
23
32
  else
24
33
  puts help_header('ssh [option]', <<HELP)
25
- list List all public keys
34
+ describe List all public keys
26
35
  HELP
27
36
  end
28
37
  when 'ins'
29
38
  case ARGV[1]
30
- when 'list'
31
- QC::Instance.each {|s| puts s}
39
+ when 'describe'
40
+ QC::Instance.describe {|i| puts i}
32
41
  else
33
42
  puts help_header('ins [option]', <<HELP)
34
- list List all machines
43
+ describe List all machines
44
+ HELP
45
+ end
46
+ when 'ip'
47
+ case ARGV[1]
48
+ when 'describe'
49
+ QC::Eip.describe {|s| puts s}
50
+ else
51
+ puts help_header('ip [option]', <<HELP)
52
+ describe List all IPs
35
53
  HELP
36
54
  end
55
+
56
+ when 'img'
57
+ case ARGV[1]
58
+ when 'describe'
59
+ QC::Image.describe.sort.each {|s| puts s}
60
+ else
61
+ puts help_header('img [option]', <<HELP)
62
+ describe List all Images
63
+ HELP
64
+ end
65
+
37
66
  else
38
67
  puts help_header('[option]', <<HELP)
39
68
  ssh SSH Key Management
data/lib/qc.rb CHANGED
@@ -7,7 +7,7 @@ require 'yaml'
7
7
  require 'fileutils'
8
8
 
9
9
  module QC
10
- VERSION = '0.0.1'
10
+ VERSION = '0.0.2'
11
11
 
12
12
  def QC.load_config key
13
13
  f = File.expand_path('~/.qingcloud/config.yaml')
@@ -56,58 +56,135 @@ module QC
56
56
  url_b64_hmac = CGI.escape(b64_hmac)
57
57
  end
58
58
 
59
- class SSH
60
- def initialize s
61
- @id = s['keypair_id']
62
- @name = s['keypair_name']
63
- @date = s['create_time']
64
- @e_method = s['encrypt_method']
65
- @desc = s['description']
66
- @key = s['pub_key']
59
+ class DataType
60
+ attr_reader :result
61
+
62
+ @identifier = 'NOT_IMPLEMENTED'
63
+
64
+ def initialize h
65
+ @values = h
67
66
  end
68
67
 
69
68
  def to_s
70
- <<STR
71
- ID: "#{@id}"
72
- Name: "#{@name}"
73
- Creation Date: "#{@date}"
74
- Encryption Method: "#{@e_method}"
75
- Description: "#{@desc}"
76
- Public Key:
77
- "#{@key}"
78
- STR
69
+ @values.to_yaml
70
+ end
71
+
72
+ def method_missing met
73
+ if @values.has_key? met.to_s
74
+ @values[met.to_s]
75
+ else
76
+ raise NoMethodError.new "undefined method `#{met}'"
77
+ end
78
+ end
79
+
80
+ def self.describe p = {}, &block
81
+ req = QC::API::Request.new "Describe#{@identifier}s", p
82
+ @result = req.execute!(QC::Key)
83
+ if block_given?
84
+ @result["#{@identifier.downcase}_set"].to_a.each {|s| block.call(self.new(s))}
85
+ else
86
+ @result["#{@identifier.downcase}_set"].to_a.map {|s| self.new(s)}
87
+ end
88
+ end
89
+ end
90
+
91
+ class KeyPair < DataType
92
+ @identifier = 'KeyPair'
93
+ end
94
+
95
+ class Instance < DataType
96
+ @identifier = 'Instance'
97
+
98
+ def Instance.run p = {image_id: 'precisex64a', instance_name: nil, count: 1, login_mode: 'keypair',
99
+ login_keypair: nil, login_passwd: nil, security_group: nil, zone: nil, instance_type: 'small_b'}
100
+ p[:image_id] = 'precisex64a' if p[:image_id].nil?
101
+ p[:login_mode] = 'keypair' if p[:login_mode].nil?
102
+ p[:instance_type] = 'small_b' if p[:instance_type].nil?
103
+ p['vxnets.1'] = 'vxnet-0' if p['vxnets.1'].nil?
104
+ ret = API::Request.execute! 'RunInstances', p
105
+ ret['instances']
106
+ end
107
+
108
+ def Instance.load instance_id
109
+ Instance.describe('instances.1' => instance_id)[0]
110
+ end
111
+
112
+ def terminate!
113
+ p = {'instances.1' => @values['instance_id']}
114
+ API::Request.execute!('TerminateInstances', p)
115
+ end
116
+
117
+ def ip= eip_id
118
+ p = {'instance' => @values['instance_id'], 'eip' => eip_id}
119
+ API::Request.execute!('AssociateEip', p)
120
+ end
121
+ end
122
+
123
+ class Volume < DataType
124
+ @identifier = 'Volume'
125
+ end
126
+
127
+ class Eip < DataType
128
+ @identifier = 'Eip'
129
+
130
+ def Eip.allocate p = {bandwidth: 1, eip_name: nil, count: 1, need_icp: nil, zone: nil}
131
+ ret = API::Request.execute! 'AllocateEips', p
132
+ if ret.respond_to? :has_key?
133
+ ret['eips']
134
+ else
135
+ false
136
+ end
137
+ end
138
+
139
+ def Eip.release eips: [], zone: nil
140
+ if eips.size > 0
141
+ p = {}
142
+ 1.upto(eips.size).each { |i| p["eips.#{i}"] = eips[i-1] }
143
+ p[:zone] = zone
144
+ API::Request.execute!('ReleaseEips', p)
145
+ else
146
+ false
147
+ end
79
148
  end
80
149
 
81
- def SSH.each &block
82
- r = QC::API::Request.new 'DescribeKeyPairs'
83
- r.execute!(QC::Key)['keypair_set'].to_a.each {|s| block.call(SSH.new(s))}
150
+ def Eip.load eip_id
151
+ Eip.describe('eips.1' => eip_id)[0]
152
+ end
153
+
154
+ def bandwidth= b
155
+ p = {'eips.1' => @values['eip_id'], 'bandwidth' => b}
156
+ ret = API::Request.execute!('ChangeEipsBandwidth', p)
157
+ if ret.respond_to? :has_key?
158
+ b
159
+ else
160
+ false
161
+ end
162
+ end
163
+
164
+ def release!
165
+ p = {'eips.1' => @values['eip_id']}
166
+ API::Request.execute!('ReleaseEips', p)
84
167
  end
85
168
  end
86
169
 
87
- class Instance
88
- def initialize s
89
- @id = s['instance_id']
90
- @name = s['instance_name']
91
- @type = s['instance_type']
92
- @vcpu = s['vcpu_current']
93
- @desc = s['description']
94
- @status = s['status']
170
+ class Image < DataType
171
+ include Comparable
172
+ @identifier = 'Image'
173
+
174
+ def Image.describe p = {}, &block
175
+ _p = p.dup
176
+ unless _p.has_key? 'provider'
177
+ _p['provider'] = 'system'
178
+ end
179
+ super _p, &block
95
180
  end
96
181
 
97
182
  def to_s
98
- <<STR
99
- ID: "#{@id}"
100
- Name: "#{@name}"
101
- Type: "#{@type}"
102
- VCPU: "#{@vcpu}"
103
- Description: "#{@desc}"
104
- Status: "#{@status}"
105
- STR
183
+ [@values['image_id'], @values['image_name']].to_yaml
106
184
  end
107
185
 
108
- def Instance.each &block
109
- r = QC::API::Request.new 'DescribeInstances'
110
- r.execute!(QC::Key)['instance_set'].to_a.each {|s| block.call(Instance.new(s))}
186
+ def <=> o
187
+ @values['image_id'] <=> o.image_id
111
188
  end
112
189
  end
113
190
 
@@ -115,7 +192,17 @@ STR
115
192
  class Request
116
193
  attr_reader :response
117
194
 
118
- def initialize action, extra_params = []
195
+ def Request.execute! a, p = {}
196
+ req = QC::API::Request.new a, p
197
+ @result = req.execute!(QC::Key)
198
+ if @result['ret_code'] == 0
199
+ @result
200
+ else
201
+ raise ArgumentError.new("#{@result['ret_code']}: #{@result['message']}")
202
+ end
203
+ end
204
+
205
+ def initialize action, extra_params = {}
119
206
  @response = :not_requested
120
207
 
121
208
  @params = []
@@ -123,8 +210,13 @@ STR
123
210
  @params << ['access_key_id', QC::AccessKeyId]
124
211
  @params << ['signature_method', 'HmacSHA256']
125
212
  @params << ['signature_version', 1]
126
- @params << ['zone', QC::Zone]
127
- extra_params.each {|i| @params << i}
213
+ zone_set = false
214
+ extra_params.each_pair do |k,v|
215
+ zone_set = true if k == 'zone'
216
+ next if v.nil?
217
+ @params << [k.to_s, v]
218
+ end
219
+ @params << ['zone', QC::Zone] unless zone_set
128
220
  end
129
221
 
130
222
  def execute!(key)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qc.rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Bovensiepen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-15 00:00:00.000000000 Z
11
+ date: 2014-02-16 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: QingCloud API Library to handle instances, networks, internetconnections,
14
14
  etc. on QingCloud.com