qc.rb 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +20 -0
- data/README.md +4 -0
- data/bin/qc +49 -0
- data/lib/qc.rb +189 -0
- data/lib/qingcloud.com.cert.pem +31 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4580a07ef6b2a0ce936e3044b00dc5d1d6d1b777
|
4
|
+
data.tar.gz: 5eb71554537db1e81fef56c5e337dc7a72859c06
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 673d374b1847215fea439935597aadde90e9b25b7ac29b347dbc889203752f1a12d22712ef443ca3651c400210859ff17177fa6257a10841afc7ba962bfe1c8c
|
7
|
+
data.tar.gz: fa0e2d2b7bdb3dd6133745e72517451a6b73c177d95ea3e8145f88d5ccda80e14a0babd3bcb49928d5b261bd4d2dd961a441af08dc7e2fba31631dfc6e6d1681
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2014 Daniel Bovensiepen
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
6
|
+
this software and associated documentation files (the "Software"), to deal in
|
7
|
+
the Software without restriction, including without limitation the rights to
|
8
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
9
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
10
|
+
subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
17
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
18
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
19
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
20
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
data/bin/qc
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'qc'
|
4
|
+
|
5
|
+
def help_header cmd, options
|
6
|
+
<<HEADER
|
7
|
+
qc.rb (Version #{QC::VERSION}) is a QingCloud API CLI
|
8
|
+
|
9
|
+
qc #{cmd}
|
10
|
+
|
11
|
+
Options:
|
12
|
+
#{options}
|
13
|
+
Website:
|
14
|
+
https://github.com/qc.rb
|
15
|
+
HEADER
|
16
|
+
end
|
17
|
+
|
18
|
+
case ARGV[0]
|
19
|
+
when 'ssh'
|
20
|
+
case ARGV[1]
|
21
|
+
when 'list'
|
22
|
+
QC::SSH.each {|s| puts s}
|
23
|
+
else
|
24
|
+
puts help_header('ssh [option]', <<HELP)
|
25
|
+
list List all public keys
|
26
|
+
HELP
|
27
|
+
end
|
28
|
+
when 'ins'
|
29
|
+
case ARGV[1]
|
30
|
+
when 'list'
|
31
|
+
QC::Instance.each {|s| puts s}
|
32
|
+
else
|
33
|
+
puts help_header('ins [option]', <<HELP)
|
34
|
+
list List all machines
|
35
|
+
HELP
|
36
|
+
end
|
37
|
+
else
|
38
|
+
puts help_header('[option]', <<HELP)
|
39
|
+
ssh SSH Key Management
|
40
|
+
img Image Managements (available Operator Systems)
|
41
|
+
sec Security Group Management (Firewall rules)
|
42
|
+
ip IP Management (Internet Bandwidth)
|
43
|
+
route Router Managemen
|
44
|
+
net Software Defined Network Management
|
45
|
+
vol Volume Management (add, change and remove HDDs)
|
46
|
+
ins Instance Management (manipulate machines)
|
47
|
+
HELP
|
48
|
+
end
|
49
|
+
|
data/lib/qc.rb
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
require 'openssl'
|
2
|
+
require 'Base64'
|
3
|
+
require 'cgi'
|
4
|
+
require 'json'
|
5
|
+
require 'net/http'
|
6
|
+
require 'yaml'
|
7
|
+
require 'fileutils'
|
8
|
+
|
9
|
+
module QC
|
10
|
+
VERSION = '0.0.1'
|
11
|
+
|
12
|
+
def QC.load_config key
|
13
|
+
f = File.expand_path('~/.qingcloud/config.yaml')
|
14
|
+
if File.exists? f
|
15
|
+
config = YAML.load(File.open(f))
|
16
|
+
if config.has_key? key
|
17
|
+
config[key]
|
18
|
+
else
|
19
|
+
raise "'#{key}' is missing in configuration file"
|
20
|
+
end
|
21
|
+
else
|
22
|
+
puts "'#{f}' doesn't exist!"
|
23
|
+
print "Do you want to create it? (Y/n)"
|
24
|
+
a = $stdin.gets.strip
|
25
|
+
if a == 'n'
|
26
|
+
puts "No configuration file!"
|
27
|
+
exit
|
28
|
+
elsif a.downcase == 'y' or a == ''
|
29
|
+
h = {}
|
30
|
+
print 'Secret Key:'
|
31
|
+
h['qy_secret_access_key'] = $stdin.gets.strip
|
32
|
+
print 'Access Key ID:'
|
33
|
+
h['qy_access_key_id'] = $stdin.gets.strip
|
34
|
+
print 'Zone:'
|
35
|
+
h['zone'] = $stdin.gets.strip
|
36
|
+
begin
|
37
|
+
FileUtils.mkdir_p(File.dirname(f))
|
38
|
+
File.new(f, 'w+').puts YAML.dump(h)
|
39
|
+
puts "Configuration file was created!"
|
40
|
+
rescue Exception => e
|
41
|
+
raise "Configuration file couldn't be created! (#{e.class}: #{e.message})"
|
42
|
+
end
|
43
|
+
exit
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
QC::CERT_FILE = File.open(File.join(File.dirname(__FILE__), "qingcloud.com.cert.pem")).readlines.join
|
49
|
+
QC::Key = QC.load_config('qy_secret_access_key')
|
50
|
+
QC::AccessKeyId = QC.load_config('qy_access_key_id')
|
51
|
+
QC::Zone = QC.load_config('zone')
|
52
|
+
|
53
|
+
def QC.hmac key, data
|
54
|
+
hmac = OpenSSL::HMAC.digest(OpenSSL::Digest::Digest.new('sha256'), key, data)
|
55
|
+
b64_hmac = Base64.encode64(hmac).strip
|
56
|
+
url_b64_hmac = CGI.escape(b64_hmac)
|
57
|
+
end
|
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']
|
67
|
+
end
|
68
|
+
|
69
|
+
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
|
79
|
+
end
|
80
|
+
|
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))}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
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']
|
95
|
+
end
|
96
|
+
|
97
|
+
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
|
106
|
+
end
|
107
|
+
|
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))}
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
module API
|
115
|
+
class Request
|
116
|
+
attr_reader :response
|
117
|
+
|
118
|
+
def initialize action, extra_params = []
|
119
|
+
@response = :not_requested
|
120
|
+
|
121
|
+
@params = []
|
122
|
+
@params << ['action', action]
|
123
|
+
@params << ['access_key_id', QC::AccessKeyId]
|
124
|
+
@params << ['signature_method', 'HmacSHA256']
|
125
|
+
@params << ['signature_version', 1]
|
126
|
+
@params << ['zone', QC::Zone]
|
127
|
+
extra_params.each {|i| @params << i}
|
128
|
+
end
|
129
|
+
|
130
|
+
def execute!(key)
|
131
|
+
_p = @params.dup
|
132
|
+
_p << ['time_stamp', Time.now.utc.strftime("%FT%TZ")]
|
133
|
+
@uri = URI.parse(API.json2url(key, _p.to_json))
|
134
|
+
|
135
|
+
# Establish a SSL connection
|
136
|
+
Net::HTTP.start(@uri.host, 443,
|
137
|
+
:use_ssl => true,
|
138
|
+
:verify_mode => OpenSSL::SSL::VERIFY_PEER) do |https|
|
139
|
+
|
140
|
+
# Verify additional the host name in the certificate to avoid MITM
|
141
|
+
unless OpenSSL::SSL.verify_certificate_identity(https.peer_cert, 'qingcloud.com')
|
142
|
+
raise 'Hostname in certifcate does NOT match! (MITM?)'
|
143
|
+
end
|
144
|
+
|
145
|
+
# Verify the individual certificate
|
146
|
+
unless https.peer_cert.to_s == QC::CERT_FILE
|
147
|
+
raise "Certificate is NOT trustworthy!"
|
148
|
+
end
|
149
|
+
|
150
|
+
####################################################################
|
151
|
+
# Starting from this point I consider the SSL connection as safe!
|
152
|
+
|
153
|
+
@response = https.request(Net::HTTP::Get.new(@uri.request_uri))
|
154
|
+
|
155
|
+
# After this point we close the SSL connection.
|
156
|
+
####################################################################
|
157
|
+
end
|
158
|
+
|
159
|
+
JSON.parse(@response.body)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def API.sort_json json
|
164
|
+
JSON.parse(json).to_a.sort.to_s
|
165
|
+
end
|
166
|
+
|
167
|
+
def API.json2reqstr json
|
168
|
+
"GET\n/iaas/\n" + json2params(json)
|
169
|
+
end
|
170
|
+
|
171
|
+
def API.json2sign key, json
|
172
|
+
QC.hmac(key, json2reqstr(sort_json(json)))
|
173
|
+
end
|
174
|
+
|
175
|
+
def API.json2url key, json
|
176
|
+
sign = json2sign(key, json)
|
177
|
+
params = json2params(json)
|
178
|
+
"https://api.qingcloud.com/iaas/?#{params}&signature=#{sign}"
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
def API.json2params json
|
184
|
+
JSON.parse(json).to_a.map do |i|
|
185
|
+
"#{CGI.escape(i[0])}=#{CGI.escape(i[1].to_s)}"
|
186
|
+
end.join('&')
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
2
|
+
MIIFRzCCBC+gAwIBAgIHSyW9yrLTdzANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
|
3
|
+
BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
|
4
|
+
BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm
|
5
|
+
aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5
|
6
|
+
IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky
|
7
|
+
ODcwHhcNMTMwMzE5MDUxMTIxWhcNMTUwMzE5MDUxMTIxWjA9MSEwHwYDVQQLExhE
|
8
|
+
b21haW4gQ29udHJvbCBWYWxpZGF0ZWQxGDAWBgNVBAMMDyoucWluZ2Nsb3VkLmNv
|
9
|
+
bTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALwYkwKcaVEk//LDRyNo
|
10
|
+
OZUNJbSFRmtaa+gVbKu1nGHhhmmyKaToV6n3yAUY4sth+js03FARcV72hkFhB4Pw
|
11
|
+
ZEyXJyHkumtJu0mQWDzo+U2nqjQJFpEbWyPC/H+KW/8XJVmBZiufW6Sde7+ypiOg
|
12
|
+
Pwv8Ch47tgZo/7Z7apHX9UzZt8O8Ml58xSmEucZzKxy60SK+hjtuFHWL5T/WzBQn
|
13
|
+
hB+geK9OSCv5Woi/hLvQaWan9xWF1NQjz9k5OzbcB04SNhRlm5Y8y3ypHxgdHSzm
|
14
|
+
AI9vabPSTbjNG084Llbe3VGdwx3gdbMD4wHhTbhFPhVV2UzGR3zRUPwcatq2wxep
|
15
|
+
mXsCAwEAAaOCAbwwggG4MA8GA1UdEwEB/wQFMAMBAQAwHQYDVR0lBBYwFAYIKwYB
|
16
|
+
BQUHAwEGCCsGAQUFBwMCMA4GA1UdDwEB/wQEAwIFoDAzBgNVHR8ELDAqMCigJqAk
|
17
|
+
hiJodHRwOi8vY3JsLmdvZGFkZHkuY29tL2dkczEtODcuY3JsMFMGA1UdIARMMEow
|
18
|
+
SAYLYIZIAYb9bQEHFwEwOTA3BggrBgEFBQcCARYraHR0cDovL2NlcnRpZmljYXRl
|
19
|
+
cy5nb2RhZGR5LmNvbS9yZXBvc2l0b3J5LzCBgAYIKwYBBQUHAQEEdDByMCQGCCsG
|
20
|
+
AQUFBzABhhhodHRwOi8vb2NzcC5nb2RhZGR5LmNvbS8wSgYIKwYBBQUHMAKGPmh0
|
21
|
+
dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3NpdG9yeS9nZF9pbnRl
|
22
|
+
cm1lZGlhdGUuY3J0MB8GA1UdIwQYMBaAFP2sYTKTbEXW4u6FX5q653aZaMznMCkG
|
23
|
+
A1UdEQQiMCCCDyoucWluZ2Nsb3VkLmNvbYINcWluZ2Nsb3VkLmNvbTAdBgNVHQ4E
|
24
|
+
FgQUnyjKq4LLVT955jb3wyzLNgFETewwDQYJKoZIhvcNAQEFBQADggEBAB5FSJjq
|
25
|
+
Zue7+jt/1rYf6pbGhpZEhVRXNq662/d5KRlSVyd0Z0LK8OUdt8JR/cQt8XAyMYii
|
26
|
+
AUXAqklQcK0fphkcPznLIMUab9QWkaUSajOf/rUh23sxNZrgKYW8Z0H8MevCWISO
|
27
|
+
+O6g9S/fzjtG7xkrDh1gBxFHCfai3st3kphyirbTkoMZN/tXEiZzYsK3nh+c7F6E
|
28
|
+
HgjZmdVMeSodJpdj7bOULntqJIau1NrTzQxGGJDLtqf8lTMiHotZ8VfN9wDPBqfs
|
29
|
+
0jFV1vvczYwIQaEr+1iZXxgZC2itR4hbX3D3JN7WnPWJp+8LJpwkZeCXDL4t2GK8
|
30
|
+
G4/6MpCRBK936qU=
|
31
|
+
-----END CERTIFICATE-----
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: qc.rb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Daniel Bovensiepen
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-02-15 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: QingCloud API Library to handle instances, networks, internetconnections,
|
14
|
+
etc. on QingCloud.com
|
15
|
+
email: daniel@bovensiepen.net
|
16
|
+
executables:
|
17
|
+
- qc
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- bin/qc
|
22
|
+
- lib/qc.rb
|
23
|
+
- lib/qingcloud.com.cert.pem
|
24
|
+
- LICENSE
|
25
|
+
- README.md
|
26
|
+
homepage: https://github.com/bovi/qc.rb
|
27
|
+
licenses:
|
28
|
+
- MIT
|
29
|
+
metadata: {}
|
30
|
+
post_install_message:
|
31
|
+
rdoc_options: []
|
32
|
+
require_paths:
|
33
|
+
- lib
|
34
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
35
|
+
requirements:
|
36
|
+
- - '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
requirements: []
|
45
|
+
rubyforge_project:
|
46
|
+
rubygems_version: 2.0.3
|
47
|
+
signing_key:
|
48
|
+
specification_version: 4
|
49
|
+
summary: QingCloud API Library
|
50
|
+
test_files: []
|