aws-sdk-core 3.168.4 → 3.224.1
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 +4 -4
- data/CHANGELOG.md +719 -0
- data/VERSION +1 -1
- data/lib/aws-defaults/default_configuration.rb +5 -6
- data/lib/aws-defaults.rb +4 -1
- data/lib/aws-sdk-core/arn.rb +1 -3
- data/lib/aws-sdk-core/assume_role_credentials.rb +13 -5
- data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +14 -7
- data/lib/aws-sdk-core/binary/decode_handler.rb +3 -9
- data/lib/aws-sdk-core/binary/encode_handler.rb +1 -1
- data/lib/aws-sdk-core/binary/event_builder.rb +34 -37
- data/lib/aws-sdk-core/binary/event_stream_decoder.rb +1 -0
- data/lib/aws-sdk-core/binary/event_stream_encoder.rb +4 -3
- data/lib/aws-sdk-core/cbor/decoder.rb +308 -0
- data/lib/aws-sdk-core/cbor/encoder.rb +243 -0
- data/lib/aws-sdk-core/cbor.rb +53 -0
- data/lib/aws-sdk-core/client_side_monitoring.rb +9 -0
- data/lib/aws-sdk-core/client_stubs.rb +33 -55
- data/lib/aws-sdk-core/credential_provider.rb +8 -1
- data/lib/aws-sdk-core/credential_provider_chain.rb +39 -11
- data/lib/aws-sdk-core/credentials.rb +19 -6
- data/lib/aws-sdk-core/ec2_metadata.rb +1 -1
- data/lib/aws-sdk-core/ecs_credentials.rb +179 -53
- data/lib/aws-sdk-core/endpoints/condition.rb +5 -0
- data/lib/aws-sdk-core/endpoints/endpoint.rb +3 -1
- data/lib/aws-sdk-core/endpoints/endpoint_rule.rb +5 -1
- data/lib/aws-sdk-core/endpoints/error_rule.rb +5 -0
- data/lib/aws-sdk-core/endpoints/function.rb +5 -0
- data/lib/aws-sdk-core/endpoints/matchers.rb +19 -18
- data/lib/aws-sdk-core/endpoints/reference.rb +5 -0
- data/lib/aws-sdk-core/endpoints/rule.rb +5 -0
- data/lib/aws-sdk-core/endpoints/rule_set.rb +5 -0
- data/lib/aws-sdk-core/endpoints/rules_provider.rb +5 -0
- data/lib/aws-sdk-core/endpoints/templater.rb +6 -0
- data/lib/aws-sdk-core/endpoints/tree_rule.rb +5 -0
- data/lib/aws-sdk-core/endpoints/url.rb +1 -0
- data/lib/aws-sdk-core/endpoints.rb +79 -19
- data/lib/aws-sdk-core/error_handler.rb +41 -0
- data/lib/aws-sdk-core/errors.rb +14 -5
- data/lib/aws-sdk-core/event_emitter.rb +0 -16
- data/lib/aws-sdk-core/ini_parser.rb +7 -0
- data/lib/aws-sdk-core/instance_profile_credentials.rb +56 -32
- data/lib/aws-sdk-core/json/builder.rb +8 -1
- data/lib/aws-sdk-core/json/error_handler.rb +30 -14
- data/lib/aws-sdk-core/json/handler.rb +13 -6
- data/lib/aws-sdk-core/json/json_engine.rb +3 -1
- data/lib/aws-sdk-core/json/oj_engine.rb +7 -1
- data/lib/aws-sdk-core/json/parser.rb +33 -3
- data/lib/aws-sdk-core/json.rb +43 -14
- data/lib/aws-sdk-core/log/formatter.rb +6 -0
- data/lib/aws-sdk-core/log/param_filter.rb +2 -2
- data/lib/aws-sdk-core/log/param_formatter.rb +7 -3
- data/lib/aws-sdk-core/log.rb +10 -0
- data/lib/aws-sdk-core/lru_cache.rb +75 -0
- data/lib/aws-sdk-core/pageable_response.rb +3 -1
- data/lib/aws-sdk-core/param_validator.rb +9 -4
- data/lib/aws-sdk-core/plugins/bearer_authorization.rb +2 -0
- data/lib/aws-sdk-core/plugins/checksum_algorithm.rb +333 -168
- data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +1 -1
- data/lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb +14 -2
- data/lib/aws-sdk-core/plugins/credentials_configuration.rb +9 -3
- data/lib/aws-sdk-core/plugins/endpoint_pattern.rb +40 -32
- data/lib/aws-sdk-core/plugins/global_configuration.rb +8 -9
- data/lib/aws-sdk-core/plugins/http_checksum.rb +3 -8
- data/lib/aws-sdk-core/plugins/invocation_id.rb +1 -11
- data/lib/aws-sdk-core/plugins/logging.rb +2 -0
- data/lib/aws-sdk-core/plugins/protocols/api_gateway.rb +3 -1
- data/lib/aws-sdk-core/plugins/protocols/ec2.rb +2 -24
- data/lib/aws-sdk-core/plugins/protocols/json_rpc.rb +6 -8
- data/lib/aws-sdk-core/plugins/protocols/query.rb +4 -2
- data/lib/aws-sdk-core/plugins/protocols/rest_json.rb +3 -15
- data/lib/aws-sdk-core/plugins/protocols/rest_xml.rb +3 -0
- data/lib/aws-sdk-core/plugins/protocols/rpc_v2.rb +17 -0
- data/lib/aws-sdk-core/plugins/regional_endpoint.rb +162 -37
- data/lib/aws-sdk-core/plugins/request_compression.rb +226 -0
- data/lib/aws-sdk-core/plugins/retry_errors.rb +12 -3
- data/lib/aws-sdk-core/plugins/sign.rb +44 -17
- data/lib/aws-sdk-core/plugins/signature_v2.rb +2 -1
- data/lib/aws-sdk-core/plugins/signature_v4.rb +2 -1
- data/lib/aws-sdk-core/plugins/stub_responses.rb +53 -9
- data/lib/aws-sdk-core/plugins/telemetry.rb +75 -0
- data/lib/aws-sdk-core/plugins/transfer_encoding.rb +16 -9
- data/lib/aws-sdk-core/plugins/user_agent.rb +191 -14
- data/lib/aws-sdk-core/plugins.rb +39 -0
- data/lib/aws-sdk-core/process_credentials.rb +48 -29
- data/lib/aws-sdk-core/query/ec2_handler.rb +27 -0
- data/lib/aws-sdk-core/query/ec2_param_builder.rb +5 -7
- data/lib/aws-sdk-core/query/handler.rb +4 -4
- data/lib/aws-sdk-core/query/param_builder.rb +2 -2
- data/lib/aws-sdk-core/query.rb +2 -1
- data/lib/aws-sdk-core/refreshing_credentials.rb +12 -12
- data/lib/aws-sdk-core/resources.rb +8 -0
- data/lib/aws-sdk-core/rest/content_type_handler.rb +60 -0
- data/lib/aws-sdk-core/rest/handler.rb +3 -4
- data/lib/aws-sdk-core/rest/request/body.rb +32 -5
- data/lib/aws-sdk-core/rest/request/endpoint.rb +24 -4
- data/lib/aws-sdk-core/rest/request/headers.rb +15 -7
- data/lib/aws-sdk-core/rest/request/querystring_builder.rb +62 -36
- data/lib/aws-sdk-core/rest/response/body.rb +15 -1
- data/lib/aws-sdk-core/rest/response/header_list_parser.rb +79 -0
- data/lib/aws-sdk-core/rest/response/headers.rb +8 -3
- data/lib/aws-sdk-core/rest.rb +1 -0
- data/lib/aws-sdk-core/rpc_v2/builder.rb +62 -0
- data/lib/aws-sdk-core/rpc_v2/cbor_engine.rb +18 -0
- data/lib/aws-sdk-core/rpc_v2/content_type_handler.rb +47 -0
- data/lib/aws-sdk-core/rpc_v2/error_handler.rb +85 -0
- data/lib/aws-sdk-core/rpc_v2/handler.rb +79 -0
- data/lib/aws-sdk-core/rpc_v2/parser.rb +90 -0
- data/lib/aws-sdk-core/rpc_v2.rb +69 -0
- data/lib/aws-sdk-core/shared_config.rb +125 -39
- data/lib/aws-sdk-core/shared_credentials.rb +1 -7
- data/lib/aws-sdk-core/sso_credentials.rb +5 -2
- data/lib/aws-sdk-core/stubbing/protocols/ec2.rb +12 -11
- data/lib/aws-sdk-core/stubbing/protocols/json.rb +11 -10
- data/lib/aws-sdk-core/stubbing/protocols/query.rb +7 -6
- data/lib/aws-sdk-core/stubbing/protocols/rest.rb +2 -1
- data/lib/aws-sdk-core/stubbing/protocols/rest_json.rb +9 -8
- data/lib/aws-sdk-core/stubbing/protocols/rest_xml.rb +6 -5
- data/lib/aws-sdk-core/stubbing/protocols/rpc_v2.rb +39 -0
- data/lib/aws-sdk-core/stubbing/stub_data.rb +11 -0
- data/lib/aws-sdk-core/stubbing.rb +22 -0
- data/lib/aws-sdk-core/telemetry/base.rb +177 -0
- data/lib/aws-sdk-core/telemetry/no_op.rb +70 -0
- data/lib/aws-sdk-core/telemetry/otel.rb +235 -0
- data/lib/aws-sdk-core/telemetry/span_kind.rb +22 -0
- data/lib/aws-sdk-core/telemetry/span_status.rb +59 -0
- data/lib/aws-sdk-core/telemetry.rb +78 -0
- data/lib/aws-sdk-core/util.rb +39 -0
- data/lib/aws-sdk-core/waiters/poller.rb +12 -5
- data/lib/aws-sdk-core/xml/builder.rb +17 -9
- data/lib/aws-sdk-core/xml/error_handler.rb +32 -42
- data/lib/aws-sdk-core/xml/parser/frame.rb +4 -20
- data/lib/aws-sdk-core/xml/parser/{engines/oga.rb → oga_engine.rb} +2 -0
- data/lib/aws-sdk-core/xml/parser/stack.rb +2 -0
- data/lib/aws-sdk-core/xml/parser.rb +2 -6
- data/lib/aws-sdk-core.rb +82 -107
- data/lib/aws-sdk-sso/client.rb +185 -79
- data/lib/aws-sdk-sso/client_api.rb +7 -0
- data/lib/aws-sdk-sso/endpoint_parameters.rb +9 -6
- data/lib/aws-sdk-sso/endpoint_provider.rb +37 -96
- data/lib/aws-sdk-sso/endpoints.rb +3 -54
- data/lib/aws-sdk-sso/plugins/endpoints.rb +23 -22
- data/lib/aws-sdk-sso/types.rb +1 -0
- data/lib/aws-sdk-sso.rb +15 -11
- data/lib/aws-sdk-ssooidc/client.rb +592 -112
- data/lib/aws-sdk-ssooidc/client_api.rb +89 -1
- data/lib/aws-sdk-ssooidc/endpoint_parameters.rb +9 -6
- data/lib/aws-sdk-ssooidc/endpoint_provider.rb +37 -95
- data/lib/aws-sdk-ssooidc/endpoints.rb +3 -40
- data/lib/aws-sdk-ssooidc/errors.rb +52 -0
- data/lib/aws-sdk-ssooidc/plugins/endpoints.rb +23 -20
- data/lib/aws-sdk-ssooidc/types.rb +407 -53
- data/lib/aws-sdk-ssooidc.rb +15 -11
- data/lib/aws-sdk-sts/client.rb +516 -238
- data/lib/aws-sdk-sts/client_api.rb +48 -11
- data/lib/aws-sdk-sts/customizations.rb +5 -1
- data/lib/aws-sdk-sts/endpoint_parameters.rb +10 -9
- data/lib/aws-sdk-sts/endpoint_provider.rb +91 -213
- data/lib/aws-sdk-sts/endpoints.rb +3 -118
- data/lib/aws-sdk-sts/errors.rb +16 -0
- data/lib/aws-sdk-sts/plugins/endpoints.rb +23 -30
- data/lib/aws-sdk-sts/presigner.rb +1 -1
- data/lib/aws-sdk-sts/types.rb +217 -36
- data/lib/aws-sdk-sts.rb +15 -11
- data/lib/seahorse/client/async_base.rb +4 -5
- data/lib/seahorse/client/async_response.rb +19 -0
- data/lib/seahorse/client/base.rb +18 -21
- data/lib/seahorse/client/configuration.rb +0 -4
- data/lib/seahorse/client/h2/connection.rb +25 -31
- data/lib/seahorse/client/h2/handler.rb +14 -3
- data/lib/seahorse/client/handler.rb +1 -1
- data/lib/seahorse/client/http/response.rb +1 -1
- data/lib/seahorse/client/net_http/connection_pool.rb +13 -11
- data/lib/seahorse/client/net_http/handler.rb +21 -9
- data/lib/seahorse/client/net_http/patches.rb +1 -4
- data/lib/seahorse/client/networking_error.rb +1 -1
- data/lib/seahorse/client/plugin.rb +9 -0
- data/lib/seahorse/client/plugins/endpoint.rb +0 -1
- data/lib/seahorse/client/plugins/h2.rb +4 -4
- data/lib/seahorse/client/plugins/net_http.rb +57 -16
- data/lib/seahorse/client/plugins/request_callback.rb +31 -0
- data/lib/seahorse/client/request_context.rb +8 -1
- data/lib/seahorse/client/response.rb +8 -0
- data/lib/seahorse/model/operation.rb +3 -0
- data/lib/seahorse/model/shapes.rb +2 -2
- data/sig/aws-sdk-core/async_client_stubs.rbs +21 -0
- data/sig/aws-sdk-core/client_stubs.rbs +10 -0
- data/sig/aws-sdk-core/errors.rbs +22 -0
- data/sig/aws-sdk-core/resources/collection.rbs +21 -0
- data/sig/aws-sdk-core/structure.rbs +4 -0
- data/sig/aws-sdk-core/telemetry/base.rbs +46 -0
- data/sig/aws-sdk-core/telemetry/otel.rbs +22 -0
- data/sig/aws-sdk-core/telemetry/span_kind.rbs +15 -0
- data/sig/aws-sdk-core/telemetry/span_status.rbs +24 -0
- data/sig/aws-sdk-core/waiters/errors.rbs +20 -0
- data/sig/aws-sdk-core.rbs +7 -0
- data/sig/seahorse/client/async_base.rbs +18 -0
- data/sig/seahorse/client/base.rbs +25 -0
- data/sig/seahorse/client/handler_builder.rbs +16 -0
- data/sig/seahorse/client/response.rbs +61 -0
- metadata +92 -23
- /data/lib/aws-sdk-core/xml/parser/{engines/libxml.rb → libxml_engine.rb} +0 -0
- /data/lib/aws-sdk-core/xml/parser/{engines/nokogiri.rb → nokogiri_engine.rb} +0 -0
- /data/lib/aws-sdk-core/xml/parser/{engines/ox.rb → ox_engine.rb} +0 -0
- /data/lib/aws-sdk-core/xml/parser/{engines/rexml.rb → rexml_engine.rb} +0 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Aws
|
|
4
|
+
module RpcV2
|
|
5
|
+
class Handler < Seahorse::Client::Handler
|
|
6
|
+
# @param [Seahorse::Client::RequestContext] context
|
|
7
|
+
# @return [Seahorse::Client::Response]
|
|
8
|
+
def call(context)
|
|
9
|
+
build_request(context)
|
|
10
|
+
response = with_metric { @handler.call(context) }
|
|
11
|
+
response.on(200..299) { |resp| resp.data = parse_body(context) }
|
|
12
|
+
response.on(200..599) { |_resp| apply_request_id(context) }
|
|
13
|
+
response
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def with_metric(&block)
|
|
19
|
+
Aws::Plugins::UserAgent.metric('PROTOCOL_RPC_V2_CBOR', &block)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def build_request(context)
|
|
23
|
+
context.http_request.headers['Smithy-Protocol'] = 'rpc-v2-cbor'
|
|
24
|
+
context.http_request.headers['X-Amzn-Query-Mode'] = 'true' if query_compatible?(context)
|
|
25
|
+
context.http_request.http_method = 'POST'
|
|
26
|
+
context.http_request.body = build_body(context)
|
|
27
|
+
build_url(context)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def build_url(context)
|
|
31
|
+
base = context.http_request.endpoint
|
|
32
|
+
service_name = context.config.api.metadata['targetPrefix']
|
|
33
|
+
base.path += "/service/#{service_name}/operation/#{context.operation.name}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def build_body(context)
|
|
37
|
+
Builder.new(context.operation.input).serialize(context.params)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def parse_body(context)
|
|
41
|
+
cbor = context.http_response.body_contents
|
|
42
|
+
if (rules = context.operation.output)
|
|
43
|
+
if cbor.is_a?(Array)
|
|
44
|
+
# an array of emitted events
|
|
45
|
+
if cbor[0].respond_to?(:response)
|
|
46
|
+
# initial response exists
|
|
47
|
+
# it must be the first event arrived
|
|
48
|
+
resp_struct = cbor.shift.response
|
|
49
|
+
else
|
|
50
|
+
resp_struct = context.operation.output.shape.struct_class.new
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
rules.shape.members.each do |name, ref|
|
|
54
|
+
if ref.eventstream
|
|
55
|
+
resp_struct.send("#{name}=", cbor.to_enum)
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
resp_struct
|
|
59
|
+
else
|
|
60
|
+
Parser.new(
|
|
61
|
+
rules,
|
|
62
|
+
query_compatible: query_compatible?(context)
|
|
63
|
+
).parse(cbor)
|
|
64
|
+
end
|
|
65
|
+
else
|
|
66
|
+
EmptyStructure.new
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def apply_request_id(context)
|
|
71
|
+
context[:request_id] = context.http_response.headers['x-amzn-requestid']
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def query_compatible?(context)
|
|
75
|
+
context.config.api.metadata.key?('awsQueryCompatible')
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'time'
|
|
4
|
+
|
|
5
|
+
module Aws
|
|
6
|
+
module RpcV2
|
|
7
|
+
class Parser
|
|
8
|
+
include Seahorse::Model::Shapes
|
|
9
|
+
|
|
10
|
+
# @param [Seahorse::Model::ShapeRef] rules
|
|
11
|
+
def initialize(rules, query_compatible: false)
|
|
12
|
+
@rules = rules
|
|
13
|
+
@query_compatible = query_compatible
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def parse(cbor, target = nil)
|
|
17
|
+
return {} if cbor.empty?
|
|
18
|
+
|
|
19
|
+
parse_ref(@rules, RpcV2.decode(cbor), target)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def structure(ref, values, target = nil)
|
|
25
|
+
shape = ref.shape
|
|
26
|
+
target = ref.shape.struct_class.new if target.nil?
|
|
27
|
+
values.each do |key, value|
|
|
28
|
+
member_name, member_ref = shape.member_by_location_name(key)
|
|
29
|
+
if member_ref
|
|
30
|
+
target[member_name] = parse_ref(member_ref, value)
|
|
31
|
+
elsif shape.union && key != '__type'
|
|
32
|
+
target[:unknown] = { 'name' => key, 'value' => value }
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
# In services that were previously Query/XML, members that were
|
|
36
|
+
# "flattened" defaulted to empty lists. In JSON, these values are nil,
|
|
37
|
+
# which is backwards incompatible. To preserve backwards compatibility,
|
|
38
|
+
# we set a default value of [] for these members.
|
|
39
|
+
if @query_compatible
|
|
40
|
+
ref.shape.members.each do |member_name, member_target|
|
|
41
|
+
next unless target[member_name].nil?
|
|
42
|
+
|
|
43
|
+
if flattened_list?(member_target.shape)
|
|
44
|
+
target[member_name] = []
|
|
45
|
+
elsif flattened_map?(member_target.shape)
|
|
46
|
+
target[member_name] = {}
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if shape.union
|
|
52
|
+
# convert to subclass
|
|
53
|
+
member_subclass = shape.member_subclass(target.member).new
|
|
54
|
+
member_subclass[target.member] = target.value
|
|
55
|
+
target = member_subclass
|
|
56
|
+
end
|
|
57
|
+
target
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def list(ref, values, target = nil)
|
|
61
|
+
target = [] if target.nil?
|
|
62
|
+
values.each do |value|
|
|
63
|
+
target << parse_ref(ref.shape.member, value)
|
|
64
|
+
end
|
|
65
|
+
target
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def map(ref, values, target = nil)
|
|
69
|
+
target = {} if target.nil?
|
|
70
|
+
values.each do |key, value|
|
|
71
|
+
target[key] = parse_ref(ref.shape.value, value) unless value.nil?
|
|
72
|
+
end
|
|
73
|
+
target
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def parse_ref(ref, value, target = nil)
|
|
77
|
+
if value.nil?
|
|
78
|
+
nil
|
|
79
|
+
else
|
|
80
|
+
case ref.shape
|
|
81
|
+
when StructureShape then structure(ref, value, target)
|
|
82
|
+
when ListShape then list(ref, value, target)
|
|
83
|
+
when MapShape then map(ref, value, target)
|
|
84
|
+
else value
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'cbor'
|
|
4
|
+
require_relative 'rpc_v2/builder'
|
|
5
|
+
require_relative 'rpc_v2/content_type_handler'
|
|
6
|
+
require_relative 'rpc_v2/error_handler'
|
|
7
|
+
require_relative 'rpc_v2/handler'
|
|
8
|
+
require_relative 'rpc_v2/parser'
|
|
9
|
+
|
|
10
|
+
module Aws
|
|
11
|
+
# @api private
|
|
12
|
+
module RpcV2
|
|
13
|
+
class << self
|
|
14
|
+
# @param [Symbol,Class] engine
|
|
15
|
+
# Must be one of the following values:
|
|
16
|
+
#
|
|
17
|
+
# * :cbor
|
|
18
|
+
#
|
|
19
|
+
def engine=(engine)
|
|
20
|
+
@engine = Class === engine ? engine : load_engine(engine)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# @return [Class] Returns the default engine.
|
|
24
|
+
# One of:
|
|
25
|
+
#
|
|
26
|
+
# * {CborEngine}
|
|
27
|
+
#
|
|
28
|
+
def engine
|
|
29
|
+
set_default_engine unless @engine
|
|
30
|
+
@engine
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def encode(data)
|
|
34
|
+
@engine.encode(data)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def decode(bytes)
|
|
38
|
+
bytes.force_encoding(Encoding::BINARY)
|
|
39
|
+
@engine.decode(bytes)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def set_default_engine
|
|
43
|
+
[:cbor].each do |name|
|
|
44
|
+
@engine ||= try_load_engine(name)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
unless @engine
|
|
48
|
+
raise 'Unable to find a compatible cbor library.'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
private
|
|
53
|
+
|
|
54
|
+
def load_engine(name)
|
|
55
|
+
require "aws-sdk-core/rpc_v2/#{name}_engine"
|
|
56
|
+
const_name = name[0].upcase + name[1..-1] + 'Engine'
|
|
57
|
+
const_get(const_name)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def try_load_engine(name)
|
|
61
|
+
load_engine(name)
|
|
62
|
+
rescue LoadError
|
|
63
|
+
false
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
set_default_engine
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -138,7 +138,11 @@ module Aws
|
|
|
138
138
|
role_session_name: entry['role_session_name']
|
|
139
139
|
}
|
|
140
140
|
cfg[:region] = opts[:region] if opts[:region]
|
|
141
|
-
|
|
141
|
+
with_metrics('CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN') do
|
|
142
|
+
creds = AssumeRoleWebIdentityCredentials.new(cfg)
|
|
143
|
+
creds.metrics << 'CREDENTIALS_PROFILE_STS_WEB_ID_TOKEN'
|
|
144
|
+
creds
|
|
145
|
+
end
|
|
142
146
|
end
|
|
143
147
|
end
|
|
144
148
|
end
|
|
@@ -167,6 +171,26 @@ module Aws
|
|
|
167
171
|
token
|
|
168
172
|
end
|
|
169
173
|
|
|
174
|
+
# Source a custom configured endpoint from the shared configuration file
|
|
175
|
+
#
|
|
176
|
+
# @param [Hash] opts
|
|
177
|
+
# @option opts [String] :profile
|
|
178
|
+
# @option opts [String] :service_id
|
|
179
|
+
def configured_endpoint(opts = {})
|
|
180
|
+
# services section is only allowed in the shared config file (not credentials)
|
|
181
|
+
profile = opts[:profile] || @profile_name
|
|
182
|
+
service_id = opts[:service_id]&.gsub(" ", "_")&.downcase
|
|
183
|
+
if @parsed_config && (prof_config = @parsed_config[profile])
|
|
184
|
+
services_section_name = prof_config['services']
|
|
185
|
+
if (services_config = @parsed_config["services #{services_section_name}"]) &&
|
|
186
|
+
(service_config = services_config[service_id])
|
|
187
|
+
return service_config['endpoint_url'] if service_config['endpoint_url']
|
|
188
|
+
end
|
|
189
|
+
return prof_config['endpoint_url']
|
|
190
|
+
end
|
|
191
|
+
nil
|
|
192
|
+
end
|
|
193
|
+
|
|
170
194
|
# Add an accessor method (similar to attr_reader) to return a configuration value
|
|
171
195
|
# Uses the get_config_value below to control where
|
|
172
196
|
# values are loaded from
|
|
@@ -178,6 +202,8 @@ module Aws
|
|
|
178
202
|
|
|
179
203
|
config_reader(
|
|
180
204
|
:region,
|
|
205
|
+
:account_id_endpoint_mode,
|
|
206
|
+
:sigv4a_signing_region_set,
|
|
181
207
|
:ca_bundle,
|
|
182
208
|
:credential_process,
|
|
183
209
|
:endpoint_discovery_enabled,
|
|
@@ -185,10 +211,14 @@ module Aws
|
|
|
185
211
|
:use_fips_endpoint,
|
|
186
212
|
:ec2_metadata_service_endpoint,
|
|
187
213
|
:ec2_metadata_service_endpoint_mode,
|
|
214
|
+
:ec2_metadata_v1_disabled,
|
|
215
|
+
:disable_host_prefix_injection,
|
|
188
216
|
:max_attempts,
|
|
189
217
|
:retry_mode,
|
|
190
218
|
:adaptive_retry_wait_to_fill,
|
|
191
219
|
:correct_clock_skew,
|
|
220
|
+
:request_checksum_calculation,
|
|
221
|
+
:response_checksum_validation,
|
|
192
222
|
:csm_client_id,
|
|
193
223
|
:csm_enabled,
|
|
194
224
|
:csm_host,
|
|
@@ -197,7 +227,12 @@ module Aws
|
|
|
197
227
|
:s3_use_arn_region,
|
|
198
228
|
:s3_us_east_1_regional_endpoint,
|
|
199
229
|
:s3_disable_multiregion_access_points,
|
|
200
|
-
:
|
|
230
|
+
:s3_disable_express_session_auth,
|
|
231
|
+
:defaults_mode,
|
|
232
|
+
:sdk_ua_app_id,
|
|
233
|
+
:disable_request_compression,
|
|
234
|
+
:request_min_compression_size_bytes,
|
|
235
|
+
:ignore_configured_endpoint_urls
|
|
201
236
|
)
|
|
202
237
|
|
|
203
238
|
private
|
|
@@ -225,8 +260,8 @@ module Aws
|
|
|
225
260
|
'provide only source_profile or credential_source, not both.'
|
|
226
261
|
elsif opts[:source_profile]
|
|
227
262
|
opts[:visited_profiles] ||= Set.new
|
|
228
|
-
|
|
229
|
-
if opts[:credentials]
|
|
263
|
+
provider = resolve_source_profile(opts[:source_profile], opts)
|
|
264
|
+
if provider && (opts[:credentials] = provider.credentials)
|
|
230
265
|
opts[:role_session_name] ||= prof_cfg['role_session_name']
|
|
231
266
|
opts[:role_session_name] ||= 'default_session'
|
|
232
267
|
opts[:role_arn] ||= prof_cfg['role_arn']
|
|
@@ -235,17 +270,28 @@ module Aws
|
|
|
235
270
|
opts[:serial_number] ||= prof_cfg['mfa_serial']
|
|
236
271
|
opts[:profile] = opts.delete(:source_profile)
|
|
237
272
|
opts.delete(:visited_profiles)
|
|
238
|
-
|
|
273
|
+
|
|
274
|
+
metrics = provider.metrics
|
|
275
|
+
if provider.is_a?(AssumeRoleCredentials)
|
|
276
|
+
opts[:credentials] = provider
|
|
277
|
+
metrics.delete('CREDENTIALS_STS_ASSUME_ROLE')
|
|
278
|
+
else
|
|
279
|
+
metrics << 'CREDENTIALS_PROFILE_SOURCE_PROFILE'
|
|
280
|
+
end
|
|
281
|
+
# Set the original credentials metrics to [] to prevent duplicate metrics during sign plugin
|
|
282
|
+
opts[:credentials].metrics = []
|
|
283
|
+
with_metrics(metrics) do
|
|
284
|
+
creds = AssumeRoleCredentials.new(opts)
|
|
285
|
+
creds.metrics.push(*metrics)
|
|
286
|
+
creds
|
|
287
|
+
end
|
|
239
288
|
else
|
|
240
289
|
raise Errors::NoSourceProfileError,
|
|
241
290
|
"Profile #{profile} has a role_arn, and source_profile, but the"\
|
|
242
291
|
' source_profile does not have credentials.'
|
|
243
292
|
end
|
|
244
293
|
elsif credential_source
|
|
245
|
-
opts[:credentials] = credentials_from_source(
|
|
246
|
-
credential_source,
|
|
247
|
-
chain_config
|
|
248
|
-
)
|
|
294
|
+
opts[:credentials] = credentials_from_source(credential_source, chain_config)
|
|
249
295
|
if opts[:credentials]
|
|
250
296
|
opts[:role_session_name] ||= prof_cfg['role_session_name']
|
|
251
297
|
opts[:role_session_name] ||= 'default_session'
|
|
@@ -254,7 +300,16 @@ module Aws
|
|
|
254
300
|
opts[:external_id] ||= prof_cfg['external_id']
|
|
255
301
|
opts[:serial_number] ||= prof_cfg['mfa_serial']
|
|
256
302
|
opts.delete(:source_profile) # Cleanup
|
|
257
|
-
|
|
303
|
+
|
|
304
|
+
metrics = opts[:credentials].metrics
|
|
305
|
+
metrics << 'CREDENTIALS_PROFILE_NAMED_PROVIDER'
|
|
306
|
+
# Set the original credentials metrics to [] to prevent duplicate metrics during sign plugin
|
|
307
|
+
opts[:credentials].metrics = []
|
|
308
|
+
with_metrics(metrics) do
|
|
309
|
+
creds = AssumeRoleCredentials.new(opts)
|
|
310
|
+
creds.metrics.push(*metrics)
|
|
311
|
+
creds
|
|
312
|
+
end
|
|
258
313
|
else
|
|
259
314
|
raise Errors::NoSourceCredentials,
|
|
260
315
|
"Profile #{profile} could not get source credentials from"\
|
|
@@ -282,12 +337,24 @@ module Aws
|
|
|
282
337
|
elsif profile_config && profile_config['source_profile']
|
|
283
338
|
opts.delete(:source_profile)
|
|
284
339
|
assume_role_credentials_from_config(opts.merge(profile: profile))
|
|
285
|
-
elsif (provider =
|
|
286
|
-
provider
|
|
340
|
+
elsif (provider = assume_role_web_identity_credentials_from_config_with_metrics(opts.merge(profile: profile)))
|
|
341
|
+
provider if provider.credentials.set?
|
|
287
342
|
elsif (provider = assume_role_process_credentials_from_config(profile))
|
|
288
|
-
provider
|
|
289
|
-
elsif (provider =
|
|
290
|
-
provider
|
|
343
|
+
provider if provider.credentials.set?
|
|
344
|
+
elsif (provider = sso_credentials_from_config_with_metrics(profile))
|
|
345
|
+
provider if provider.credentials.set?
|
|
346
|
+
end
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
def assume_role_web_identity_credentials_from_config_with_metrics(opts)
|
|
350
|
+
with_metrics('CREDENTIALS_PROFILE_SOURCE_PROFILE') do
|
|
351
|
+
assume_role_web_identity_credentials_from_config(opts)
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def sso_credentials_from_config_with_metrics(profile)
|
|
356
|
+
with_metrics('CREDENTIALS_PROFILE_SOURCE_PROFILE') do
|
|
357
|
+
sso_credentials_from_config(profile: profile)
|
|
291
358
|
end
|
|
292
359
|
end
|
|
293
360
|
|
|
@@ -312,7 +379,11 @@ module Aws
|
|
|
312
379
|
if @parsed_config
|
|
313
380
|
credential_process ||= @parsed_config.fetch(profile, {})['credential_process']
|
|
314
381
|
end
|
|
315
|
-
|
|
382
|
+
if credential_process
|
|
383
|
+
creds = ProcessCredentials.new([credential_process])
|
|
384
|
+
creds.metrics << 'CREDENTIALS_PROFILE_PROCESS'
|
|
385
|
+
creds
|
|
386
|
+
end
|
|
316
387
|
end
|
|
317
388
|
|
|
318
389
|
def credentials_from_shared(profile, _opts)
|
|
@@ -335,12 +406,8 @@ module Aws
|
|
|
335
406
|
!(prof_config.keys & SSO_CREDENTIAL_PROFILE_KEYS).empty?
|
|
336
407
|
|
|
337
408
|
if sso_session_name = prof_config['sso_session']
|
|
338
|
-
sso_session = cfg
|
|
339
|
-
|
|
340
|
-
raise ArgumentError,
|
|
341
|
-
"sso-session #{sso_session_name} must be defined in the config file. " \
|
|
342
|
-
"Referenced by profile #{profile}"
|
|
343
|
-
end
|
|
409
|
+
sso_session = sso_session(cfg, profile, sso_session_name)
|
|
410
|
+
|
|
344
411
|
sso_region = sso_session['sso_region']
|
|
345
412
|
sso_start_url = sso_session['sso_start_url']
|
|
346
413
|
|
|
@@ -360,13 +427,18 @@ module Aws
|
|
|
360
427
|
sso_start_url = prof_config['sso_start_url']
|
|
361
428
|
end
|
|
362
429
|
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
430
|
+
metric = prof_config['sso_session'] ? 'CREDENTIALS_PROFILE_SSO' : 'CREDENTIALS_PROFILE_SSO_LEGACY'
|
|
431
|
+
with_metrics(metric) do
|
|
432
|
+
creds = SSOCredentials.new(
|
|
433
|
+
sso_account_id: prof_config['sso_account_id'],
|
|
434
|
+
sso_role_name: prof_config['sso_role_name'],
|
|
435
|
+
sso_session: prof_config['sso_session'],
|
|
436
|
+
sso_region: sso_region,
|
|
437
|
+
sso_start_url: sso_start_url
|
|
369
438
|
)
|
|
439
|
+
creds.metrics << metric
|
|
440
|
+
creds
|
|
441
|
+
end
|
|
370
442
|
end
|
|
371
443
|
end
|
|
372
444
|
|
|
@@ -378,16 +450,7 @@ module Aws
|
|
|
378
450
|
!(prof_config.keys & SSO_TOKEN_PROFILE_KEYS).empty?
|
|
379
451
|
|
|
380
452
|
sso_session_name = prof_config['sso_session']
|
|
381
|
-
sso_session = cfg
|
|
382
|
-
unless sso_session
|
|
383
|
-
raise ArgumentError,
|
|
384
|
-
"sso-session #{sso_session_name} must be defined in the config file." \
|
|
385
|
-
"Referenced by profile #{profile}"
|
|
386
|
-
end
|
|
387
|
-
|
|
388
|
-
unless sso_session['sso_region']
|
|
389
|
-
raise ArgumentError, "sso-session #{sso_session_name} missing required parameter: sso_region"
|
|
390
|
-
end
|
|
453
|
+
sso_session = sso_session(cfg, profile, sso_session_name)
|
|
391
454
|
|
|
392
455
|
SSOTokenProvider.new(
|
|
393
456
|
sso_session: sso_session_name,
|
|
@@ -400,8 +463,10 @@ module Aws
|
|
|
400
463
|
creds = Credentials.new(
|
|
401
464
|
prof_config['aws_access_key_id'],
|
|
402
465
|
prof_config['aws_secret_access_key'],
|
|
403
|
-
prof_config['aws_session_token']
|
|
466
|
+
prof_config['aws_session_token'],
|
|
467
|
+
account_id: prof_config['aws_account_id']
|
|
404
468
|
)
|
|
469
|
+
creds.metrics = ['CREDENTIALS_PROFILE']
|
|
405
470
|
creds if creds.set?
|
|
406
471
|
end
|
|
407
472
|
|
|
@@ -445,5 +510,26 @@ module Aws
|
|
|
445
510
|
ret ||= 'default'
|
|
446
511
|
ret
|
|
447
512
|
end
|
|
513
|
+
|
|
514
|
+
def sso_session(cfg, profile, sso_session_name)
|
|
515
|
+
# aws sso-configure may add quotes around sso session names with whitespace
|
|
516
|
+
sso_session = cfg["sso-session #{sso_session_name}"] || cfg["sso-session '#{sso_session_name}'"]
|
|
517
|
+
|
|
518
|
+
unless sso_session
|
|
519
|
+
raise ArgumentError,
|
|
520
|
+
"sso-session #{sso_session_name} must be defined in the config file. " \
|
|
521
|
+
"Referenced by profile #{profile}"
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
unless sso_session['sso_region']
|
|
525
|
+
raise ArgumentError, "sso-session #{sso_session_name} missing required parameter: sso_region"
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
sso_session
|
|
529
|
+
end
|
|
530
|
+
|
|
531
|
+
def with_metrics(metrics, &block)
|
|
532
|
+
Aws::Plugins::UserAgent.metric(*metrics, &block)
|
|
533
|
+
end
|
|
448
534
|
end
|
|
449
535
|
end
|
|
@@ -7,13 +7,6 @@ module Aws
|
|
|
7
7
|
|
|
8
8
|
include CredentialProvider
|
|
9
9
|
|
|
10
|
-
# @api private
|
|
11
|
-
KEY_MAP = {
|
|
12
|
-
'aws_access_key_id' => 'access_key_id',
|
|
13
|
-
'aws_secret_access_key' => 'secret_access_key',
|
|
14
|
-
'aws_session_token' => 'session_token',
|
|
15
|
-
}
|
|
16
|
-
|
|
17
10
|
# Constructs a new SharedCredentials object. This will load static
|
|
18
11
|
# (access_key_id, secret_access_key and session_token) AWS access
|
|
19
12
|
# credentials from an ini file, which supports profiles. The default
|
|
@@ -47,6 +40,7 @@ module Aws
|
|
|
47
40
|
)
|
|
48
41
|
@credentials = config.credentials(profile: @profile_name)
|
|
49
42
|
end
|
|
43
|
+
@metrics = ['CREDENTIALS_CODE']
|
|
50
44
|
end
|
|
51
45
|
|
|
52
46
|
# @return [String]
|
|
@@ -91,6 +91,7 @@ module Aws
|
|
|
91
91
|
client_opts[:credentials] = nil
|
|
92
92
|
@client = Aws::SSO::Client.new(client_opts)
|
|
93
93
|
end
|
|
94
|
+
@metrics = ['CREDENTIALS_SSO']
|
|
94
95
|
else # legacy behavior
|
|
95
96
|
missing_keys = LEGACY_REQUIRED_OPTS.select { |k| options[k].nil? }
|
|
96
97
|
unless missing_keys.empty?
|
|
@@ -111,6 +112,7 @@ module Aws
|
|
|
111
112
|
client_opts[:credentials] = nil
|
|
112
113
|
|
|
113
114
|
@client = options[:client] || Aws::SSO::Client.new(client_opts)
|
|
115
|
+
@metrics = ['CREDENTIALS_SSO_LEGACY']
|
|
114
116
|
end
|
|
115
117
|
|
|
116
118
|
@async_refresh = true
|
|
@@ -156,9 +158,10 @@ module Aws
|
|
|
156
158
|
@credentials = Credentials.new(
|
|
157
159
|
c.access_key_id,
|
|
158
160
|
c.secret_access_key,
|
|
159
|
-
c.session_token
|
|
161
|
+
c.session_token,
|
|
162
|
+
account_id: @sso_account_id
|
|
160
163
|
)
|
|
161
|
-
@expiration = c.expiration
|
|
164
|
+
@expiration = Time.at(c.expiration / 1000.0)
|
|
162
165
|
end
|
|
163
166
|
|
|
164
167
|
def sso_cache_file
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module Aws
|
|
4
4
|
module Stubbing
|
|
5
5
|
module Protocols
|
|
6
|
+
# @api private
|
|
6
7
|
class EC2
|
|
7
8
|
|
|
8
9
|
def stub_data(api, operation, data)
|
|
@@ -16,17 +17,17 @@ module Aws
|
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
def stub_error(error_code)
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
<ErrorResponse>
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</ErrorResponse>
|
|
20
|
+
resp = Seahorse::Client::Http::Response.new
|
|
21
|
+
resp.status_code = 400
|
|
22
|
+
resp.body = <<~XML.strip
|
|
23
|
+
<ErrorResponse>
|
|
24
|
+
<Error>
|
|
25
|
+
<Code>#{error_code}</Code>
|
|
26
|
+
<Message>stubbed-response-error-message</Message>
|
|
27
|
+
</Error>
|
|
28
|
+
</ErrorResponse>
|
|
28
29
|
XML
|
|
29
|
-
|
|
30
|
+
resp
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
private
|
|
@@ -37,7 +38,7 @@ module Aws
|
|
|
37
38
|
xml.shift
|
|
38
39
|
xml.pop
|
|
39
40
|
xmlns = "http://ec2.amazonaws.com/doc/#{api.version}/".inspect
|
|
40
|
-
xml.unshift(
|
|
41
|
+
xml.unshift(' <requestId>stubbed-request-id</requestId>')
|
|
41
42
|
xml.unshift("<#{operation.name}Response xmlns=#{xmlns}>\n")
|
|
42
43
|
xml.push("</#{operation.name}Response>\n")
|
|
43
44
|
xml.join
|
|
@@ -3,27 +3,28 @@
|
|
|
3
3
|
module Aws
|
|
4
4
|
module Stubbing
|
|
5
5
|
module Protocols
|
|
6
|
+
# @api private
|
|
6
7
|
class Json
|
|
7
8
|
|
|
8
9
|
def stub_data(api, operation, data)
|
|
9
10
|
resp = Seahorse::Client::Http::Response.new
|
|
10
11
|
resp.status_code = 200
|
|
11
|
-
resp.headers[
|
|
12
|
-
resp.headers[
|
|
12
|
+
resp.headers['Content-Type'] = content_type(api)
|
|
13
|
+
resp.headers['x-amzn-RequestId'] = 'stubbed-request-id'
|
|
13
14
|
resp.body = build_body(operation, data)
|
|
14
15
|
resp
|
|
15
16
|
end
|
|
16
17
|
|
|
17
18
|
def stub_error(error_code)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
19
|
+
resp = Seahorse::Client::Http::Response.new
|
|
20
|
+
resp.status_code = 400
|
|
21
|
+
resp.body = <<~JSON.strip
|
|
22
|
+
{
|
|
23
|
+
"code": #{error_code.inspect},
|
|
24
|
+
"message": "stubbed-response-error-message"
|
|
25
|
+
}
|
|
25
26
|
JSON
|
|
26
|
-
|
|
27
|
+
resp
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
private
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
module Aws
|
|
4
4
|
module Stubbing
|
|
5
5
|
module Protocols
|
|
6
|
+
# @api private
|
|
6
7
|
class Query
|
|
7
8
|
|
|
8
9
|
def stub_data(api, operation, data)
|
|
@@ -13,10 +14,10 @@ module Aws
|
|
|
13
14
|
end
|
|
14
15
|
|
|
15
16
|
def stub_error(error_code)
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
resp = Seahorse::Client::Http::Response.new
|
|
18
|
+
resp.status_code = 400
|
|
19
|
+
resp.body = XmlError.new(error_code).to_xml
|
|
20
|
+
resp
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
private
|
|
@@ -24,9 +25,9 @@ module Aws
|
|
|
24
25
|
def build_body(api, operation, data)
|
|
25
26
|
xml = []
|
|
26
27
|
builder = Aws::Xml::DocBuilder.new(target: xml, indent: ' ')
|
|
27
|
-
builder.node(operation.name
|
|
28
|
+
builder.node("#{operation.name}Response", xmlns: xmlns(api)) do
|
|
28
29
|
if (rules = operation.output)
|
|
29
|
-
rules.location_name = operation.name
|
|
30
|
+
rules.location_name = "#{operation.name}Result"
|
|
30
31
|
Xml::Builder.new(rules, target: xml, pad:' ').to_xml(data)
|
|
31
32
|
end
|
|
32
33
|
builder.node('ResponseMetadata') do
|