misty 0.1.0 → 0.3.0
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/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
|