deltacloud-core 0.5.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/NOTICE +1 -1
- data/Rakefile +63 -21
- data/bin/deltacloudd +10 -6
- data/config.ru +62 -6
- data/config/drivers/ec2.yaml +8 -0
- data/config/drivers/fgcp.yaml +13 -0
- data/deltacloud-core.gemspec +10 -2
- data/lib/cimi/collections.rb +58 -0
- data/lib/cimi/collections/address_templates.rb +49 -0
- data/lib/cimi/collections/addresses.rb +74 -0
- data/lib/cimi/collections/cloud_entry_point.rb +37 -0
- data/lib/{deltacloud/helpers/conversion_helper.rb → cimi/collections/entity_metadata.rb} +24 -16
- data/lib/cimi/collections/machine_admins.rb +74 -0
- data/lib/cimi/collections/machine_configurations.rb +49 -0
- data/lib/cimi/collections/machine_images.rb +50 -0
- data/lib/cimi/collections/machines.rb +157 -0
- data/lib/cimi/collections/network_configurations.rb +47 -0
- data/lib/cimi/collections/network_templates.rb +48 -0
- data/lib/cimi/collections/networks.rb +125 -0
- data/lib/cimi/collections/routing_group_templates.rb +47 -0
- data/lib/cimi/collections/routing_groups.rb +48 -0
- data/lib/cimi/collections/volume_configurations.rb +48 -0
- data/lib/cimi/collections/volume_images.rb +50 -0
- data/lib/cimi/collections/volumes.rb +80 -0
- data/lib/cimi/collections/vsp_configurations.rb +48 -0
- data/lib/cimi/collections/vsp_templates.rb +50 -0
- data/lib/cimi/collections/vsps.rb +108 -0
- data/lib/cimi/dependencies.rb +1 -0
- data/lib/cimi/helpers.rb +116 -0
- data/lib/cimi/helpers/cimi_helper.rb +6 -2
- data/lib/cimi/models.rb +72 -0
- data/lib/cimi/{model → models}/action.rb +1 -1
- data/lib/cimi/models/address.rb +72 -0
- data/lib/cimi/models/address_collection.rb +34 -0
- data/lib/cimi/models/address_template.rb +54 -0
- data/lib/cimi/models/address_template_collection.rb +34 -0
- data/lib/cimi/{model → models}/base.rb +2 -2
- data/lib/cimi/{model → models}/cloud_entry_point.rb +3 -5
- data/lib/cimi/{model → models}/entity_metadata.rb +7 -6
- data/lib/cimi/{model → models}/entity_metadata_collection.rb +2 -2
- data/lib/cimi/{model → models}/errors.rb +8 -0
- data/lib/cimi/{model → models}/machine.rb +10 -10
- data/lib/cimi/{model → models}/machine_admin.rb +1 -1
- data/lib/cimi/{model → models}/machine_admin_collection.rb +2 -2
- data/lib/cimi/{model → models}/machine_collection.rb +2 -2
- data/lib/cimi/{model → models}/machine_configuration.rb +9 -6
- data/lib/cimi/{model → models}/machine_configuration_collection.rb +2 -2
- data/lib/cimi/{model → models}/machine_image.rb +1 -1
- data/lib/cimi/{model → models}/machine_image_collection.rb +2 -2
- data/lib/cimi/{model → models}/machine_template.rb +0 -0
- data/lib/cimi/{model → models}/machine_template_collection.rb +2 -2
- data/lib/cimi/models/network.rb +109 -0
- data/lib/cimi/{model → models}/network_collection.rb +2 -2
- data/lib/cimi/{model → models}/network_configuration.rb +3 -4
- data/lib/cimi/{model → models}/network_configuration_collection.rb +2 -2
- data/lib/cimi/models/network_template.rb +36 -0
- data/lib/cimi/models/network_template_collection.rb +35 -0
- data/lib/cimi/models/routing_group.rb +34 -0
- data/lib/cimi/models/routing_group_collection.rb +34 -0
- data/lib/cimi/models/routing_group_template.rb +34 -0
- data/lib/cimi/models/routing_group_template_collection.rb +35 -0
- data/lib/cimi/{model → models}/schema.rb +0 -0
- data/lib/cimi/{model → models}/volume.rb +4 -4
- data/lib/cimi/{model → models}/volume_collection.rb +2 -2
- data/lib/cimi/{model → models}/volume_configuration.rb +1 -1
- data/lib/cimi/{model → models}/volume_configuration_collection.rb +2 -2
- data/lib/cimi/{model → models}/volume_image.rb +1 -1
- data/lib/cimi/{model → models}/volume_image_collection.rb +2 -2
- data/lib/cimi/{model → models}/volume_template.rb +0 -0
- data/lib/cimi/{model → models}/volume_template_collection.rb +2 -2
- data/lib/cimi/models/vsp.rb +102 -0
- data/lib/cimi/models/vsp_collection.rb +34 -0
- data/lib/cimi/models/vsp_configuration.rb +40 -0
- data/lib/cimi/models/vsp_configuration_collection.rb +34 -0
- data/lib/cimi/models/vsp_template.rb +34 -0
- data/lib/cimi/models/vsp_template_collection.rb +34 -0
- data/lib/cimi/server.rb +27 -549
- data/lib/deltacloud/api.rb +79 -0
- data/lib/deltacloud/collections.rb +54 -0
- data/lib/deltacloud/collections/addresses.rb +91 -0
- data/lib/deltacloud/collections/buckets.rb +273 -0
- data/lib/deltacloud/collections/drivers.rb +51 -0
- data/lib/deltacloud/collections/firewalls.rb +116 -0
- data/lib/deltacloud/collections/hardware_profiles.rb +29 -0
- data/lib/deltacloud/collections/images.rb +73 -0
- data/lib/deltacloud/collections/instance_states.rb +59 -0
- data/lib/deltacloud/collections/instances.rb +113 -0
- data/lib/deltacloud/collections/keys.rb +61 -0
- data/lib/deltacloud/collections/load_balancers.rb +102 -0
- data/lib/deltacloud/collections/metrics.rb +28 -0
- data/lib/deltacloud/collections/realms.rb +28 -0
- data/lib/deltacloud/collections/storage_snapshots.rb +51 -0
- data/lib/deltacloud/collections/storage_volumes.rb +99 -0
- data/lib/deltacloud/core_ext.rb +14 -6
- data/lib/deltacloud/core_ext/string.rb +17 -5
- data/lib/deltacloud/drivers.rb +6 -42
- data/lib/deltacloud/drivers/azure/azure_driver.rb +0 -4
- data/lib/deltacloud/{base_driver → drivers}/base_driver.rb +56 -18
- data/lib/deltacloud/drivers/condor/condor_driver.rb +1 -8
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +142 -33
- data/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb +2 -6
- data/lib/deltacloud/{base_driver → drivers}/exceptions.rb +25 -2
- data/lib/deltacloud/drivers/features.rb +154 -0
- data/lib/deltacloud/drivers/fgcp/fgcp_client.rb +387 -0
- data/lib/deltacloud/drivers/fgcp/fgcp_driver.rb +1435 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +8 -11
- data/lib/deltacloud/drivers/google/google_driver.rb +2 -5
- data/lib/deltacloud/drivers/mock/data/keys/test-key.yml +28 -0
- data/lib/deltacloud/drivers/mock/mock_client.rb +2 -2
- data/lib/deltacloud/drivers/mock/mock_driver.rb +58 -40
- data/lib/deltacloud/drivers/mock/mock_driver_cimi_methods.rb +145 -0
- data/lib/deltacloud/drivers/opennebula/cloud_client.rb +107 -73
- data/lib/deltacloud/drivers/opennebula/occi_client.rb +285 -145
- data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +189 -126
- data/lib/deltacloud/drivers/openstack/openstack_driver.rb +427 -8
- data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +7 -9
- data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +48 -66
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb +44 -51
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +7 -8
- data/lib/deltacloud/drivers/sbc/sbc_client.rb +1 -1
- data/lib/deltacloud/drivers/sbc/sbc_driver.rb +3 -3
- data/lib/deltacloud/drivers/terremark/terremark_driver.rb +8 -8
- data/lib/deltacloud/drivers/vsphere/vsphere_driver.rb +39 -13
- data/lib/deltacloud/drivers/vsphere/vsphere_filemanager.rb +1 -0
- data/lib/deltacloud/helpers.rb +79 -7
- data/lib/{sinatra/lazy_auth.rb → deltacloud/helpers/auth_helper.rb} +5 -9
- data/lib/deltacloud/helpers/{blob_stream.rb → blob_stream_helper.rb} +7 -7
- data/lib/deltacloud/helpers/deltacloud_helper.rb +286 -0
- data/lib/deltacloud/helpers/driver_helper.rb +58 -0
- data/lib/deltacloud/helpers/rabbit_helper.rb +34 -0
- data/lib/{sinatra/url_for.rb → deltacloud/helpers/url_helper.rb} +31 -9
- data/lib/deltacloud/models.rb +19 -17
- data/lib/deltacloud/models/bucket.rb +4 -0
- data/lib/deltacloud/{hardware_profile.rb → models/hardware_profile.rb} +4 -2
- data/lib/deltacloud/models/image.rb +1 -0
- data/lib/deltacloud/models/instance.rb +4 -2
- data/lib/deltacloud/models/instance_address.rb +4 -0
- data/lib/deltacloud/models/key.rb +4 -0
- data/lib/deltacloud/models/metric.rb +40 -0
- data/lib/deltacloud/{state_machine.rb → models/state_machine.rb} +18 -1
- data/lib/deltacloud/server.rb +41 -1222
- data/lib/deltacloud_rack.rb +79 -0
- data/lib/{cimi/model/network_template.rb → ec2/helpers.rb} +7 -10
- data/lib/{deltacloud/backend_capability.rb → ec2/helpers/errors.rb} +24 -29
- data/lib/ec2/helpers/result.rb +31 -0
- data/lib/ec2/query_parser.rb +152 -0
- data/lib/ec2/server.rb +70 -0
- data/lib/{deltacloud.rb → sinatra.rb} +7 -12
- data/lib/sinatra/rack_accept.rb +13 -7
- data/lib/sinatra/rack_driver_select.rb +1 -1
- data/lib/sinatra/rack_matrix_params.rb +1 -3
- data/public/images/metric.png +0 -0
- data/public/javascripts/jquery.mobile-1.0.1.min.js +177 -0
- data/public/stylesheets/jquery.mobile-1.0.1.min.css +2 -0
- data/public/stylesheets/new.css +10 -0
- data/support/fedora/deltacloud-core.spec +1 -1
- data/tests/api/common.rb +1 -0
- data/tests/api/driver_test.rb +79 -0
- data/tests/api/library_test.rb +48 -0
- data/tests/cimi/features/step_definitions/common_steps.rb +2 -2
- data/tests/cimi/features/step_definitions/machines_steps.rb +5 -4
- data/tests/cimi/features/step_definitions/volumes_steps.rb +8 -8
- data/tests/cimi/features/support/env.rb +33 -11
- data/tests/common.rb +7 -8
- data/tests/drivers/ec2/api_test.rb +19 -0
- data/tests/drivers/ec2/common.rb +23 -0
- data/tests/drivers/ec2/drivers_test.rb +120 -0
- data/tests/drivers/ec2/hardware_profiles_test.rb +224 -0
- data/tests/drivers/ec2/images_test.rb +230 -0
- data/tests/drivers/ec2/instances_test.rb +356 -0
- data/tests/drivers/ec2/keys_test.rb +181 -0
- data/tests/drivers/ec2/realms_test.rb +146 -0
- data/tests/drivers/fgcp/api_test.rb +47 -0
- data/tests/drivers/fgcp/hardware_profiles_test.rb +54 -0
- data/tests/drivers/fgcp/realms_test.rb +42 -0
- data/tests/drivers/{rackspace → fgcp}/setup.rb +5 -6
- data/tests/drivers/google/api_test.rb +10 -26
- data/tests/drivers/google/buckets_test.rb +79 -95
- data/tests/drivers/google/common.rb +54 -0
- data/tests/drivers/mock/api_test.rb +4 -127
- data/tests/drivers/mock/buckets_test.rb +195 -0
- data/tests/drivers/mock/common.rb +7 -0
- data/tests/drivers/mock/drivers_test.rb +123 -0
- data/tests/drivers/mock/hardware_profiles_test.rb +190 -100
- data/tests/drivers/mock/images_test.rb +162 -103
- data/tests/drivers/mock/instances_test.rb +310 -220
- data/tests/drivers/mock/keys_test.rb +161 -0
- data/tests/drivers/mock/realms_test.rb +109 -70
- data/tests/drivers/mock/storage_snapshots_test.rb +114 -0
- data/tests/drivers/mock/storage_volumes_test.rb +122 -0
- data/tests/drivers/openstack/api_test.rb +8 -3
- data/tests/drivers/openstack/common.rb +21 -0
- data/tests/drivers/openstack/hardware_profiles_test.rb +20 -9
- data/tests/drivers/openstack/images_test.rb +11 -5
- data/tests/drivers/openstack/instances_test.rb +61 -16
- data/tests/drivers/openstack/realms_test.rb +11 -7
- data/tests/drivers/rackspace/api_test.rb +7 -2
- data/tests/drivers/rackspace/buckets_test.rb +7 -2
- data/tests/drivers/rackspace/common.rb +16 -0
- data/tests/drivers/rackspace/hardware_profiles_test.rb +7 -2
- data/tests/drivers/rackspace/images_test.rb +7 -2
- data/tests/drivers/rackspace/instances_test.rb +10 -5
- data/tests/drivers/rackspace/realms_test.rb +7 -2
- data/tests/drivers/rhevm/api_test.rb +12 -6
- data/tests/drivers/rhevm/{setup.rb → common.rb} +8 -1
- data/tests/drivers/rhevm/hardware_profiles_test.rb +7 -2
- data/tests/drivers/rhevm/images_test.rb +8 -2
- data/tests/drivers/rhevm/instances_test.rb +7 -2
- data/tests/drivers/rhevm/realms_test.rb +7 -2
- data/tests/minitest_common.rb +58 -0
- data/tests/minitest_common_api_test.rb +115 -0
- data/views/addresses/associate.html.haml +1 -1
- data/views/addresses/index.html.haml +1 -1
- data/views/addresses/show.html.haml +2 -3
- data/views/api/show.html.haml +22 -9
- data/views/api/show.xml.haml +8 -7
- data/views/blobs/show.xml.haml +7 -4
- data/views/buckets/new.html.haml +2 -2
- data/views/cimi/errors/401.xml.haml +1 -1
- data/views/error.html.haml +3 -3
- data/views/errors/400.html.haml +1 -1
- data/views/errors/400.xml.haml +1 -2
- data/views/errors/401.html.haml +8 -7
- data/views/errors/401.xml.haml +1 -1
- data/views/errors/404.xml.haml +1 -0
- data/views/errors/500.xml.haml +4 -2
- data/views/{cimi/errors/403.html.haml → errors/501.html.haml} +4 -2
- data/views/errors/501.xml.haml +1 -0
- data/views/errors/502.xml.haml +1 -7
- data/views/{cimi/errors/500.html.haml → errors/504.html.haml} +0 -0
- data/views/errors/504.xml.haml +1 -0
- data/views/firewalls/new.html.haml +2 -2
- data/views/firewalls/new_rule.html.haml +1 -1
- data/views/firewalls/show.html.haml +1 -1
- data/views/hardware_profiles/index.html.haml +3 -1
- data/views/hardware_profiles/index.xml.haml +2 -2
- data/views/hardware_profiles/show.html.haml +3 -3
- data/views/hardware_profiles/show.xml.haml +3 -3
- data/views/images/show.html.haml +5 -0
- data/views/images/show.xml.haml +6 -1
- data/views/instance_states/show.html.haml +1 -1
- data/views/instances/index.html.haml +1 -1
- data/views/instances/new.html.haml +54 -39
- data/views/instances/run_command.html.haml +24 -15
- data/views/instances/show.html.haml +7 -3
- data/views/instances/show.xml.haml +2 -2
- data/views/keys/show.xml.haml +1 -0
- data/views/layout.html.haml +5 -9
- data/views/load_balancers/show.html.haml +12 -6
- data/views/metrics/index.html.haml +13 -0
- data/views/metrics/index.xml.haml +5 -0
- data/views/metrics/show.html.haml +23 -0
- data/views/metrics/show.xml.haml +9 -0
- data/views/realms/show.xml.haml +2 -1
- data/views/root/index.html.haml +1 -1
- data/views/storage_snapshots/show.html.haml +1 -1
- data/views/storage_snapshots/show.xml.haml +1 -0
- data/views/storage_volumes/attach.html.haml +1 -2
- data/views/storage_volumes/index.html.haml +1 -1
- data/views/storage_volumes/new.html.haml +22 -16
- data/views/storage_volumes/show.html.haml +10 -4
- data/views/storage_volumes/show.xml.haml +3 -4
- metadata +547 -519
- data/DISCLAIMER +0 -8
- data/lib/cimi/model.rb +0 -52
- data/lib/cimi/model/network.rb +0 -69
- data/lib/deltacloud/base_driver.rb +0 -18
- data/lib/deltacloud/base_driver/features.rb +0 -262
- data/lib/deltacloud/base_driver/mock_driver.rb +0 -78
- data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +0 -186
- data/lib/deltacloud/drivers/rhevm/rhevm_client.rb +0 -521
- data/lib/deltacloud/helpers/application_helper.rb +0 -267
- data/lib/deltacloud/helpers/hardware_profiles_helper.rb +0 -50
- data/lib/deltacloud/helpers/json_helper.rb +0 -31
- data/lib/deltacloud/method_serializer.rb +0 -83
- data/lib/deltacloud/validation.rb +0 -107
- data/lib/sinatra/rabbit.rb +0 -441
- data/lib/sinatra/rack_runtime.rb +0 -47
- data/lib/sinatra/rack_syslog.rb +0 -86
- data/lib/sinatra/sinatra_verbose.rb +0 -73
- data/lib/sinatra/static_assets.rb +0 -99
- data/public/javascripts/jquery.mobile-1.0rc1.min.js +0 -170
- data/public/stylesheets/jquery.mobile-1.0rc1.min.css +0 -12
- data/tests/drivers/google/setup.rb +0 -38
- data/tests/drivers/mock/instance_states_test.rb +0 -71
- data/tests/drivers/mock/setup.rb +0 -3
- data/tests/drivers/mock/url_for_test.rb +0 -67
- data/tests/drivers/openstack/setup.rb +0 -20
- data/views/cimi/errors/400.html.haml +0 -41
- data/views/cimi/errors/401.html.haml +0 -41
- data/views/cimi/errors/404.html.haml +0 -29
- data/views/cimi/errors/405.html.haml +0 -29
- data/views/cimi/errors/502.html.haml +0 -43
- data/views/cimi/errors/backend_capability_failure.html.haml +0 -29
@@ -19,11 +19,7 @@ require 'deltacloud/drivers/ec2/ec2_driver.rb'
|
|
19
19
|
module Deltacloud
|
20
20
|
module Drivers
|
21
21
|
module Eucalyptus
|
22
|
-
class EucalyptusDriver <
|
23
|
-
|
24
|
-
def supported_collections
|
25
|
-
DEFAULT_COLLECTIONS + [ :keys, :buckets, :addresses, :firewalls ]
|
26
|
-
end
|
22
|
+
class EucalyptusDriver < Ec2::Ec2Driver
|
27
23
|
|
28
24
|
feature :instances, :user_data
|
29
25
|
feature :instances, :authentication_key
|
@@ -67,7 +63,7 @@ module Deltacloud
|
|
67
63
|
end
|
68
64
|
|
69
65
|
def self.instance_state_machine
|
70
|
-
|
66
|
+
Ec2::Ec2Driver.instance_state_machine
|
71
67
|
end
|
72
68
|
|
73
69
|
def instance_state_machine
|
@@ -72,6 +72,20 @@ module Deltacloud
|
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
75
|
+
class ProviderTimeout < DeltacloudException
|
76
|
+
def initialize(e, message)
|
77
|
+
message ||= e.message
|
78
|
+
super(504, e.class.name, message, e.backtrace)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
class NotImplemented < DeltacloudException
|
83
|
+
def initialize(e, message)
|
84
|
+
message ||= e.message
|
85
|
+
super(501, e.class.name, message, e.backtrace)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
75
89
|
class ObjectNotFound < DeltacloudException
|
76
90
|
def initialize(e, message)
|
77
91
|
message ||= e.message
|
@@ -79,6 +93,12 @@ module Deltacloud
|
|
79
93
|
end
|
80
94
|
end
|
81
95
|
|
96
|
+
class NotSupported < DeltacloudException
|
97
|
+
def initialize(message)
|
98
|
+
super(501, self.class.name, message, self.backtrace)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
82
102
|
class ExceptionDef
|
83
103
|
attr_accessor :status
|
84
104
|
attr_accessor :message
|
@@ -121,7 +141,9 @@ module Deltacloud
|
|
121
141
|
when 405 then Deltacloud::ExceptionHandler::MethodNotAllowed.new(e, @message)
|
122
142
|
when 400 then Deltacloud::ExceptionHandler::ValidationFailure.new(e, @message)
|
123
143
|
when 500 then Deltacloud::ExceptionHandler::BackendError.new(e, @message)
|
144
|
+
when 501 then Deltacloud::ExceptionHandler::NotImplemented.new(e, @message)
|
124
145
|
when 502 then Deltacloud::ExceptionHandler::ProviderError.new(e, @message)
|
146
|
+
when 504 then Deltacloud::ExceptionHandler::ProviderTimeout.new(e, @message)
|
125
147
|
end
|
126
148
|
end
|
127
149
|
|
@@ -153,9 +175,10 @@ module Deltacloud
|
|
153
175
|
report_method = $stderr.respond_to?(:err) ? :err : :puts
|
154
176
|
Deltacloud::ExceptionHandler::exceptions.each do |exdef|
|
155
177
|
if exdef.match?($!)
|
156
|
-
$stderr.send(report_method, "#{[$!.class.to_s, $!.message].join(':')}\n#{$!.backtrace.join("\n")}")
|
157
178
|
new_exception = exdef.handler($!)
|
158
|
-
|
179
|
+
m = new_exception.message.nil? ? $!.message : new_exception.message
|
180
|
+
$stderr.send(report_method, "#{[$!.class.to_s, m].join(':')}\n#{$!.backtrace[0..10].join("\n")}")
|
181
|
+
raise exdef.handler($!) unless new_exception.nil?
|
159
182
|
end
|
160
183
|
end
|
161
184
|
$stderr.send(report_method, "[NO HANDLED] #{[$!.class.to_s, $!.message].join(': ')}\n#{$!.backtrace.join("\n")}")
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
2
|
+
# contributor license agreements. See the NOTICE file distributed with
|
3
|
+
# this work for additional information regarding copyright ownership. The
|
4
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
5
|
+
# "License"); you may not use this file except in compliance with the
|
6
|
+
# License. You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations
|
14
|
+
# under the License.
|
15
|
+
|
16
|
+
module Deltacloud
|
17
|
+
|
18
|
+
module Features
|
19
|
+
|
20
|
+
def self.included(k)
|
21
|
+
current_features = features
|
22
|
+
k.instance_eval do
|
23
|
+
features(¤t_features)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.features(&block)
|
28
|
+
block_given? ? @features = block : @features || Proc.new{}
|
29
|
+
end
|
30
|
+
|
31
|
+
features do
|
32
|
+
|
33
|
+
feature :owner_id, :for => :images do
|
34
|
+
description "Filter images using owner id"
|
35
|
+
operation :index do
|
36
|
+
param :owner_id, :string, :optional, [], "Owner ID"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
feature :image_name, :for => :images do
|
41
|
+
description "Allow specifying user name for created image"
|
42
|
+
operation :create do
|
43
|
+
param :name, :string, :optional, [], "Image name"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
feature :image_description, :for => :images do
|
48
|
+
description "Allow specifying user description for created image"
|
49
|
+
operation :create do
|
50
|
+
param :description, :string, :optional, [], "Image description"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
feature :bucket_location, :for => :buckets do
|
55
|
+
description "Take extra location parameter for Bucket creation (e.g. S3, 'eu' or 'us-west-1')"
|
56
|
+
operation :create do
|
57
|
+
param :location, :string, :optional
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
feature :metrics, :for => :instances do
|
62
|
+
description "Enable more detailed monitoring and metrics reporting for the instance"
|
63
|
+
operation :create do
|
64
|
+
param :metrics, :string, :optional
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
feature :user_name, :for => :instances do
|
69
|
+
description "Allow to set user-defined name for the instance"
|
70
|
+
operation :create do
|
71
|
+
param :name, :string, :optional
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
feature :user_data, :for => :instances do
|
76
|
+
description "Allow to pass user-defined data into the instance"
|
77
|
+
operation :create do
|
78
|
+
param :user_data, :string, :optional
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
feature :user_files, :for => :instances do
|
83
|
+
description "Allow to pass user files into the instance"
|
84
|
+
operation :create do
|
85
|
+
param :user_files, :string, :optional
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
feature :user_iso, :for => :instances do
|
90
|
+
description "Base64 encoded gzipped ISO file will be accessible as CD-ROM drive in instance"
|
91
|
+
operation :create do
|
92
|
+
param :user_iso, :string, :optional
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
feature :firewalls, :for => :instances do
|
97
|
+
description "Put instance in one or more firewalls (security groups) on launch"
|
98
|
+
operation :create do
|
99
|
+
param :firewalls, :array, :optional, nil, "Array of firewall ID strings"
|
100
|
+
"Array of firewall (security group) id"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
feature :authentication_key, :for => :instances do
|
105
|
+
operation :create do
|
106
|
+
param :keyname, :string, :optional, [], "Key authentification method"
|
107
|
+
end
|
108
|
+
operation :show do
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
feature :authentication_password, :for => :instances do
|
113
|
+
operation :create do
|
114
|
+
param :password, :string, :optional
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
feature :hardware_profiles, :for => :instances do
|
119
|
+
description "Size instances according to changes to a hardware profile"
|
120
|
+
# The parameters are filled in from the hardware profiles
|
121
|
+
end
|
122
|
+
|
123
|
+
feature :register_to_load_balancer, :for => :instances do
|
124
|
+
description "Register instance to load balancer"
|
125
|
+
operation :create do
|
126
|
+
param :load_balancer_id, :string, :optional
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
feature :instance_count, :for => :instances do
|
131
|
+
description "Number of instances to be launch with at once"
|
132
|
+
operation :create do
|
133
|
+
param :instance_count, :string, :optional
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
feature :attach_snapshot, :for => :instances do
|
138
|
+
description "Attach an snapshot to instance on create"
|
139
|
+
operation :create do
|
140
|
+
param :snapshot_id, :string, :optional
|
141
|
+
param :device_name, :string, :optional
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
feature :sandboxing, :for => :instances do
|
146
|
+
description "Allow lanuching sandbox images"
|
147
|
+
operation :create do
|
148
|
+
param :sandbox, :string, :optional
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,387 @@
|
|
1
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
2
|
+
# contributor license agreements. See the NOTICE file distributed with
|
3
|
+
# this work for additional information regarding copyright ownership. The
|
4
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
5
|
+
# "License"); you may not use this file except in compliance with the
|
6
|
+
# License. You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
12
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
13
|
+
# License for the specific language governing permissions and limitations
|
14
|
+
# under the License.
|
15
|
+
#
|
16
|
+
# Author: Dies Koper <diesk@fast.au.fujitsu.com>
|
17
|
+
|
18
|
+
require 'net/http'
|
19
|
+
require 'net/https'
|
20
|
+
require 'rubygems'
|
21
|
+
require 'xmlsimple'
|
22
|
+
require 'base64'
|
23
|
+
require 'cgi'
|
24
|
+
require 'uri'
|
25
|
+
|
26
|
+
module Deltacloud
|
27
|
+
module Drivers
|
28
|
+
module Fgcp
|
29
|
+
|
30
|
+
class FgcpClient
|
31
|
+
|
32
|
+
def initialize(cert, key, endpoint = nil, version = '2011-01-31', locale = 'en')
|
33
|
+
@version = version
|
34
|
+
@locale = locale
|
35
|
+
cert.subject.to_s =~ /\b[Cc]=(\w\w)\b/
|
36
|
+
country = $1.downcase
|
37
|
+
endpoint = Deltacloud::Drivers::driver_config[:fgcp][:entrypoints]['default'][country] unless endpoint
|
38
|
+
raise "API endpoint not found for region #{country}" if endpoint.nil?
|
39
|
+
|
40
|
+
#proxy settings:
|
41
|
+
http_proxy = ENV['http_proxy']
|
42
|
+
proxy_uri = URI.parse(http_proxy) if http_proxy
|
43
|
+
|
44
|
+
if proxy_uri
|
45
|
+
proxy_addr = proxy_uri.host
|
46
|
+
proxy_port = proxy_uri.port
|
47
|
+
proxy_user = proxy_uri.user
|
48
|
+
proxy_pass = proxy_uri.password
|
49
|
+
end
|
50
|
+
|
51
|
+
@uri = URI.parse(endpoint)
|
52
|
+
@headers = {'Accept' => 'text/xml', 'User-Agent' => 'OViSS-API-CLIENT'}
|
53
|
+
|
54
|
+
@service = Net::HTTP::Proxy(proxy_addr, proxy_port, proxy_user, proxy_pass).new(@uri.host, @uri.port)
|
55
|
+
@service.set_debug_output $stderr if cert.subject.to_s =~ /diesk/ # TODO: use a proper debug mode flag
|
56
|
+
|
57
|
+
# configure client authentication
|
58
|
+
@service.use_ssl = (@uri.scheme == 'https')
|
59
|
+
@service.key = key
|
60
|
+
@service.cert = cert
|
61
|
+
|
62
|
+
# configure server authentication (peer verification)
|
63
|
+
ca_certs = ENV['FGCP_CA_CERTS'] # e.g. '/etc/ssl/certs/ca-bundle.crt'
|
64
|
+
@service.ca_file = ca_certs if ca_certs and File.file?(ca_certs)
|
65
|
+
@service.ca_path = ca_certs if ca_certs and File.directory?(ca_certs)
|
66
|
+
@service.verify_mode = (@service.ca_file or @service.ca_path) ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE
|
67
|
+
end
|
68
|
+
|
69
|
+
######################################################################
|
70
|
+
# API methods
|
71
|
+
#####################################################################
|
72
|
+
|
73
|
+
def list_server_types
|
74
|
+
#diskImageId is mandatory but value seems to be ignored
|
75
|
+
request('ListServerType', {'diskImageId' => 'dummy'})
|
76
|
+
end
|
77
|
+
|
78
|
+
def list_vsys
|
79
|
+
request('ListVSYS')
|
80
|
+
end
|
81
|
+
|
82
|
+
def get_vsys_attributes(vsys_id)
|
83
|
+
request('GetVSYSAttributes', {'vsysId' => vsys_id})
|
84
|
+
end
|
85
|
+
|
86
|
+
def get_vsys_configuration(vsys_id)
|
87
|
+
request('GetVSYSConfiguration', {'vsysId' => vsys_id})
|
88
|
+
end
|
89
|
+
|
90
|
+
def start_vserver(vserver_id)
|
91
|
+
request('StartVServer', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id})
|
92
|
+
end
|
93
|
+
|
94
|
+
def stop_vserver(vserver_id, force=false)
|
95
|
+
request('StopVServer', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id, 'force' => force})
|
96
|
+
end
|
97
|
+
|
98
|
+
def create_vserver(vserver_name, vserver_type, disk_image_id, network_id)
|
99
|
+
request('CreateVServer', {
|
100
|
+
'vsysId' => extract_vsys_id(network_id),
|
101
|
+
'vserverName' => vserver_name,
|
102
|
+
'vserverType' => vserver_type,
|
103
|
+
'diskImageId' => disk_image_id,
|
104
|
+
'networkId' => network_id})
|
105
|
+
end
|
106
|
+
|
107
|
+
def destroy_vserver(vserver_id)
|
108
|
+
request('DestroyVServer', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id})
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_vserver_status(vserver_id)
|
112
|
+
request('GetVServerStatus', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id})
|
113
|
+
end
|
114
|
+
|
115
|
+
def get_vserver_initial_password(vserver_id)
|
116
|
+
request('GetVServerInitialPassword', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id})
|
117
|
+
end
|
118
|
+
|
119
|
+
def get_vserver_attributes(vserver_id)
|
120
|
+
request('GetVServerAttributes', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id})
|
121
|
+
end
|
122
|
+
|
123
|
+
def get_vserver_configuration(vserver_id)
|
124
|
+
request('GetVServerConfiguration', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id})
|
125
|
+
end
|
126
|
+
|
127
|
+
def list_disk_images(server_category=nil, vsys_descriptor_id=nil)
|
128
|
+
params = {}
|
129
|
+
params.merge! 'serverCategory' => server_category if server_category
|
130
|
+
params.merge! 'vsysDescriptorId' => vsys_descriptor_id if vsys_descriptor_id
|
131
|
+
|
132
|
+
request('ListDiskImage', params)
|
133
|
+
end
|
134
|
+
|
135
|
+
def register_private_disk_image(vserver_id, name, description)
|
136
|
+
#TODO: support different attributes for different locales?
|
137
|
+
image_descriptor = <<-"eoidxml"
|
138
|
+
<?xml version="1.0" encoding ="UTF-8"?>
|
139
|
+
<Request>
|
140
|
+
<vserverId>#{vserver_id}</vserverId>
|
141
|
+
<locales>
|
142
|
+
<locale>
|
143
|
+
<lcid>en</lcid>
|
144
|
+
<name>#{name}</name>
|
145
|
+
<description>#{description}</description>
|
146
|
+
</locale>
|
147
|
+
<locale>
|
148
|
+
<lcid>jp</lcid>
|
149
|
+
<name>#{name}</name>
|
150
|
+
<description>#{description}</description>
|
151
|
+
</locale>
|
152
|
+
</locales>
|
153
|
+
</Request>
|
154
|
+
eoidxml
|
155
|
+
request('RegisterPrivateDiskImage', nil, image_descriptor, 'diskImageXMLFilePath')
|
156
|
+
end
|
157
|
+
|
158
|
+
def unregister_disk_image(disk_image_id)
|
159
|
+
request('UnregisterDiskImage', {'diskImageId' => disk_image_id})
|
160
|
+
end
|
161
|
+
|
162
|
+
def list_efm(vsys_id, efm_type)
|
163
|
+
request('ListEFM', {'vsysId' => vsys_id, 'efmType' => efm_type})
|
164
|
+
end
|
165
|
+
|
166
|
+
def start_efm(efm_id)
|
167
|
+
request('StartEFM', {'vsysId' => extract_vsys_id(efm_id), 'efmId' => efm_id})
|
168
|
+
end
|
169
|
+
|
170
|
+
def stop_efm(efm_id)
|
171
|
+
request('StopEFM', {'vsysId' => extract_vsys_id(efm_id), 'efmId' => efm_id})
|
172
|
+
end
|
173
|
+
|
174
|
+
def create_efm(efm_type, efm_name, network_id)
|
175
|
+
request('CreateEFM', {
|
176
|
+
'vsysId' => extract_vsys_id(network_id),
|
177
|
+
'efmType' => efm_type,
|
178
|
+
'efmName' => efm_name,
|
179
|
+
'networkId' => network_id}
|
180
|
+
)
|
181
|
+
end
|
182
|
+
|
183
|
+
def destroy_efm(efm_id)
|
184
|
+
request('DestroyEFM', {'vsysId' => extract_vsys_id(efm_id), 'efmId' => efm_id})
|
185
|
+
end
|
186
|
+
|
187
|
+
def get_efm_status(efm_id)
|
188
|
+
request('GetEFMStatus', {'vsysId' => extract_vsys_id(efm_id), 'efmId' => efm_id})
|
189
|
+
end
|
190
|
+
|
191
|
+
def get_efm_configuration(efm_id, configuration_name, configuration_xml=nil)
|
192
|
+
request('GetEFMConfiguration',
|
193
|
+
{
|
194
|
+
'vsysId' => extract_vsys_id(efm_id),
|
195
|
+
'efmId' => efm_id,
|
196
|
+
'configurationName' => configuration_name
|
197
|
+
},
|
198
|
+
configuration_xml,
|
199
|
+
'configurationXMLFilePath'
|
200
|
+
)
|
201
|
+
end
|
202
|
+
|
203
|
+
def update_efm_configuration(efm_id, configuration_name, configuration_xml=nil)
|
204
|
+
request('UpdateEFMConfiguration',
|
205
|
+
{
|
206
|
+
'vsysId' => extract_vsys_id(efm_id),
|
207
|
+
'efmId' => efm_id,
|
208
|
+
'configurationName' => configuration_name
|
209
|
+
},
|
210
|
+
configuration_xml,
|
211
|
+
'configurationXMLFilePath'
|
212
|
+
)
|
213
|
+
end
|
214
|
+
|
215
|
+
def list_vdisk(vsys_id)
|
216
|
+
request('ListVDisk', {'vsysId' => vsys_id})
|
217
|
+
end
|
218
|
+
|
219
|
+
def get_vdisk_status(vdisk_id)
|
220
|
+
request('GetVDiskStatus', {'vsysId' => extract_vsys_id(vdisk_id), 'vdiskId' => vdisk_id})
|
221
|
+
end
|
222
|
+
|
223
|
+
def get_vdisk_attributes(vdisk_id)
|
224
|
+
request('GetVDiskAttributes', {'vsysId' => extract_vsys_id(vdisk_id), 'vdiskId' => vdisk_id})
|
225
|
+
end
|
226
|
+
|
227
|
+
def create_vdisk(vsys_id, vdisk_name, size)
|
228
|
+
request('CreateVDisk', {'vsysId' => vsys_id, 'vdiskName' => vdisk_name, 'size' => size})
|
229
|
+
end
|
230
|
+
|
231
|
+
def destroy_vdisk(vdisk_id)
|
232
|
+
request('DestroyVDisk', {'vsysId' => extract_vsys_id(vdisk_id), 'vdiskId' => vdisk_id})
|
233
|
+
end
|
234
|
+
|
235
|
+
def attach_vdisk(vserver_id, vdisk_id)
|
236
|
+
request('AttachVDisk', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id, 'vdiskId' => vdisk_id})
|
237
|
+
end
|
238
|
+
|
239
|
+
def detach_vdisk(vserver_id, vdisk_id)
|
240
|
+
request('DetachVDisk', {'vsysId' => extract_vsys_id(vserver_id), 'vserverId' => vserver_id, 'vdiskId' => vdisk_id})
|
241
|
+
end
|
242
|
+
|
243
|
+
def list_vdisk_backup(vdisk_id)
|
244
|
+
request('ListVDiskBackup', {'vsysId' => extract_vsys_id(vdisk_id), 'vdiskId' => vdisk_id})
|
245
|
+
end
|
246
|
+
|
247
|
+
def backup_vdisk(vdisk_id)
|
248
|
+
request('BackupVDisk', {'vsysId' => extract_vsys_id(vdisk_id), 'vdiskId' => vdisk_id})
|
249
|
+
end
|
250
|
+
|
251
|
+
def destroy_vdisk_backup(vsys_id, backup_id)
|
252
|
+
request('DestroyVDiskBackup', {'vsysId' => vsys_id, 'backupId' => backup_id})
|
253
|
+
end
|
254
|
+
|
255
|
+
def list_public_ips(vsys_id=nil)
|
256
|
+
if vsys_id.nil?
|
257
|
+
request('ListPublicIP')
|
258
|
+
else
|
259
|
+
request('ListPublicIP', {'vsysId' => vsys_id})
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
def allocate_public_ip(vsys_id)
|
264
|
+
request('AllocatePublicIP', {'vsysId' => vsys_id})
|
265
|
+
end
|
266
|
+
|
267
|
+
def attach_public_ip(vsys_id, public_ip)
|
268
|
+
request('AttachPublicIP', {'vsysId' => vsys_id, 'publicIp' => public_ip})
|
269
|
+
end
|
270
|
+
|
271
|
+
def detach_public_ip(vsys_id, public_ip)
|
272
|
+
request('DetachPublicIP', {'vsysId' => vsys_id, 'publicIp' => public_ip})
|
273
|
+
end
|
274
|
+
|
275
|
+
def free_public_ip(vsys_id, public_ip)
|
276
|
+
request('FreePublicIP', {'vsysId' => vsys_id, 'publicIp' => public_ip})
|
277
|
+
end
|
278
|
+
|
279
|
+
def create_vsys(vsys_descriptor_id, vsys_name)
|
280
|
+
request('CreateVSYS', {'vsysDescriptorId' => vsys_descriptor_id, 'vsysName' => vsys_name})
|
281
|
+
end
|
282
|
+
|
283
|
+
def destroy_vsys(vsys_id)
|
284
|
+
request('DestroyVSYS', {'vsysId' => vsys_id})
|
285
|
+
end
|
286
|
+
|
287
|
+
#extract vsysId from vserverId, efmId or networkId
|
288
|
+
def extract_vsys_id(id)
|
289
|
+
/^(\w+-\w+)\b.*/ =~ id
|
290
|
+
$1
|
291
|
+
end
|
292
|
+
|
293
|
+
private
|
294
|
+
|
295
|
+
# params hash is of the form :vserverId => 'ABC123', etc.
|
296
|
+
# uses POST if there is an attachment, else GET
|
297
|
+
def request(action, params={}, attachment=nil, attachment_name=nil)
|
298
|
+
accesskeyid, signature = generate_accesskeyid
|
299
|
+
params ||= {}
|
300
|
+
|
301
|
+
params.merge! :Version => @version unless params.has_key?(:Version)
|
302
|
+
params.merge! :Locale => @locale unless params.has_key?(:Locale)
|
303
|
+
params.merge! :Action => action,
|
304
|
+
:AccessKeyId => accesskeyid,
|
305
|
+
:Signature => signature
|
306
|
+
|
307
|
+
begin
|
308
|
+
if attachment.nil?
|
309
|
+
@uri.query = encode_params(params)
|
310
|
+
|
311
|
+
resp = @service.request_get(@uri.request_uri, @headers)
|
312
|
+
else
|
313
|
+
#multipart post
|
314
|
+
boundary = "BOUNDARY#{Time.now.to_i}"
|
315
|
+
body = create_multipart_body(params, attachment, attachment_name, boundary)
|
316
|
+
@headers['Content-Type'] = "multipart/form-data; boundary=#{boundary}"
|
317
|
+
@uri.query = nil #clear query params from previous request
|
318
|
+
|
319
|
+
resp = @service.request_post(@uri.request_uri, body, @headers)
|
320
|
+
end
|
321
|
+
rescue => e
|
322
|
+
# special treatment for errors like "Errno::ETIMEDOUT: Connection timed out - connect(2)"? (when proxy not set)
|
323
|
+
raise e
|
324
|
+
end
|
325
|
+
|
326
|
+
# p resp.body
|
327
|
+
# API endpoint only returns HTTPSuccess, so different code means connection issues (http proxy, etc.)
|
328
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
329
|
+
$stderr.print 'error: ' + $!
|
330
|
+
raise $!
|
331
|
+
end
|
332
|
+
|
333
|
+
xml = XmlSimple.xml_in(resp.body)
|
334
|
+
#check for connection errors, incl. NTP sync and auth related errors
|
335
|
+
raise "#{xml['responseStatus'][0]}: #{xml['responseMessage'][0]}" unless xml['responseStatus'].to_s =~ /SUCCESS/
|
336
|
+
|
337
|
+
xml
|
338
|
+
end
|
339
|
+
|
340
|
+
def generate_accesskeyid
|
341
|
+
t = Time.now
|
342
|
+
tz = t.zone
|
343
|
+
expires = (t.to_i * 1000.0).to_i
|
344
|
+
sig_version = '1.0'
|
345
|
+
sig_method = 'SHA1withRSA'
|
346
|
+
|
347
|
+
accesskeyid = Base64.encode64([ tz, expires, sig_version, sig_method ].join('&'))
|
348
|
+
signature = Base64.encode64(sign(accesskeyid))
|
349
|
+
|
350
|
+
return accesskeyid, signature
|
351
|
+
end
|
352
|
+
|
353
|
+
def encode_params(params)
|
354
|
+
params.map {|k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join('&')
|
355
|
+
end
|
356
|
+
|
357
|
+
def sign(data)
|
358
|
+
digester = OpenSSL::Digest::SHA1.new
|
359
|
+
@service.key.sign(digester, data)
|
360
|
+
end
|
361
|
+
|
362
|
+
def create_multipart_body(params, attachment, attachment_name, boundary)
|
363
|
+
body = "--#{boundary}\r\n"
|
364
|
+
body += "Content-Type: text/xml; charset=UTF-8\r\n"
|
365
|
+
body += "Content-Disposition: form-data; name=\"Document\"\r\n"
|
366
|
+
body += "\r\n"
|
367
|
+
|
368
|
+
body += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
|
369
|
+
body += "<OViSSRequest>\n"
|
370
|
+
params.each_pair do |k,v|
|
371
|
+
body += " <#{k}>#{v}</#{k}>\n"
|
372
|
+
end
|
373
|
+
body += "</OViSSRequest>"
|
374
|
+
body += "\r\n"
|
375
|
+
|
376
|
+
body += "--#{boundary}\r\n"
|
377
|
+
body += "Content-Type: application/octet-stream\r\n"
|
378
|
+
body += "Content-Disposition: form-data; name=\"#{attachment_name}\"; filename=\"#{attachment_name}.xml\"\r\n"
|
379
|
+
body += "\r\n"
|
380
|
+
body += attachment
|
381
|
+
body += "\r\n--#{boundary}--"
|
382
|
+
end
|
383
|
+
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|