qingcloud-sdk 0.2.3
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 +7 -0
- data/.gitignore +13 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE +674 -0
- data/README.md +96 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/qingcloud/sdk/client/connector.rb +89 -0
- data/lib/qingcloud/sdk/client/foundation.rb +73 -0
- data/lib/qingcloud/sdk/client/service.rb +699 -0
- data/lib/qingcloud/sdk/general/contract.rb +19 -0
- data/lib/qingcloud/sdk/general/error.rb +42 -0
- data/lib/qingcloud/sdk/template/qingcloud.json +4 -0
- data/lib/qingcloud/sdk/utility/file_manager.rb +43 -0
- data/lib/qingcloud/sdk/utility/json_parser.rb +41 -0
- data/lib/qingcloud/sdk/utility/logger.rb +19 -0
- data/lib/qingcloud/sdk/version.rb +7 -0
- data/lib/qingcloud/sdk.rb +15 -0
- data/qingcloud-sdk.gemspec +29 -0
- metadata +109 -0
data/README.md
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
# QingCloud::SDK
|
2
|
+
|
3
|
+
SDK for QingCloud
|
4
|
+
|
5
|
+
## Install from RubyGems
|
6
|
+
|
7
|
+
$ gem install qingcloud-sdk
|
8
|
+
|
9
|
+
|
10
|
+
## Install from Source Code
|
11
|
+
|
12
|
+
Get Code from Github:
|
13
|
+
|
14
|
+
$ git clone git@github.com:prettyxw/qingcloud-sdk-ruby.git
|
15
|
+
|
16
|
+
Build and Install with Bundle:
|
17
|
+
|
18
|
+
$ cd qingcloud-sdk-ruby && bundle exec rake install
|
19
|
+
|
20
|
+
## Install using Gemfile
|
21
|
+
|
22
|
+
Add this line to your application's Gemfile:
|
23
|
+
|
24
|
+
```ruby
|
25
|
+
gem 'qingcloud-sdk', git: 'https://github.com/prettyxw/qingcloud-sdk-ruby'
|
26
|
+
```
|
27
|
+
|
28
|
+
And then execute:
|
29
|
+
|
30
|
+
$ bundle install
|
31
|
+
|
32
|
+
## Uninstall
|
33
|
+
|
34
|
+
Using gem to remove this package:
|
35
|
+
|
36
|
+
$ gem uninstall qingcloud-sdk
|
37
|
+
|
38
|
+
## Getting Started
|
39
|
+
|
40
|
+
Before your start, please go to [QingCloud Console](https://console.qingcloud.com/access_keys/) to create a pair of QingCloud API keys.
|
41
|
+
|
42
|
+
## Code Example
|
43
|
+
|
44
|
+
### Create Connection and Service
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
require 'qingcloud/sdk'
|
48
|
+
|
49
|
+
# Create Connection and Service
|
50
|
+
|
51
|
+
connector = QingCloud::SDK::Client::Connector.init(
|
52
|
+
'qy_access_key_id', 'qy_secret_access_key'
|
53
|
+
)
|
54
|
+
|
55
|
+
service = QingCloud::SDK::Client::Service.new connector
|
56
|
+
|
57
|
+
# Describe Instances
|
58
|
+
|
59
|
+
service.describe_instances zone: 'ap1'
|
60
|
+
|
61
|
+
puts service.response
|
62
|
+
|
63
|
+
# Run Instances
|
64
|
+
|
65
|
+
service.run_instances(
|
66
|
+
image_id: 'centos7x64b',
|
67
|
+
cpu: 1,
|
68
|
+
memory: 1024,
|
69
|
+
login_mode: 'keypair',
|
70
|
+
login_keypair: 'keypair-id',
|
71
|
+
zone: 'ap1'
|
72
|
+
)
|
73
|
+
|
74
|
+
puts service.response
|
75
|
+
|
76
|
+
# Terminate Instances
|
77
|
+
|
78
|
+
service.describe_instances instances: ['instance-id'], zone: 'ap1'
|
79
|
+
|
80
|
+
puts service.response
|
81
|
+
```
|
82
|
+
### Describe Zones
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
## Contributing
|
87
|
+
|
88
|
+
1. Fork it ( https://github.com/prettyxw/qingcloud-sdk-ruby/fork )
|
89
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
90
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
91
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
92
|
+
5. Create a new Pull Request
|
93
|
+
|
94
|
+
LICENSE
|
95
|
+
-------
|
96
|
+
The GPL License. Read [GNU General Public License](http://www.gnu.org/licenses/gpl.html) for further information.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "qingcloud/sdk"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
4
|
+
require 'net/http'
|
5
|
+
|
6
|
+
module QingCloud
|
7
|
+
module SDK
|
8
|
+
module Client
|
9
|
+
|
10
|
+
class Connector
|
11
|
+
|
12
|
+
attr_accessor :access_key
|
13
|
+
attr_accessor :secret_key
|
14
|
+
|
15
|
+
def initialize(access_key, secret_key)
|
16
|
+
raise Error::ParameterError, 'Load API Key' unless access_key && access_key.length > 0
|
17
|
+
raise Error::ParameterError, 'Load API Key' unless secret_key && secret_key.length > 0
|
18
|
+
|
19
|
+
self.access_key = access_key
|
20
|
+
self.secret_key = secret_key
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.init(access_key, secret_key)
|
24
|
+
Connector.new access_key, secret_key
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.init_with_config_file
|
28
|
+
config_map = {}
|
29
|
+
content = Utility.file_manager.read_config_file
|
30
|
+
config_map = Utility.json_parser.decode content if content
|
31
|
+
Connector.new config_map['qy_access_key_id'], config_map['qy_secret_access_key']
|
32
|
+
end
|
33
|
+
|
34
|
+
def fetch(action, params={})
|
35
|
+
raise Error::ParameterError, 'Check API Request' unless action && action.length > 0
|
36
|
+
|
37
|
+
params.update(
|
38
|
+
action: action,
|
39
|
+
time_stamp: Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ'),
|
40
|
+
access_key_id: access_key,
|
41
|
+
version: 1,
|
42
|
+
signature_method: 'HmacSHA256',
|
43
|
+
signature_version: 1,
|
44
|
+
)
|
45
|
+
|
46
|
+
request_body = params.sort.map { |key, value|
|
47
|
+
if value.is_a? Array
|
48
|
+
value.map { |v|
|
49
|
+
"#{CGI.escape key.to_s}.#{value.index(v)+1}=#{CGI.escape v.to_s}"
|
50
|
+
}.join('&')
|
51
|
+
else
|
52
|
+
"#{CGI.escape key.to_s}=#{CGI.escape value.to_s}"
|
53
|
+
end
|
54
|
+
}.join('&')
|
55
|
+
|
56
|
+
signature = Base64.encode64(
|
57
|
+
OpenSSL::HMAC.digest(
|
58
|
+
OpenSSL::Digest.new('sha256'),
|
59
|
+
self.secret_key,
|
60
|
+
"GET\n/iaas/\n#{request_body}"
|
61
|
+
)
|
62
|
+
).strip
|
63
|
+
|
64
|
+
request_url = "#{Contract::API_URL}#{request_body}&signature=#{CGI.escape signature}"
|
65
|
+
|
66
|
+
# Log
|
67
|
+
Utility.logger.info request_url
|
68
|
+
|
69
|
+
response = Net::HTTPResponse.new 1.1, 500, 'Error'
|
70
|
+
|
71
|
+
begin
|
72
|
+
response = Net::HTTP.get_response URI(request_url)
|
73
|
+
rescue
|
74
|
+
raise Error::NetworkError
|
75
|
+
end
|
76
|
+
|
77
|
+
raise Error::ServerError, response.code unless response.code == '200'
|
78
|
+
|
79
|
+
# Log
|
80
|
+
Utility.logger.info response.body
|
81
|
+
|
82
|
+
Utility.json_parser.decode response.body
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module QingCloud
|
2
|
+
module SDK
|
3
|
+
module Client
|
4
|
+
|
5
|
+
class Foundation
|
6
|
+
|
7
|
+
ERROR_CODE_MAP = {
|
8
|
+
1100 => 'Request Format Invalid',
|
9
|
+
1200 => 'Authentication Failed',
|
10
|
+
1300 => 'Request Expired',
|
11
|
+
1400 => 'Request Denied',
|
12
|
+
2100 => 'Resource Not Found',
|
13
|
+
2400 => 'Balance Insufficient',
|
14
|
+
2500 => 'Over Quota',
|
15
|
+
5000 => 'Internal Error',
|
16
|
+
5100 => 'Server Busy',
|
17
|
+
5200 => 'Resources Inadequate',
|
18
|
+
5300 => 'Server Updating',
|
19
|
+
}
|
20
|
+
|
21
|
+
attr_accessor :response
|
22
|
+
|
23
|
+
def initialize(connector)
|
24
|
+
@connector = connector
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def fetch_response(action, params={})
|
30
|
+
|
31
|
+
params.map { |key, value|
|
32
|
+
params.delete key unless (value.is_a? Numeric) || (value && value.length > 0)
|
33
|
+
}
|
34
|
+
|
35
|
+
response_body = @connector.fetch action, params
|
36
|
+
|
37
|
+
raise Error::APIError, 'No Response Data Received' unless response_body['ret_code']
|
38
|
+
|
39
|
+
self.response = response_body
|
40
|
+
|
41
|
+
if response_body['ret_code'] != 0
|
42
|
+
raise Error::APIError, response_body['message'] || ERROR_CODE_MAP[response_body['ret_code']]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def merge_maps(maps)
|
47
|
+
final = {}
|
48
|
+
maps.map { |map| final.merge! map }
|
49
|
+
final
|
50
|
+
end
|
51
|
+
|
52
|
+
def build_fetch(action_name)
|
53
|
+
"
|
54
|
+
fetch_response(
|
55
|
+
\"#{action_name}\",
|
56
|
+
eval('merge_maps(method(__method__).parameters.map { |_, p| {p.to_sym => eval(p.to_s)} })')
|
57
|
+
)
|
58
|
+
"
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_fetch_match
|
62
|
+
"
|
63
|
+
fetch_response(
|
64
|
+
__method__.to_s.split('_').map{ |w| w.capitalize! }.join,
|
65
|
+
eval('merge_maps(method(__method__).parameters.map { |_, p| {p.to_sym => eval(p.to_s)} })')
|
66
|
+
)
|
67
|
+
"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|