qc.rb 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (7) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +4 -0
  4. data/bin/qc +49 -0
  5. data/lib/qc.rb +189 -0
  6. data/lib/qingcloud.com.cert.pem +31 -0
  7. 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
@@ -0,0 +1,4 @@
1
+ qc.rb
2
+ =====
3
+
4
+ QingCloud API Library to handle instances, networks, etc. on QingCloud.com
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: []