mos-sdk 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (4) hide show
  1. checksums.yaml +7 -0
  2. data/lib/mos-sdk.rb +315 -0
  3. data/lib/mos-sdk/base.rb +169 -0
  4. metadata +74 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 428f05b30643c7b4a19bd82f0e53b3de34230793
4
+ data.tar.gz: c2dbd68bcecfba4e7e77817be61eedd8359d8a31
5
+ SHA512:
6
+ metadata.gz: 9e10d6e04e4a5f16c04e83078384a67b31b704b5497833782a41dbc6380fecf0ae6f569faf84f9fd55a470e38710e6b8ff9ad69af1119cd373c8453af2e98f2e
7
+ data.tar.gz: bc45d3c96e2868400f8c091da0b0140c947cbcadbd1f929b0e2acf3cf029a12e65a6795e46c0bda063a5032a544ad4031de7ca4694889e282a01a168556786d4
@@ -0,0 +1,315 @@
1
+ # -*- coding: utf-8 -*-
2
+ $:.unshift File.join(File.dirname(__FILE__), '.', 'mos-sdk')
3
+ require 'base.rb'
4
+
5
+ module Mos
6
+ class Client < Mos::Base
7
+ end
8
+ end
9
+
10
+ # 基类函数为Base,mos-sdk的实现类
11
+ class Mos::Client
12
+ # 构造函数
13
+ def initialize(access, secret, url, format='xml', timeout=300, debug=false)
14
+ super(access, secret, url, format, timeout, debug)
15
+ end
16
+
17
+ # 获取所有虚拟机类型
18
+ # - @param [Integer] limit 最大返回数量,用于分页控制
19
+ # - @param [Integer] offset 返回偏移量,用于分页控制
20
+ # - @param [Hash] filters 过滤条件,key/value分别指定过滤字段名称和值,支持的字段名称为:name, status
21
+ # - @return [Hash] 所有虚拟机信息
22
+ def describe_instance_types(limit=0, offset=0, filters=nil)
23
+ kwargs = {}
24
+ self.parse_array_params(limit, offset, filters, kwargs) # parse_list_params 父类函数
25
+ val = self.request('DescribeInstanceTypes', *kwargs)
26
+ val['InstanceTypeSet']
27
+ end
28
+
29
+ # 获得所有虚拟机模板
30
+ # - @return [Hash] 模板列表
31
+ def describe_templates()
32
+ val = self.request('DescribeTemplates')
33
+ val['TemplateSet']
34
+ end
35
+
36
+ # 获取帐户余额和最近更新时间
37
+ # - @return [Hash] 帐户余额和最近更新时间
38
+ def get_balance()
39
+ self.request('GetBalance')
40
+ end
41
+
42
+ # 获得所有虚拟机
43
+ # - @param [Array] ids 期望获取的虚拟机ID列表
44
+ # - @param [Array] names 期望获取信息的虚拟机名称列表
45
+ # - @param [Integer] limit 最多返回数量
46
+ # - @param [Integer] offset 返回虚拟机的偏移量,用于分页显示
47
+ # - @param [Hash] filters 过滤器,一个hash,包含过滤字段名和值,可能过滤字段为:name, status
48
+ # - @return [Hash] 虚拟机列表
49
+ def describe_instances(ids=nil, names=nil, limit=0, offset=0, filters=nil)
50
+ kwargs = {}
51
+ kwargs['InstanceId'] = ids if ids.kind_of?(Array) && ids.size() > 0
52
+ kwargs['InstanceName'] = names if names.kind_of?(Array) && names.size() > 0
53
+ self.parse_array_params(limit, offset, filters, kwargs)
54
+ val = self.request('DescribeInstances', *kwargs)
55
+ val['InstanceSet']
56
+ end
57
+
58
+ # 获取指定虚拟机的虚拟磁盘信息
59
+ # - @param [String] iid 虚拟机ID
60
+ # - @param [Integer] limit 最大返回数量,用于分页控制
61
+ # - @param [Integer] offset 返回的偏移量,用于分页控制
62
+ # - @param [Hash] filters 返回结果过滤条件,由hash的key/value指定过滤字段名和值
63
+ # - @return [Hash] 指定虚拟机磁盘列表
64
+ def describe_instance_volumes(iid, limit=0, offset=0, filters=nil)
65
+ kwargs = {}
66
+ kwargs['InstanceId'] = iid
67
+ self.parse_array_params(limit, offset, filters, kwargs)
68
+ val = self.request('DescribeInstanceVolumes', *kwargs)
69
+ val['InstanceVolumeSet']
70
+ end
71
+
72
+ # 获取指定虚拟机的网络接口(虚拟网卡)信息
73
+ # - @param [String] iid 虚拟机ID
74
+ # - @param [Integer] limit 最大返回数量,用于分页控制
75
+ # - @param [Integer] offset 返回的偏移量,用于分页控制
76
+ # - @param [Hash] filters 返回结果过滤条件,由hash的key/value指定过滤字段名和值
77
+ # - @return [Hash] 指定虚拟机的网络接口(虚拟网卡)信息
78
+ def describe_network_interfaces(iid, limit=0, offset=0, filters=nil)
79
+ kwargs = {}
80
+ kwargs['InstanceId'] = iid
81
+ self.parse_array_params(limit, offset, filters, kwargs)
82
+ val = self.request('DescribeInstanceNetworkInterfaces', *kwargs)
83
+ val['InstanceNetworkInterfaceSet']
84
+ end
85
+
86
+ # 虚拟机租期续费
87
+ # - @param [String] iid 虚拟机ID
88
+ # - @param [String] duration 续费租期,缺省为'1M',即一个月
89
+ def renew_instance(iid, duration=nil)
90
+ kwargs = {}
91
+ kwargs['InstanceId'] = iid
92
+ unless duration.nil?
93
+ (/^\d+[HhMm]$/.match(duration)) ? (kwargs['Duration'] = duration) : (raise Exception("Illegal duration %s" % duration))
94
+ end
95
+ self.request('RenewInstance', *kwargs)
96
+ end
97
+
98
+ # 获取虚拟机的租期信息
99
+ # - @param [String] iid 虚拟机ID
100
+ # - @return [Hash] 虚拟机租期信息,包含过期时间、自动删除时间
101
+ def get_instance_contract_info(iid)
102
+ kwargs = {}
103
+ kwargs['InstanceId'] = iid
104
+ self.request('GetInstanceContractInfo', *kwargs)
105
+ end
106
+
107
+ # 创建虚拟机,创建时要提供datadisk和bandwidth参数
108
+ # - @param [String] imageid 系统模板ID
109
+ # - @param [String] itype 虚拟机类型ID 例如 C4_M4 代表四核 4G内存
110
+ # - @param [String] duration 虚拟机租期, 缺省为'1M',即一个月
111
+ # - @param [String] name 虚拟机名称(可选)
112
+ # - @param [String] keypair 虚拟机使用的SSH密钥ID
113
+ # - @param [Integer] datadisk 指定创建虚拟机使用的额外数据盘,单位为1GB
114
+ # - @param [Integer] bandwidth 指定创建虚拟机使用的额外带宽,单位为Mbps
115
+ # - @return [Hash] 创建成功的虚拟机信息
116
+ def create_instance(imageid, itype, duration=nil, name=nil, keypair=nil, datadisk=nil, bandwidth=nil)
117
+ kwargs = {}
118
+ kwargs['ImageId'] = imageid
119
+ kwargs['InstanceType'] = itype
120
+ unless duration.nil?
121
+ /^\d+[HhMm]$/.match(duration) ? kwargs['Duration'] = duration : (raise Exception('Illegal duration format'))
122
+ end
123
+
124
+ kwargs['InstanceName'] = name unless name.nil?
125
+ kwargs['KeyName'] = keypair unless keypair.nil?
126
+ kwargs['ExtraExtDisksize'] = datadisk unless datadisk.nil?
127
+ kwargs['ExtraExtBandwidth'] = bandwidth unless bandwidth.nil?
128
+ val = self.request('CreateInstance', *kwargs)
129
+ val['Instance']
130
+ end
131
+
132
+ # 获取虚拟机的状态
133
+ # - @param [String] iid 虚拟机ID
134
+ # - @return [Hash] 虚拟机状态
135
+ def describe_instance_status(iid)
136
+ kwargs = {}
137
+ kwargs['InstanceId'] = iid
138
+ val = self.request('DescribeInstanceStatus', *kwargs)
139
+ val['InstanceStatus']
140
+ end
141
+
142
+ # 获取虚拟机的Login帐户信息
143
+ # - @param [String] iid 虚拟机ID
144
+ # - @param [String] key_file 私钥文件路径,如果虚拟机使用了SSH密钥,需要指定私钥解密password
145
+ # - @return [Hash] 虚拟机Login信息,包含帐户名称、密码,如果使用SSH密钥,则还包含密钥ID和名称
146
+ def get_password_data(iid, key_file=nil)
147
+ kwargs = {}
148
+ kwargs['InstanceId'] = iid
149
+ val = self.request('GetPasswordData', *kwargs)
150
+ if val.has_key?('passwordData') && val.has_key?('keypairName')
151
+ if key_file.nil?
152
+ raise Exception('Password is encrypted, please specify private key of keypair %s' % val['keypairName'])
153
+ else
154
+ begin
155
+ f = open(key_file)
156
+ rescue
157
+ puts 'fail to open file'
158
+ exit(-1)
159
+ end
160
+
161
+ key = f.read()
162
+ f.close()
163
+ val['passwordData']=Base64.decode64(
164
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), key, val['passwordData'])
165
+ ).strip
166
+ end
167
+ end
168
+ val
169
+ end
170
+
171
+ # 启动虚拟机
172
+ # - @param [String] iid 虚拟机ID
173
+ def start_instance(iid)
174
+ kwargs = {}
175
+ kwargs['InstanceId'] = iid
176
+ self.request('StartInstance', *kwargs)
177
+ end
178
+
179
+ # 停止虚拟机
180
+ # - @param [String] iid 虚拟机ID
181
+ # - @param [] force 是否强制停止虚拟机
182
+ def stop_instance(iid, force=false)
183
+ kwargs = {}
184
+ kwargs['InstanceId'] = iid
185
+ kwargs['Force'] = force if force
186
+ self.request('StopInstance', *kwargs)
187
+ end
188
+
189
+ # 重启虚拟机
190
+ # - @param [String] iid 虚拟机ID
191
+ def reboot_instance(iid)
192
+ kwargs = {}
193
+ kwargs['InstanceId'] = iid
194
+ self.request('RebootInstance', *kwargs)
195
+ end
196
+
197
+ # 删除虚拟机
198
+ # - @param [String] iid 虚拟机ID
199
+ def terminate_instance(iid)
200
+ kwargs = {}
201
+ kwargs['InstanceId'] = iid
202
+ self.request('TerminateInstance', *kwargs)
203
+ end
204
+
205
+ # 重置虚拟机系统磁盘
206
+ # - @param [String] iid 虚拟机ID
207
+ # - @param [String] image_id 将虚拟机系统磁盘用指定镜像模板重置,如果无该参数,则使用原镜像模板重置
208
+ def rebuild_instance_root_image(iid, image_id=nil)
209
+ kwargs = {}
210
+ kwargs['InstanceId'] = iid
211
+ kwargs['ImageId'] = image_id if !(image_id.nil?) && image_id.size > 0
212
+ self.request('RebuildInstanceRootImage', *kwargs)
213
+ end
214
+
215
+ # 更改虚拟机类型
216
+ # - @param [String] iid 虚拟机ID
217
+ # - @param [String] itype 指定更改的虚拟机类型
218
+ # - @param [String] duration 指定更改后的初始租期,缺省为'1M',即一个月
219
+ # - @param [Integer] datadisk 指定创建虚拟机使用的额外数据盘,单位为1GB
220
+ # - @param [Integer] bandwidth 指定创建虚拟机使用的额外带宽,单位为Mbps
221
+ # - 省略datadisk和bandwidth参数无法成功修改,具体用法可参考对应测试样例
222
+ def change_instance_type(iid, itype, duration=nil, datadisk=nil, bandwidth=nil)
223
+ kwargs = {}
224
+ kwargs['InstanceId'] = iid
225
+ kwargs['InstanceType'] = itype
226
+ unless duration.nil?
227
+ /^\d+[HhMm]$/.match(duration) ? kwargs['Duration'] = duration : (raise Exception('Illegal duration format'))
228
+ end
229
+
230
+ kwargs['ExtraExtDisksize'] = datadisk unless datadisk.nil?
231
+ kwargs['ExtraExtBandwidth'] = bandwidth unless bandwidth.nil?
232
+
233
+ self.request('ChangeInstanceType', *kwargs)
234
+ end
235
+
236
+ # 获取虚拟机的metadata
237
+ # - @param [String] iid 虚拟机ID
238
+ # - @return [Hash] 一个hash,包含虚拟机所有metadata的key/value
239
+ def get_instance_metadata(iid)
240
+ kwargs = {}
241
+ kwargs['InstanceId'] = iid
242
+ val = self.request('GetInstanceMetadata', *kwargs)
243
+ val['InstanceMetadata']
244
+ end
245
+
246
+ # 修改虚拟机的metadata
247
+ # - @param [String] iid 虚拟机ID
248
+ # - @param [Hash] data 需要增加或修改的metadata信息
249
+ def put_instance_metadata(iid, data)
250
+ kwargs = {}
251
+ kwargs['InstanceId'] = iid
252
+ names = []
253
+ values = []
254
+ data.each do |key, value|
255
+ names.push(key)
256
+ values.push(value)
257
+ end
258
+ kwargs['Name'] = names
259
+ kwargs['Value'] = values
260
+ self.request('PutInstanceMetadata', *kwargs)
261
+ end
262
+
263
+ # 获取用户的SSH密钥对
264
+ # - @param [Integer] limit 最大返回数量,用于分页控制
265
+ # - @param [Integer] offset 返回偏移量,用于分页控制
266
+ # - @param [Hash] filters 过滤条件,key/value分别指定过滤字段名称和值,支持的字段名称为:name
267
+ # - @return [Hash] 包含SSH密钥对列表
268
+ def describe_key_pairs(limit=0, offset=0, filters=nil)
269
+ kwargs = {}
270
+ self.parse_array_params(limit, offset, filters, kwargs)
271
+ val = self.request('DescribeKeyPairs', *kwargs)
272
+ val['KeyPairSet']
273
+ end
274
+
275
+ # 导入一个用户的SSH公钥,并创建一个SSH密钥对
276
+ # - @param [String] name 密钥对名称
277
+ # - @param [String] pubkey SSH公钥信息
278
+ # - @return [Hash] 创建的SSH密钥对信息
279
+ def import_key_pair(name, pubkey)
280
+ kwargs = {}
281
+ kwargs['KeyName'] = name
282
+ kwargs['PublicKeyMaterial'] = pubkey
283
+ val = self.request('ImportKeyPair', *kwargs)
284
+ val['KeyPair']
285
+ end
286
+
287
+ # 删除一个SSH密钥对
288
+ # - @param [String] kid 密钥对ID
289
+ def delete_key_pair(kid)
290
+ kwargs = {}
291
+ kwargs['KeyName'] = kid
292
+ self.request('DeleteKeyPair', *kwargs)
293
+ end
294
+
295
+ # 保存虚拟机的模板
296
+ # - @param [String] iid 虚拟机ID
297
+ # - @param [String] name 模板名称
298
+ # - @param [String] notes 保存模板的说明
299
+ # - @return [Hash] 请求是否成功
300
+ def create_template(iid, name, notes=nil)
301
+ kwargs = {}
302
+ kwargs['InstanceId'] = iid
303
+ kwargs['Name'] = name
304
+ kwargs['Notes'] = notes unless notes.nil?
305
+ self.request('CreateTemplate', *kwargs)
306
+ end
307
+
308
+ # 删除一个模板
309
+ # - @param [String] tid 模板ID
310
+ def delete_template(tid)
311
+ kwargs = {}
312
+ kwargs['TemplateId'] = tid
313
+ self.request('DeleteTemplate', *kwargs)
314
+ end
315
+ end
@@ -0,0 +1,169 @@
1
+ require "uri"
2
+ require "base64"
3
+ require "openssl"
4
+ require "net/http"
5
+ require "json"
6
+ require "logger"
7
+ require "rubygems"
8
+ require "crack"
9
+ require "erb"
10
+ include ERB::Util
11
+ module Mos
12
+ class Base
13
+ end
14
+ end
15
+
16
+ class Mos::Base
17
+ attr_accessor :access, :secret, :url, :format, :timeout, :debug
18
+
19
+ # 基类初始化函数
20
+ # - @param [String] access
21
+ # - @param [String] secret
22
+ # - @param [String] url
23
+ # - @param [String] format 默认为xml格式
24
+ # - @param [Integer] timeout
25
+ # - @param [] debug
26
+ def initialize(access, secret, url, format='xml', timeout=300, debug=false)
27
+ @access=access
28
+ @secret=secret
29
+ @url=url
30
+ @format=format
31
+ @timeout=timeout
32
+ @debug=debug
33
+ end
34
+
35
+ def raw_request(action, *kwargs)
36
+ self._request(action, *kwargs)
37
+ end
38
+
39
+ # 处理请求函数
40
+ # - @param [String] action 函数名
41
+ # - @param [Hash] kwargs 函数调用参数
42
+ # - @return [HTTPResponse] 返回请求处理结果
43
+ def _request(action, *kwargs)
44
+ params = {}
45
+ params['Action'] = action
46
+ params['AWSAccessKeyId'] = self.access
47
+ params['Timestamp'] = Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")
48
+ params['SignatureVersion'] = '2'
49
+ params['SignatureMethod'] = 'HmacSHA256'
50
+
51
+ unless kwargs.empty?
52
+ kwargs.each do |k, v|
53
+ if v.kind_of?(Array)
54
+ i = 1
55
+ v.each do |vi|
56
+ params['%s.%d' % [k, i]] = vi
57
+ i += 1
58
+ end
59
+ else
60
+ params[k] = v
61
+ end
62
+ end
63
+ end
64
+
65
+ params['Format'] = self.format if self.format
66
+ sig = self.get_signature(params)
67
+ params['Signature'] = sig
68
+ headers = {}
69
+ headers['User-Agent'] = 'ruby-mosclient'
70
+ data = URI.encode_www_form(params)
71
+ puts self.url + '?' + data if self.debug
72
+
73
+ uri = URI.parse(self.url)
74
+ http = Net::HTTP.new(uri.host, uri.port)
75
+ http.use_ssl=true
76
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
77
+ http.request_post('/', data, headers)
78
+ end
79
+
80
+ # 签名函数
81
+ # - @param [Hash] params 签名参数
82
+ # - @return [String] 签名处理结果
83
+ def get_signature(params) #signature method
84
+ req = URI.parse(self.url)
85
+ host = req.host
86
+ endpoint = host + ':' + req.port.to_s
87
+ path = req.path
88
+ path = '/' if req.path == ''
89
+ cred_dict = {'access' => self.access,
90
+ 'host' => endpoint,
91
+ 'verb' => 'POST',
92
+ 'path' => path,
93
+ 'params' => params,
94
+ }
95
+ params=Hash[params.sort]
96
+ sha256_hmac(string_to_sign(cred_dict, params))
97
+ end
98
+
99
+ # 字符串格式化函数
100
+ # - @param [Hash] cred_dict 认证信息
101
+ # - @param [Hash] params 认证参数
102
+ # - @return [String] 格式化结果
103
+ def string_to_sign(cred_dict, params)
104
+ [
105
+ cred_dict['verb'],
106
+ cred_dict['host'],
107
+ cred_dict['path'],
108
+ URI.encode_www_form(params),
109
+ ].join("\n")
110
+ end
111
+
112
+ # sha256算法实现
113
+ # - @param [String] value 加密内容
114
+ # - @return [String] 加密结果
115
+ def sha256_hmac(value)
116
+ Base64.encode64(
117
+ OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), self.secret, value)
118
+ ).strip
119
+ end
120
+
121
+ # 请求/响应函数,核心处理由_request函数实现
122
+ # - @param [String] action 函数名
123
+ # - @param [Hash] kwargs 函数调用参数
124
+ # - @return [Hash] 返回函数调用结果
125
+ def request(action, *kwargs)
126
+ resp = self._request(action, *kwargs)
127
+ body = resp.body
128
+ if self.debug
129
+ puts body
130
+ end
131
+
132
+ # todo begin 中if...else 执行else
133
+ begin
134
+ if resp.header['Content-Type'].start_with?('application/json')
135
+ body = JSON.parse(body)
136
+ else
137
+ body = Crack::XML.parse(body)
138
+ body["#{action}Response"]
139
+ end
140
+ rescue
141
+ return body
142
+ end
143
+ end
144
+
145
+ # 结果格式化函数
146
+ # - @param [Integer] limit 最大返回数量,用于分页控制
147
+ # - @param [Integer] offset 返回偏移量,用于分页控制
148
+ # - @param [Hash] filters 过滤条件,key/value分别指定过滤字段名称和值
149
+ # - @param [Hash] kwargs 其他参数
150
+ def parse_array_params(limit, offset, filters, kwargs)
151
+ kwargs['Limit'] = limit if limit > 0
152
+ kwargs['Offset'] = offset if offset > 0
153
+ unless filters.nil?
154
+ fidx = 1
155
+ filters.each do |k, vs|
156
+ kwargs['Filter.%d.Name' % fidx] = k
157
+ vs = [vs] unless vs.kind_of?(Array)
158
+ vidx = 1
159
+ vs.each do |v|
160
+ kwargs['Filter.%d.Value.%d' % [fidx, vidx]] = v
161
+ vidx += 1
162
+ end
163
+ fidx += 1
164
+ end
165
+ end
166
+ end
167
+
168
+ end
169
+
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mos-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.2
5
+ platform: ruby
6
+ authors:
7
+ - yangcs2009
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Ruby SDK for MOS.
42
+ email:
43
+ - yangchangsheng@meituan.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - lib/mos-sdk.rb
49
+ - lib/mos-sdk/base.rb
50
+ homepage: ''
51
+ licenses:
52
+ - MIT
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements: []
69
+ rubyforge_project:
70
+ rubygems_version: 2.4.5
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: Ruby SDK for MOS.
74
+ test_files: []