misty 0.1.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +222 -1
- data/lib/misty.rb +8 -0
- data/lib/misty/auth.rb +60 -0
- data/lib/misty/auth/auth_v2.rb +46 -0
- data/lib/misty/auth/auth_v3.rb +58 -0
- data/lib/misty/autoload.rb +82 -0
- data/lib/misty/cloud.rb +133 -0
- data/lib/misty/http/client.rb +115 -0
- data/lib/misty/http/direct.rb +26 -0
- data/lib/misty/http/method_builder.rb +96 -0
- data/lib/misty/http/request.rb +75 -0
- data/lib/misty/misty.rb +51 -0
- data/lib/misty/openstack/aodh/aodh_v2.rb +12 -0
- data/lib/misty/openstack/aodh/v2.rb +20 -0
- data/lib/misty/openstack/ceilometer/ceilometer_v2.rb +13 -0
- data/lib/misty/openstack/ceilometer/v2.rb +20 -0
- data/lib/misty/openstack/cinder/cinder_v1.rb +35 -0
- data/lib/misty/openstack/cinder/cinder_v3.rb +148 -0
- data/lib/misty/openstack/cinder/v1.rb +24 -0
- data/lib/misty/openstack/cinder/v3.rb +24 -0
- data/lib/misty/openstack/designate/designate_v2.rb +69 -0
- data/lib/misty/openstack/designate/v2.rb +20 -0
- data/lib/misty/openstack/glance/glance_v1.rb +16 -0
- data/lib/misty/openstack/glance/glance_v2.rb +29 -0
- data/lib/misty/openstack/glance/v1.rb +20 -0
- data/lib/misty/openstack/glance/v2.rb +20 -0
- data/lib/misty/openstack/heat/heat_v1.rb +85 -0
- data/lib/misty/openstack/heat/v1.rb +24 -0
- data/lib/misty/openstack/ironic/ironic_v1.rb +71 -0
- data/lib/misty/openstack/ironic/v1.rb +26 -0
- data/lib/misty/openstack/karbor/karbor_v1.rb +32 -0
- data/lib/misty/openstack/karbor/v1.rb +20 -0
- data/lib/misty/openstack/keystone/keystone_v2_0.rb +11 -0
- data/lib/misty/openstack/keystone/keystone_v2_0_ext.rb +32 -0
- data/lib/misty/openstack/keystone/keystone_v3.rb +147 -0
- data/lib/misty/openstack/keystone/keystone_v3_ext.rb +124 -0
- data/lib/misty/openstack/keystone/v2_0.rb +23 -0
- data/lib/misty/openstack/keystone/v3.rb +23 -0
- data/lib/misty/openstack/magnum/magnum_v1.rb +41 -0
- data/lib/misty/openstack/magnum/v1.rb +26 -0
- data/lib/misty/openstack/manila/manila_v2.rb +143 -0
- data/lib/misty/openstack/manila/v2.rb +26 -0
- data/lib/misty/openstack/microversion.rb +62 -0
- data/lib/misty/openstack/neutron/neutron_v2_0.rb +205 -0
- data/lib/misty/openstack/neutron/v2_0.rb +20 -0
- data/lib/misty/openstack/nova/nova_v2_1.rb +269 -0
- data/lib/misty/openstack/nova/v2_1.rb +40 -0
- data/lib/misty/openstack/sahara/sahara_v1_1.rb +77 -0
- data/lib/misty/openstack/sahara/v1_1.rb +20 -0
- data/lib/misty/openstack/searchlight/searchlight_v1.rb +15 -0
- data/lib/misty/openstack/searchlight/v1.rb +20 -0
- data/lib/misty/openstack/senlin/senlin_v1.rb +66 -0
- data/lib/misty/openstack/senlin/v1.rb +20 -0
- data/lib/misty/openstack/swift/swift_v1.rb +23 -0
- data/lib/misty/openstack/swift/v1.rb +20 -0
- data/lib/misty/openstack/trove/trove_v1_0.rb +51 -0
- data/lib/misty/openstack/trove/v1_0.rb +20 -0
- data/lib/misty/openstack/zaqar/v2.rb +20 -0
- data/lib/misty/openstack/zaqar/zaqar_v2.rb +46 -0
- data/lib/misty/version.rb +2 -2
- data/test/integration/compute_test.rb +35 -0
- data/test/integration/network_test.rb +34 -0
- data/test/integration/orchestration_test.rb +92 -0
- data/test/integration/test_helper.rb +19 -0
- data/test/integration/vcr/compute_using_nova_v2_1.yml +1107 -0
- data/test/integration/vcr/network_using_neutron_v2_0.yml +1029 -0
- data/test/integration/vcr/orchestration_using_heat_v1.yml +1457 -0
- data/test/unit/auth_helper.rb +52 -0
- data/test/unit/auth_test.rb +99 -0
- data/test/unit/cloud/requests_test.rb +113 -0
- data/test/unit/cloud/services_test.rb +171 -0
- data/test/unit/cloud_test.rb +145 -0
- data/test/unit/http/client_test.rb +74 -0
- data/test/unit/http/direct_test.rb +103 -0
- data/test/unit/http/method_builder_test.rb +133 -0
- data/test/unit/http/request_test.rb +123 -0
- data/test/unit/misty_test.rb +36 -0
- data/test/unit/openstack/APIs_test.rb +40 -0
- data/test/unit/openstack/microversion_test.rb +70 -0
- data/test/unit/service_helper.rb +25 -0
- data/test/unit/test_helper.rb +8 -0
- metadata +170 -5
data/lib/misty/cloud.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'misty/auth/auth_v2'
|
2
|
+
require 'misty/auth/auth_v3'
|
3
|
+
|
4
|
+
module Misty
|
5
|
+
class Cloud
|
6
|
+
Setup = Struct.new(:auth, :content_type, :log)
|
7
|
+
|
8
|
+
Options = Struct.new(:alarming, :baremetal, :block_storage, :clustering, :compute, :container, :data_processing,
|
9
|
+
:database, :data_protection, :dns, :identity, :image, :messaging, :metering, :network, :object_storage,
|
10
|
+
:orchestration, :search, :shared_file_systems)
|
11
|
+
|
12
|
+
attr_reader :services
|
13
|
+
|
14
|
+
def initialize(options = {:auth => {}})
|
15
|
+
@cloud = Setup.new
|
16
|
+
@cloud.auth = Misty::Auth.factory(options[:auth])
|
17
|
+
@cloud.content_type = options[:content_type] ? options[:content_type] : nil
|
18
|
+
@cloud.log = Logger.new(options[:log_file] ? options[:log_file] : Misty::LOG_FILE)
|
19
|
+
@cloud.log.level = options[:log_level] ? options[:log_level] : Misty::LOG_LEVEL
|
20
|
+
|
21
|
+
@options = Options.new
|
22
|
+
Misty.services.each do |service|
|
23
|
+
@options.send("#{service.name}=".to_sym, options[service.name] ? options[service.name] : {})
|
24
|
+
end
|
25
|
+
|
26
|
+
@services = setup_services(@options)
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup_services(options)
|
30
|
+
services = {}
|
31
|
+
Misty.services.each do |service|
|
32
|
+
if options[service.name] && options[service.name][:api_version] \
|
33
|
+
&& service.versions.include?(options[service.name][:api_version])
|
34
|
+
services.merge!(service.name => {service.project => options[service.name][:api_version]})
|
35
|
+
else
|
36
|
+
# Highest version is used by default!
|
37
|
+
services.merge!(service.name => {service.project => service.versions.sort[-1]})
|
38
|
+
end
|
39
|
+
end
|
40
|
+
services
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_service(service_name)
|
44
|
+
project = @services[service_name].keys[0]
|
45
|
+
version = @services[service_name].fetch(project)
|
46
|
+
version = self.class.dot_to_underscore(version)
|
47
|
+
klass = Object.const_get("Misty::Openstack::#{project.capitalize}::#{version.capitalize}")
|
48
|
+
klass.new(@cloud, @options[service_name])
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.dot_to_underscore(val)
|
52
|
+
val.gsub(/\./,'_')
|
53
|
+
end
|
54
|
+
|
55
|
+
def alarming
|
56
|
+
@alarming ||= build_service(:alarming)
|
57
|
+
end
|
58
|
+
|
59
|
+
def baremetal
|
60
|
+
@baremetal ||= build_service(:baremetal)
|
61
|
+
end
|
62
|
+
|
63
|
+
def block_storage
|
64
|
+
@block_storage ||= build_service(:block_storage)
|
65
|
+
end
|
66
|
+
|
67
|
+
alias volume block_storage
|
68
|
+
|
69
|
+
def clustering
|
70
|
+
@clustering ||= build_service(:clustering)
|
71
|
+
end
|
72
|
+
|
73
|
+
def compute
|
74
|
+
@compute ||= build_service(:compute)
|
75
|
+
end
|
76
|
+
|
77
|
+
def container
|
78
|
+
@container ||= build_service(:container)
|
79
|
+
end
|
80
|
+
|
81
|
+
def data_processing
|
82
|
+
@data_processing ||= build_service(:data_processing)
|
83
|
+
end
|
84
|
+
|
85
|
+
def data_protection
|
86
|
+
@data_protection ||= build_service(:data_protection)
|
87
|
+
end
|
88
|
+
|
89
|
+
def database
|
90
|
+
@database ||= build_service(:database)
|
91
|
+
end
|
92
|
+
|
93
|
+
def dns
|
94
|
+
@dns ||= build_service(:dns)
|
95
|
+
end
|
96
|
+
|
97
|
+
def identity
|
98
|
+
@identity ||= build_service(:identity)
|
99
|
+
end
|
100
|
+
|
101
|
+
def image
|
102
|
+
@image ||= build_service(:image)
|
103
|
+
end
|
104
|
+
|
105
|
+
def messaging
|
106
|
+
@messaging ||= build_service(:messaging)
|
107
|
+
end
|
108
|
+
|
109
|
+
def metering
|
110
|
+
@metering ||= build_service(:metering)
|
111
|
+
end
|
112
|
+
|
113
|
+
def network
|
114
|
+
@network ||= build_service(:network)
|
115
|
+
end
|
116
|
+
|
117
|
+
def object_storage
|
118
|
+
@object_storage ||= build_service(:object_storage)
|
119
|
+
end
|
120
|
+
|
121
|
+
def orchestration
|
122
|
+
@orchestration ||= build_service(:orchestration)
|
123
|
+
end
|
124
|
+
|
125
|
+
def search
|
126
|
+
@search ||= build_service(:search)
|
127
|
+
end
|
128
|
+
|
129
|
+
def shared_file_systems
|
130
|
+
@shared_file_systems ||= build_service(:shared_file_systems)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'misty/http/method_builder'
|
2
|
+
require 'misty/http/request'
|
3
|
+
require 'misty/http/direct'
|
4
|
+
|
5
|
+
module Misty
|
6
|
+
module HTTP
|
7
|
+
class Client
|
8
|
+
class InvalidDataError < StandardError; end
|
9
|
+
|
10
|
+
include Misty::HTTP::MethodBuilder
|
11
|
+
include Misty::HTTP::Request
|
12
|
+
include Misty::HTTP::Direct
|
13
|
+
|
14
|
+
INTERFACES = %w{admin public internal}
|
15
|
+
|
16
|
+
attr_reader :microversion
|
17
|
+
|
18
|
+
Options = Struct.new(:base_path, :base_url, :interface, :region_id, :service_names, :ssl_verify_mode, :version)
|
19
|
+
|
20
|
+
def requests
|
21
|
+
list = []
|
22
|
+
self.class.api.each do |_path, verbs|
|
23
|
+
verbs.each do |_verb, requests|
|
24
|
+
list << requests
|
25
|
+
end
|
26
|
+
end
|
27
|
+
list.flatten.sort
|
28
|
+
end
|
29
|
+
|
30
|
+
# Options - Values shown are the default
|
31
|
+
# Base path can be forced (Not recommended, mainly used for test purposes)
|
32
|
+
# :base_path => nil
|
33
|
+
# URL can be forced (Helps when setup is broken)
|
34
|
+
# :base_url => nil
|
35
|
+
# Endpoint type (admin, public or internal)
|
36
|
+
# :interface => "public"
|
37
|
+
# Region ID
|
38
|
+
# :region_id => "regionOne"
|
39
|
+
# Service name
|
40
|
+
# The Service names are pre defined but more can be added using this option.
|
41
|
+
# :service_name
|
42
|
+
# SSL Verify Mode
|
43
|
+
# :ssl_verify_mode => true
|
44
|
+
# (micro)version: Can be numbered (3.1) or by state (CURRENT, LATEST or SUPPORTED)
|
45
|
+
# :version => "CURRENT"
|
46
|
+
def initialize(cloud, options)
|
47
|
+
@cloud = cloud
|
48
|
+
@options = setup(options)
|
49
|
+
@uri = URI.parse(@cloud.auth.get_endpoint(@options.service_names, @options.region_id, @options.interface))
|
50
|
+
@base_path = @options.base_path ? @options.base_path : @uri.path
|
51
|
+
@base_path = @base_path.chomp("/")
|
52
|
+
@http = net_http(@uri)
|
53
|
+
@version = nil
|
54
|
+
@microversion = false
|
55
|
+
end
|
56
|
+
|
57
|
+
# Sub classes to override
|
58
|
+
# When a catalog provides a base path and the Service API definition containts the generic equivalent as prefix
|
59
|
+
# then the preifx is redundant and must be removed from the path.
|
60
|
+
# For example:
|
61
|
+
# Catalog provides "http://192.0.2.21:8004/v1/48985e6b8da145699d411f12a3459fca"
|
62
|
+
# and Service API has "/v1/{tenant_id}/stacks"
|
63
|
+
# then the path prefix is ignored and path is only "/stacks"
|
64
|
+
def self.prefix_path_to_ignore
|
65
|
+
""
|
66
|
+
end
|
67
|
+
|
68
|
+
def headers_default
|
69
|
+
Misty::HEADER_JSON
|
70
|
+
end
|
71
|
+
|
72
|
+
def headers
|
73
|
+
h = headers_default.merge("X-Auth-Token" => "#{@cloud.auth.get_token}")
|
74
|
+
h.merge!(microversion_header) if microversion
|
75
|
+
h
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
def baseclass
|
81
|
+
self.class.to_s.split('::')[-1]
|
82
|
+
end
|
83
|
+
|
84
|
+
def net_http(uri)
|
85
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
86
|
+
http.set_debug_output($stdout) if @cloud.log.level == Logger::DEBUG
|
87
|
+
if uri.scheme == "https"
|
88
|
+
http.use_ssl = true
|
89
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless @options[:ssl_verify_mode]
|
90
|
+
end
|
91
|
+
http
|
92
|
+
end
|
93
|
+
|
94
|
+
def setup(params)
|
95
|
+
options = Options.new()
|
96
|
+
options.base_path = params[:base_path] ? params[:base_path] : nil
|
97
|
+
options.base_url = params[:base_url] ? params[:base_url] : nil
|
98
|
+
options.interface = params[:interface] ? params[:interface] : "public"
|
99
|
+
options.region_id = params[:region_id] ? params[:region_id] : "regionOne"
|
100
|
+
options.service_names = params[:service_name] ? self.class.service_names << params[:service_name] : self.class.service_names
|
101
|
+
options.ssl_verify_mode = params[:ssl_verify_mode] ? params[:ssl_verify_mode] : true
|
102
|
+
options.version = params[:version] ? params[:version] : "CURRENT"
|
103
|
+
|
104
|
+
unless INTERFACES.include?(options.interface)
|
105
|
+
raise InvalidDataError, "Options ':interface'must be one of #{INTERFACES}"
|
106
|
+
end
|
107
|
+
|
108
|
+
unless options.ssl_verify_mode == !!options.ssl_verify_mode
|
109
|
+
raise InvalidDataError, "Options ':ssl_verify_mode' must be a boolean"
|
110
|
+
end
|
111
|
+
options
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Misty
|
2
|
+
module HTTP
|
3
|
+
# Provides methods to submit the current service with a path and override @base_path if needed
|
4
|
+
module Direct
|
5
|
+
def base_set(base_path)
|
6
|
+
base = base_path ? base_path : @base_path
|
7
|
+
end
|
8
|
+
|
9
|
+
def delete(path, base_path = nil)
|
10
|
+
http_delete(base_set(base_path) + path, headers)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(path, base_path = nil)
|
14
|
+
http_get(base_set(base_path) + path, headers)
|
15
|
+
end
|
16
|
+
|
17
|
+
def post(path, data, base_path = nil)
|
18
|
+
http_post(base_set(base_path) + path, headers, data)
|
19
|
+
end
|
20
|
+
|
21
|
+
def put(path, data, base_path = nil)
|
22
|
+
http_put(base_set(base_path) + path, headers, data)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
module Misty
|
2
|
+
module HTTP
|
3
|
+
module MethodBuilder
|
4
|
+
def method_missing(method_name, *args)
|
5
|
+
if method = get_method(method_name)
|
6
|
+
method_call(method, *args)
|
7
|
+
else
|
8
|
+
raise NoMethodError, "API #{baseclass.downcase}: method #{method_name} not implemented!"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def method_call(method, *args)
|
15
|
+
base, path = prefixed_path(method[:path])
|
16
|
+
size_path_parameters = count_path_params(path)
|
17
|
+
path_params = args[0, size_path_parameters]
|
18
|
+
args_left = args - path_params
|
19
|
+
path = inject_elements(path, path_params)
|
20
|
+
final_path = base_filter(base, path)
|
21
|
+
|
22
|
+
case method[:request]
|
23
|
+
when :COPY
|
24
|
+
http_copy(final_path, headers)
|
25
|
+
when :DELETE
|
26
|
+
http_delete(final_path, headers)
|
27
|
+
when :GET
|
28
|
+
final_path << query_param(args_left[0]) if args_left && args_left.size == 1
|
29
|
+
http_get(final_path, headers)
|
30
|
+
when :HEAD
|
31
|
+
http_head(final_path, headers, data)
|
32
|
+
when :POST
|
33
|
+
data = args_left[0] if args_left && args_left.size == 1
|
34
|
+
http_post(final_path, headers, data)
|
35
|
+
when :PUT
|
36
|
+
data = args_left[0] if args_left && args_left.size == 1
|
37
|
+
http_put(final_path, headers, data)
|
38
|
+
when :PATCH
|
39
|
+
data = args_left[0] if args_left && args_left.size == 1
|
40
|
+
http_patch(final_path, headers, data)
|
41
|
+
else
|
42
|
+
raise SyntaxError, "Invalid HTTP request: #{method[:request]}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def base_filter(base, path)
|
47
|
+
return (@base_path + path) if base
|
48
|
+
return path
|
49
|
+
end
|
50
|
+
|
51
|
+
def count_path_params(str)
|
52
|
+
subpath = /(.*)(\{.*\})(.*)/.match(str)
|
53
|
+
return 0 unless subpath
|
54
|
+
return count_path_params(subpath[1]) + 1
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_method(name)
|
58
|
+
self.class.api.each do |path, requests|
|
59
|
+
requests.each do |request, methods_list|
|
60
|
+
if methods_list.include?(name)
|
61
|
+
return {:path => path, :request => request, :name => name}
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
|
68
|
+
def inject_elements(str, args)
|
69
|
+
subpath = /(.*)(\{.*\})(.*)/.match(str)
|
70
|
+
return str unless subpath
|
71
|
+
arg = args.pop
|
72
|
+
raise ArgumentError, "Not enough arguments" unless arg
|
73
|
+
return inject_elements(subpath[1], args) + arg + subpath[3]
|
74
|
+
end
|
75
|
+
|
76
|
+
def prefixed_path(path)
|
77
|
+
unless self.class.prefix_path_to_ignore.empty?
|
78
|
+
if path =~ %r{#{self.class.prefix_path_to_ignore}}
|
79
|
+
return true, path.gsub(self.class.prefix_path_to_ignore, '')
|
80
|
+
else
|
81
|
+
return false, path
|
82
|
+
end
|
83
|
+
end
|
84
|
+
return true, path
|
85
|
+
end
|
86
|
+
|
87
|
+
def query_param(data)
|
88
|
+
if data.is_a? String
|
89
|
+
str = '?'
|
90
|
+
str.force_encoding('ASCII-8BIT')
|
91
|
+
str << data unless data.empty?
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Misty
|
2
|
+
module HTTP
|
3
|
+
module Request
|
4
|
+
def decode?(response)
|
5
|
+
if @cloud.content_type != :json && response.code =~ /2??/ && !response.is_a?(Net::HTTPNoContent) \
|
6
|
+
&& !response.is_a?(Net::HTTPResetContent) && response.header["content-type"] \
|
7
|
+
&& response.header["content-type"].include?("application/json")
|
8
|
+
true
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def http(request)
|
13
|
+
response = @http.request(request)
|
14
|
+
response.body = JSON.load(response.body) if decode?(response)
|
15
|
+
response
|
16
|
+
end
|
17
|
+
|
18
|
+
def http_delete(path, headers)
|
19
|
+
@cloud.log.info(http_to_s(path, headers))
|
20
|
+
request = Net::HTTP::Delete.new(path, headers)
|
21
|
+
http(request)
|
22
|
+
end
|
23
|
+
|
24
|
+
def http_copy(path, headers)
|
25
|
+
@cloud.log.info(http_to_s(path, headers))
|
26
|
+
request = Net::HTTP::Copy.new(path, headers)
|
27
|
+
http(request)
|
28
|
+
end
|
29
|
+
|
30
|
+
def http_get(path, headers)
|
31
|
+
@cloud.log.info(http_to_s(path, headers))
|
32
|
+
request = Net::HTTP::Get.new(path, headers)
|
33
|
+
http(request)
|
34
|
+
end
|
35
|
+
|
36
|
+
def http_head(path, headers)
|
37
|
+
@cloud.log.info(http_to_s(path, headers))
|
38
|
+
request = Net::HTTP::Head.new(path, headers)
|
39
|
+
http(request)
|
40
|
+
end
|
41
|
+
|
42
|
+
def http_options(path, headers)
|
43
|
+
@cloud.log.info(http_to_s(path, headers))
|
44
|
+
request = Net::HTTP::Options.new(path, headers)
|
45
|
+
http(request)
|
46
|
+
end
|
47
|
+
|
48
|
+
def http_patch(path, headers, data)
|
49
|
+
@cloud.log.info(http_to_s(path, headers, data))
|
50
|
+
request = Net::HTTP::Patch.new(path, headers)
|
51
|
+
request.body = Misty.to_json(data)
|
52
|
+
http(request)
|
53
|
+
end
|
54
|
+
|
55
|
+
def http_post(path, headers, data)
|
56
|
+
@cloud.log.info(http_to_s(path, headers, data))
|
57
|
+
request = Net::HTTP::Post.new(path, headers)
|
58
|
+
request.body = Misty.to_json(data)
|
59
|
+
http(request)
|
60
|
+
end
|
61
|
+
|
62
|
+
def http_put(path, headers, data)
|
63
|
+
@cloud.log.info(http_to_s(path, headers, data))
|
64
|
+
request = Net::HTTP::Put.new(path, headers)
|
65
|
+
request.body = Misty.to_json(data)
|
66
|
+
http(request)
|
67
|
+
end
|
68
|
+
|
69
|
+
def http_to_s(path, headers, data = nil)
|
70
|
+
log = "base_url='#{@uri.host}:#{@uri.port}', path='#{path}', header=#{headers}"
|
71
|
+
log << ", data='#{data}'" if data
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|