aliyun-odps 0.1.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +31 -0
- data/Gemfile +3 -0
- data/README.md +55 -12
- data/Rakefile +15 -5
- data/aliyun-odps.gemspec +22 -11
- data/bin/console +10 -3
- data/lib/aliyun/odps.rb +69 -2
- data/lib/aliyun/odps/authorization.rb +90 -0
- data/lib/aliyun/odps/client.rb +40 -0
- data/lib/aliyun/odps/configuration.rb +16 -0
- data/lib/aliyun/odps/error.rb +97 -0
- data/lib/aliyun/odps/http.rb +138 -0
- data/lib/aliyun/odps/list.rb +40 -0
- data/lib/aliyun/odps/model/function.rb +16 -0
- data/lib/aliyun/odps/model/functions.rb +113 -0
- data/lib/aliyun/odps/model/instance.rb +130 -0
- data/lib/aliyun/odps/model/instance_task.rb +30 -0
- data/lib/aliyun/odps/model/instances.rb +119 -0
- data/lib/aliyun/odps/model/projects.rb +73 -0
- data/lib/aliyun/odps/model/resource.rb +26 -0
- data/lib/aliyun/odps/model/resources.rb +144 -0
- data/lib/aliyun/odps/model/table.rb +37 -0
- data/lib/aliyun/odps/model/table_column.rb +13 -0
- data/lib/aliyun/odps/model/table_partition.rb +9 -0
- data/lib/aliyun/odps/model/table_partitions.rb +90 -0
- data/lib/aliyun/odps/model/table_schema.rb +13 -0
- data/lib/aliyun/odps/model/tables.rb +125 -0
- data/lib/aliyun/odps/model/task_result.rb +9 -0
- data/lib/aliyun/odps/modelable.rb +16 -0
- data/lib/aliyun/odps/project.rb +47 -0
- data/lib/aliyun/odps/service_object.rb +27 -0
- data/lib/aliyun/odps/struct.rb +126 -0
- data/lib/aliyun/odps/tunnel/download_session.rb +98 -0
- data/lib/aliyun/odps/tunnel/router.rb +15 -0
- data/lib/aliyun/odps/tunnel/snappy_reader.rb +19 -0
- data/lib/aliyun/odps/tunnel/snappy_writer.rb +45 -0
- data/lib/aliyun/odps/tunnel/table_tunnels.rb +81 -0
- data/lib/aliyun/odps/tunnel/upload_block.rb +9 -0
- data/lib/aliyun/odps/tunnel/upload_session.rb +132 -0
- data/lib/aliyun/odps/utils.rb +102 -0
- data/lib/aliyun/odps/version.rb +1 -1
- data/requirements.png +0 -0
- data/wiki/error.md +188 -0
- data/wiki/functions.md +39 -0
- data/wiki/get_start.md +34 -0
- data/wiki/installation.md +15 -0
- data/wiki/instances.md +32 -0
- data/wiki/projects.md +51 -0
- data/wiki/resources.md +62 -0
- data/wiki/ssl.md +7 -0
- data/wiki/tables.md +75 -0
- data/wiki/tunnels.md +80 -0
- metadata +195 -13
- data/requirements.mindnode/QuickLook/Preview.jpg +0 -0
- data/requirements.mindnode/contents.xml +0 -10711
- data/requirements.mindnode/viewState.plist +0 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'addressable/uri'
|
2
|
+
|
3
|
+
module Aliyun
|
4
|
+
module Odps
|
5
|
+
class Configuration
|
6
|
+
attr_accessor :access_key, :secret_key, :endpoint, :tunnel_endpoint, :project, :options, :ssl_ca_file
|
7
|
+
def initialize
|
8
|
+
@options = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def protocol
|
12
|
+
Addressable::URI.parse(@endpoint).scheme
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
# [Aliyun::Odps::RequestError] when Odps give a Non 2xx response
|
6
|
+
class RequestError < Error
|
7
|
+
# Error Code defined by Odps
|
8
|
+
attr_reader :code
|
9
|
+
|
10
|
+
# Error Message defined by Odps
|
11
|
+
attr_reader :message
|
12
|
+
|
13
|
+
# It's the UUID to uniquely identifies this request;
|
14
|
+
# When you can't solve the problem, you can request help from the ODPS development engineer with the RequestId.
|
15
|
+
attr_reader :request_id
|
16
|
+
|
17
|
+
# The Origin Httparty Response
|
18
|
+
attr_reader :origin_response
|
19
|
+
|
20
|
+
def initialize(response)
|
21
|
+
assign_error_code(response)
|
22
|
+
assign_request_id(response)
|
23
|
+
@origin_response = response
|
24
|
+
super("#{@request_id} - #{@code}: #{@message}")
|
25
|
+
end
|
26
|
+
|
27
|
+
def assign_error_code(response)
|
28
|
+
result = response.parsed_response
|
29
|
+
if result.key?('Error')
|
30
|
+
@code = result['Error']['Code']
|
31
|
+
@message = result['Error']['Message']
|
32
|
+
elsif result.key?('Code')
|
33
|
+
@code = result['Code']
|
34
|
+
@message = result['Message']
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def assign_request_id(response)
|
39
|
+
@request_id = response.headers['x-odps-request-id']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class XmlElementMissingError < Error
|
44
|
+
def initialize(element)
|
45
|
+
super("Missing #{element} Element in xml")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class MissingProjectConfigurationError < Error
|
50
|
+
def initialize
|
51
|
+
super("Must config project first. Use Aliyun::Odps.configure {|config| config.project = 'your-project' }")
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class PriorityInvalidError < Error
|
56
|
+
def initialize
|
57
|
+
super('Priority must more than or equal to zero.')
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
class InstanceTaskNotSuccessError < Error
|
62
|
+
def initialize(name, status, task_result)
|
63
|
+
super("Task #{name} #{status}: #{task_result}")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
class InstanceNameInvalidError < Error
|
68
|
+
def initialize(name)
|
69
|
+
super("#{name} should match pattern: #{Instance::NAME_PATTERN}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
class TunnelEndpointMissingError < Error
|
74
|
+
def initialize
|
75
|
+
super("Tunnel Endpoint auto detect fail, Use Aliyun::Odps.configure {|config| config.tunnel_endpoint = 'your-project' } to config")
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class ValueNotSupportedError < Error
|
80
|
+
def initialize(attr, supported_value)
|
81
|
+
super("#{attr} only support: #{Utils.wrap(supported_value).join(', ')} !!")
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class ResourceMissingContentError < Error
|
86
|
+
def initialize
|
87
|
+
super('A Resource must exist file or table')
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class RecordNotMatchSchemaError < Error
|
92
|
+
def initialize(values, schema)
|
93
|
+
super("#{values} not match with #{schema}")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
require 'addressable/uri'
|
3
|
+
require 'aliyun/odps/error'
|
4
|
+
|
5
|
+
module Aliyun
|
6
|
+
module Odps
|
7
|
+
class Http # nodoc
|
8
|
+
include HTTParty
|
9
|
+
|
10
|
+
class BetterXmlParser < HTTParty::Parser
|
11
|
+
protected
|
12
|
+
|
13
|
+
def xml
|
14
|
+
MultiXml.parse(body)
|
15
|
+
rescue
|
16
|
+
body
|
17
|
+
end
|
18
|
+
end
|
19
|
+
parser BetterXmlParser
|
20
|
+
|
21
|
+
attr_reader :config
|
22
|
+
|
23
|
+
def initialize(config)
|
24
|
+
@config = config
|
25
|
+
end
|
26
|
+
|
27
|
+
def get(uri, options = {})
|
28
|
+
request('GET', uri, options)
|
29
|
+
end
|
30
|
+
|
31
|
+
def put(uri, options = {})
|
32
|
+
headers = default_content_type.merge(options[:headers] || {})
|
33
|
+
request('PUT', uri, options.merge(headers: headers))
|
34
|
+
end
|
35
|
+
|
36
|
+
def post(uri, options = {})
|
37
|
+
headers = default_content_type.merge(options[:headers] || {})
|
38
|
+
request('POST', uri, options.merge(headers: headers))
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete(uri, options = {})
|
42
|
+
headers = default_content_type.merge(options[:headers] || {})
|
43
|
+
request('DELETE', uri, options.merge(headers: headers))
|
44
|
+
end
|
45
|
+
|
46
|
+
def options(uri, options = {})
|
47
|
+
request('OPTIONS', uri, options)
|
48
|
+
end
|
49
|
+
|
50
|
+
def head(uri, options = {})
|
51
|
+
request('HEAD', uri, options)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def request(verb, resource, options = {})
|
57
|
+
query = options.fetch(:query, {})
|
58
|
+
headers = options.fetch(:headers, {})
|
59
|
+
body = options.delete(:body)
|
60
|
+
|
61
|
+
append_headers!(headers, verb, body, options.merge(path: resource))
|
62
|
+
path = config.endpoint + resource
|
63
|
+
options = { headers: headers, query: query, body: body }
|
64
|
+
append_options!(options, path)
|
65
|
+
|
66
|
+
wrap(self.class.__send__(verb.downcase, path, options))
|
67
|
+
end
|
68
|
+
|
69
|
+
def wrap(response)
|
70
|
+
case response.code
|
71
|
+
when 200..299
|
72
|
+
response
|
73
|
+
else
|
74
|
+
fail RequestError, response
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def append_headers!(headers, verb, body, options)
|
79
|
+
append_default_headers!(headers)
|
80
|
+
append_body_headers!(headers, body)
|
81
|
+
append_authorization_headers!(headers, verb, options)
|
82
|
+
end
|
83
|
+
|
84
|
+
def append_options!(options, url)
|
85
|
+
options.merge!(uri_adapter: Addressable::URI)
|
86
|
+
if config.ssl_ca_file
|
87
|
+
options.merge!(ssl_ca_file: config.ssl_ca_file)
|
88
|
+
elsif url.start_with?('https://')
|
89
|
+
options.merge!(verify_peer: true)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def append_default_headers!(headers)
|
94
|
+
headers.merge!(default_headers)
|
95
|
+
end
|
96
|
+
|
97
|
+
def append_body_headers!(headers, body)
|
98
|
+
return headers unless body
|
99
|
+
|
100
|
+
unless headers.key?('Content-MD5')
|
101
|
+
headers.merge!('Content-MD5' => Utils.md5_hexdigest(body))
|
102
|
+
end
|
103
|
+
|
104
|
+
return if headers.key?('Content-Length')
|
105
|
+
headers.merge!('Content-Length' => Utils.content_size(body).to_s)
|
106
|
+
end
|
107
|
+
|
108
|
+
def append_authorization_headers!(headers, verb, options)
|
109
|
+
auth_key = get_auth_key(
|
110
|
+
options.merge(verb: verb, headers: headers, date: headers['Date'])
|
111
|
+
)
|
112
|
+
headers.merge!('Authorization' => auth_key)
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_auth_key(options)
|
116
|
+
Authorization.get_authorization(config.access_key, config.secret_key, options)
|
117
|
+
end
|
118
|
+
|
119
|
+
def default_headers
|
120
|
+
{
|
121
|
+
'User-Agent' => user_agent,
|
122
|
+
'Date' => Time.now.utc.strftime('%a, %d %b %Y %H:%M:%S GMT')
|
123
|
+
}
|
124
|
+
end
|
125
|
+
|
126
|
+
def default_content_type
|
127
|
+
{
|
128
|
+
'Content-Type' => 'application/xml'
|
129
|
+
}
|
130
|
+
end
|
131
|
+
|
132
|
+
def user_agent
|
133
|
+
"aliyun-odps-sdk-ruby/#{Aliyun::Odps::VERSION} " \
|
134
|
+
"(#{RbConfig::CONFIG['host_os']} ruby-#{RbConfig::CONFIG['ruby_version']})"
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
|
3
|
+
module Aliyun
|
4
|
+
module Odps
|
5
|
+
# Wrap for simple array and give marker and max_items methods
|
6
|
+
class List
|
7
|
+
include Enumerable
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
attr_reader :marker, :max_items
|
11
|
+
def_delegators :@objects, :[], :each, :size, :inspect
|
12
|
+
|
13
|
+
def initialize(marker, max_items, objects)
|
14
|
+
@marker = marker
|
15
|
+
@max_items = max_items.to_i
|
16
|
+
@objects = objects
|
17
|
+
end
|
18
|
+
|
19
|
+
# Auto detect marker, max_items, values from result,
|
20
|
+
# build a object, where you can access marker, max_items, and values
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
#
|
24
|
+
# Aliyun::Odps::List.build(result, %w(Projects Project)) do |hash|
|
25
|
+
# Project.new(hash.merge(client: client))
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @return [List]
|
29
|
+
def self.build(result, keys, &_block)
|
30
|
+
top_key = keys.first
|
31
|
+
marker = Utils.dig_value(result, top_key, 'Marker')
|
32
|
+
max_items = Utils.dig_value(result, top_key, 'MaxItems')
|
33
|
+
objects = Utils.wrap(Utils.dig_value(result, *keys)).map do |hash|
|
34
|
+
yield hash
|
35
|
+
end
|
36
|
+
new(marker, max_items, objects)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
class Function < Struct::Base
|
4
|
+
extend Aliyun::Odps::Modelable
|
5
|
+
|
6
|
+
property :name, String, required: true
|
7
|
+
property :owner, String
|
8
|
+
property :class_type, String
|
9
|
+
property :creation_time, DateTime
|
10
|
+
property :resources, Array
|
11
|
+
property :location, String
|
12
|
+
|
13
|
+
alias_method :alias=, :name=
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
# Methods for Functions
|
4
|
+
class Functions < ServiceObject
|
5
|
+
# List Functions of project
|
6
|
+
#
|
7
|
+
# @see http://repo.aliyun.com/api-doc/Function/get_functions/index.html Get functions
|
8
|
+
#
|
9
|
+
# @param options [Hash] options
|
10
|
+
# @option options [String] :name specify function name
|
11
|
+
# @option options [String] :owner specify function owner
|
12
|
+
# @option options [String] :marker
|
13
|
+
# @option options [String] :maxitems (1000)
|
14
|
+
#
|
15
|
+
# @return [List]
|
16
|
+
def list(options = {})
|
17
|
+
Utils.stringify_keys!(options)
|
18
|
+
path = "/projects/#{project.name}/registration/functions"
|
19
|
+
query = Utils.hash_slice(options, 'name', 'owner', 'marker', 'maxitems')
|
20
|
+
result = client.get(path, query: query).parsed_response
|
21
|
+
|
22
|
+
Aliyun::Odps::List.build(result, %w(Functions Function)) do |hash|
|
23
|
+
Function.new(hash)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Get Function
|
28
|
+
#
|
29
|
+
# @param name specify function name
|
30
|
+
#
|
31
|
+
# @return [Function]
|
32
|
+
def get(name)
|
33
|
+
path = "/projects/#{project.name}/registration/functions/#{name}"
|
34
|
+
|
35
|
+
result = client.get(path).parsed_response
|
36
|
+
Function.new(Utils.dig_value(result, 'Function'))
|
37
|
+
end
|
38
|
+
alias_method :function, :get
|
39
|
+
|
40
|
+
# Register function in project
|
41
|
+
#
|
42
|
+
# @see http://repo.aliyun.com/api-doc/Function/post_function/index.html Post function
|
43
|
+
#
|
44
|
+
# @param name [String] specify function name
|
45
|
+
# @param class_path [String] specify class Path used by function
|
46
|
+
# @param resources [Array<Model::Resource>] specify resources used by function
|
47
|
+
#
|
48
|
+
# @return [Function]
|
49
|
+
def create(name, class_path, resources = [])
|
50
|
+
path = "/projects/#{project.name}/registration/functions"
|
51
|
+
|
52
|
+
function = Function.new(
|
53
|
+
name: name,
|
54
|
+
class_type: class_path,
|
55
|
+
resources: resources
|
56
|
+
)
|
57
|
+
|
58
|
+
resp = client.post(path, body: build_create_body(function))
|
59
|
+
|
60
|
+
function.tap do |obj|
|
61
|
+
obj.location = resp.headers['Location']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Update function in project
|
66
|
+
#
|
67
|
+
# @see http://repo.aliyun.com/api-doc/Function/put_function/index.html Put function
|
68
|
+
#
|
69
|
+
# @param name [String] specify function name
|
70
|
+
# @param class_path [String] specify class Path used by function
|
71
|
+
# @param resources [Array<Model::Resource>] specify resources used by function
|
72
|
+
#
|
73
|
+
# @return [true]
|
74
|
+
def update(name, class_path, resources = [])
|
75
|
+
path = "/projects/#{project.name}/registration/functions/#{name}"
|
76
|
+
|
77
|
+
function = Function.new(
|
78
|
+
name: name,
|
79
|
+
class_type: class_path,
|
80
|
+
resources: resources
|
81
|
+
)
|
82
|
+
!!client.put(path, body: build_create_body(function))
|
83
|
+
end
|
84
|
+
|
85
|
+
# Delete function in project
|
86
|
+
#
|
87
|
+
# @see http://repo.aliyun.com/api-doc/Function/delete_function/index.html Delete function
|
88
|
+
#
|
89
|
+
# @param name [String] specify function name
|
90
|
+
#
|
91
|
+
# @return [true]
|
92
|
+
def delete(name)
|
93
|
+
path = "/projects/#{project.name}/registration/functions/#{name}"
|
94
|
+
!!client.delete(path)
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def build_create_body(function)
|
100
|
+
fail XmlElementMissingError, 'ClassType' if function.class_type.nil?
|
101
|
+
fail XmlElementMissingError, 'Resources' if function.resources.empty?
|
102
|
+
|
103
|
+
Utils.to_xml(
|
104
|
+
'Function' => {
|
105
|
+
'Alias' => function.name,
|
106
|
+
'ClassType' => function.class_type,
|
107
|
+
'Resources' => function.resources.map(&:to_hash)
|
108
|
+
}
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
module Aliyun
|
2
|
+
module Odps
|
3
|
+
class Instance < Struct::Base
|
4
|
+
extend Aliyun::Odps::Modelable
|
5
|
+
|
6
|
+
NAME_PATTERN = /^([a-z]|[A-Z]){1,}([a-z]|[A-Z]|[\d]|_)*/
|
7
|
+
|
8
|
+
property :project, Project, required: true
|
9
|
+
|
10
|
+
property :name, String, required: true
|
11
|
+
property :owner, String
|
12
|
+
property :comment, String
|
13
|
+
property :priority, Integer
|
14
|
+
property :tasks, Array
|
15
|
+
property :status, String
|
16
|
+
property :start_time, DateTime
|
17
|
+
property :end_time, DateTime
|
18
|
+
property :location, String
|
19
|
+
|
20
|
+
# Get task detail of instance
|
21
|
+
#
|
22
|
+
# @see http://repo.aliyun.com/api-doc/Instance/get_instance_detail/index.html Get instance detail
|
23
|
+
#
|
24
|
+
# @params task_name [String] specify task name
|
25
|
+
#
|
26
|
+
# @return [Hash]
|
27
|
+
def task_detail(task_name)
|
28
|
+
path = "/projects/#{project.name}/instances/#{name}"
|
29
|
+
query = { instancedetail: true, taskname: task_name }
|
30
|
+
client.get(path, query: query).parsed_response
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get task progress of instance
|
34
|
+
#
|
35
|
+
# @see http://repo.aliyun.com/api-doc/Instance/get_instance_progress/index.html Get instance progress
|
36
|
+
#
|
37
|
+
# @params task_name [String] specify task name
|
38
|
+
#
|
39
|
+
# @return [Hash]
|
40
|
+
def task_progress(task_name)
|
41
|
+
path = "/projects/#{project.name}/instances/#{name}"
|
42
|
+
query = { instanceprogress: true, taskname: task_name }
|
43
|
+
client.get(path, query: query).parsed_response['Progress']
|
44
|
+
end
|
45
|
+
|
46
|
+
# Get task summary of instance
|
47
|
+
#
|
48
|
+
# @see http://repo.aliyun.com/api-doc/Instance/get_instance_summary/index.html Get instance summary
|
49
|
+
#
|
50
|
+
# @params task_name [String] specify task name
|
51
|
+
#
|
52
|
+
# @return [Hash]
|
53
|
+
def task_summary(task_name)
|
54
|
+
path = "/projects/#{project.name}/instances/#{name}"
|
55
|
+
query = { instancesummary: true, taskname: task_name }
|
56
|
+
client.get(path, query: query).parsed_response
|
57
|
+
end
|
58
|
+
|
59
|
+
# Get task results
|
60
|
+
#
|
61
|
+
# @return [Hash<name, TaskResult>]
|
62
|
+
def task_results
|
63
|
+
path = "/projects/#{project.name}/instances/#{name}"
|
64
|
+
query = { result: true }
|
65
|
+
result = client.get(path, query: query).parsed_response
|
66
|
+
task_results = Utils.dig_value(result, 'Instance', 'Tasks', 'Task')
|
67
|
+
Hash[Utils.wrap(task_results).map { |v| [v['Name'], Aliyun::Odps::TaskResult.new(v)] }]
|
68
|
+
end
|
69
|
+
|
70
|
+
# Get tasks of instance
|
71
|
+
#
|
72
|
+
# @see http://repo.aliyun.com/api-doc/Instance/get_instance_task/index.html Get instance task
|
73
|
+
#
|
74
|
+
# @return [List]
|
75
|
+
def list_tasks
|
76
|
+
path = "/projects/#{project.name}/instances/#{name}"
|
77
|
+
query = { taskstatus: true }
|
78
|
+
result = client.get(path, query: query).parsed_response
|
79
|
+
|
80
|
+
keys = %w(Instance Tasks Task)
|
81
|
+
Utils.wrap(Utils.dig_value(result, *keys)).map do |hash|
|
82
|
+
InstanceTask.new(hash)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Terminate the instance
|
87
|
+
#
|
88
|
+
# @see http://repo.aliyun.com/api-doc/Instance/put_instance_terminate/index.html Put instance terminated
|
89
|
+
#
|
90
|
+
# @return true
|
91
|
+
def terminate
|
92
|
+
path = "/projects/#{project.name}/instances/#{name}"
|
93
|
+
|
94
|
+
body = Utils.to_xml(
|
95
|
+
'Instance' => { 'Status' => 'Terminated' }
|
96
|
+
)
|
97
|
+
!!client.put(path, body: body)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Get status
|
101
|
+
#
|
102
|
+
# @see http://repo.aliyun.com/api-doc/Instance/get_instance/index.html Get instance
|
103
|
+
#
|
104
|
+
# @return [String] Instance status: Suspended, Running, Terminated
|
105
|
+
def get_status
|
106
|
+
path = "/projects/#{project.name}/instances/#{name}"
|
107
|
+
result = client.get(path).parsed_response
|
108
|
+
Utils.dig_value(result, 'Instance', 'Status')
|
109
|
+
end
|
110
|
+
|
111
|
+
# Block process until instance success
|
112
|
+
#
|
113
|
+
# @raise [InstanceTaskNotSuccessError] if task not success
|
114
|
+
def wait_for_success(interval = 0.01)
|
115
|
+
wait_for_terminated(interval)
|
116
|
+
|
117
|
+
list_tasks.each do |task|
|
118
|
+
if task.status.upcase != 'SUCCESS'
|
119
|
+
fail InstanceTaskNotSuccessError.new(task.name, task.status, task_results[task.name].result)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# Block process until instance terminated
|
125
|
+
def wait_for_terminated(interval = 0.01)
|
126
|
+
sleep interval while get_status != 'Terminated'
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|