deltacloud-core 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +1 -24
- data/lib/deltacloud/base_driver/features.rb +15 -0
- data/lib/deltacloud/base_driver/mock_driver.rb +37 -0
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +70 -48
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +97 -14
- data/lib/deltacloud/drivers/{rimu/rimu_hosting_client.rb → rimuhosting/rimuhosting_client.rb} +5 -8
- data/lib/deltacloud/drivers/{rimu/rimu_hosting_driver.rb → rimuhosting/rimuhosting_driver.rb} +6 -5
- data/lib/deltacloud/drivers/terremark/terremark_driver.rb +261 -0
- data/lib/deltacloud/hardware_profile.rb +22 -0
- data/lib/deltacloud/helpers/application_helper.rb +18 -0
- data/lib/deltacloud/helpers/conversion_helper.rb +2 -3
- data/lib/deltacloud/method_serializer.rb +84 -0
- data/lib/drivers.rb +4 -3
- data/lib/sinatra/accept_media_types.rb +128 -0
- data/lib/sinatra/respond_to.rb +23 -16
- data/public/javascripts/application.js +30 -0
- data/public/javascripts/jquery-1.4.2.min.js +154 -0
- data/server.rb +23 -21
- data/support/fedora/deltacloudd +68 -0
- data/support/fedora/rubygem-deltacloud-core.spec +91 -0
- data/views/instances/index.html.haml +2 -1
- data/views/instances/index.xml.haml +3 -3
- data/views/instances/new.html.haml +9 -3
- data/views/instances/show.html.haml +2 -1
- data/views/instances/show.xml.haml +16 -3
- data/views/layout.html.haml +2 -0
- metadata +19 -37
- data/lib/converters/xml_converter.rb +0 -133
- data/public/javascripts/controls.js +0 -963
- data/public/javascripts/dragdrop.js +0 -973
- data/public/javascripts/effects.js +0 -1128
- data/public/javascripts/prototype.js +0 -4320
data/lib/deltacloud/drivers/{rimu/rimu_hosting_client.rb → rimuhosting/rimuhosting_client.rb}
RENAMED
@@ -24,17 +24,14 @@ require "deltacloud/base_driver"
|
|
24
24
|
|
25
25
|
module Deltacloud
|
26
26
|
module Drivers
|
27
|
-
module
|
27
|
+
module RimuHosting
|
28
28
|
|
29
29
|
class RimuHostingClient
|
30
30
|
def initialize(credentials ,baseuri = 'https://rimuhosting.com/r')
|
31
31
|
@uri = URI.parse(baseuri)
|
32
32
|
@service = Net::HTTP.new(@uri.host, @uri.port)
|
33
33
|
@service.use_ssl = true
|
34
|
-
|
35
|
-
@auth = "rimuhosting apikey=#{credentials.password}"
|
36
|
-
end
|
37
|
-
|
34
|
+
@auth = "rimuhosting apikey=#{credentials.password}"
|
38
35
|
end
|
39
36
|
|
40
37
|
def request(resource, data='', method='GET')
|
@@ -47,8 +44,9 @@ class RimuHostingClient
|
|
47
44
|
res = JSON.parse(r.body)
|
48
45
|
res = res[res.keys[0]]
|
49
46
|
|
50
|
-
if(res['response_type'] == "ERROR" and res['error_info']['error_class'] == "PermissionException")
|
51
|
-
|
47
|
+
if(res['response_type'] == "ERROR" and ( (res['error_info']['error_class'] == "PermissionException") or
|
48
|
+
(res['error_info']['error_class'] == "LoginRequired") ))
|
49
|
+
raise Deltacloud::AuthException.new
|
52
50
|
end
|
53
51
|
res
|
54
52
|
end
|
@@ -58,7 +56,6 @@ class RimuHostingClient
|
|
58
56
|
end
|
59
57
|
|
60
58
|
def list_plans
|
61
|
-
puts "testsdasfdsf"
|
62
59
|
request('/pricing-plans;server-type=VPS')["pricing_plan_infos"]
|
63
60
|
end
|
64
61
|
|
data/lib/deltacloud/drivers/{rimu/rimu_hosting_driver.rb → rimuhosting/rimuhosting_driver.rb}
RENAMED
@@ -17,11 +17,11 @@
|
|
17
17
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
18
18
|
|
19
19
|
require "deltacloud/base_driver"
|
20
|
-
require "deltacloud/drivers/
|
20
|
+
require "deltacloud/drivers/rimuhosting/rimuhosting_client"
|
21
21
|
|
22
22
|
module Deltacloud
|
23
23
|
module Drivers
|
24
|
-
module
|
24
|
+
module RimuHosting
|
25
25
|
|
26
26
|
class RimuHostingDriver < Deltacloud::BaseDriver
|
27
27
|
|
@@ -51,8 +51,8 @@ class RimuHostingDriver < Deltacloud::BaseDriver
|
|
51
51
|
# not contained in hte pricing_plan_infos
|
52
52
|
HardwareProfile.new(plan["pricing_plan_code"]) do
|
53
53
|
memory plan["minimum_memory_mb"].to_f
|
54
|
-
storage
|
55
|
-
architecture
|
54
|
+
storage plan["minimum_disk_gb"].to_i
|
55
|
+
architecture "x86"
|
56
56
|
end
|
57
57
|
end
|
58
58
|
filter_hardware_profiles(results, opts)
|
@@ -118,7 +118,8 @@ class RimuHostingDriver < Deltacloud::BaseDriver
|
|
118
118
|
:realm_id => "RH",
|
119
119
|
:owner_id => "root",
|
120
120
|
:instance_profile => InstanceProfile.new("none"),
|
121
|
-
:actions => instance_actions_for("RUNNING")
|
121
|
+
:actions => instance_actions_for("RUNNING"),
|
122
|
+
:public_addresses => inst["allocated_ips"]["primary_ip"]
|
122
123
|
})
|
123
124
|
end
|
124
125
|
|
@@ -0,0 +1,261 @@
|
|
1
|
+
# Copyright (C) 2010 Red Hat, Inc.
|
2
|
+
#
|
3
|
+
# This library is free software; you can redistribute it and/or
|
4
|
+
# modify it under the terms of the GNU Lesser General Public
|
5
|
+
# License as published by the Free Software Foundation; either
|
6
|
+
# version 2.1 of the License, or (at your option) any later version.
|
7
|
+
#
|
8
|
+
# This library is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
11
|
+
# Lesser General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
14
|
+
# License along with this library; if not, write to the Free Software
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
16
|
+
#
|
17
|
+
# This driver uses the fog library (Geemus - Wesley Beary) to talk to terremark... see
|
18
|
+
# http://github.com/geemus/fog
|
19
|
+
# see terremark vcloud express api at:
|
20
|
+
# https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/d-complete-vcloud-express-api-document.aspx
|
21
|
+
#
|
22
|
+
# 02 May 2010
|
23
|
+
#
|
24
|
+
require 'deltacloud/base_driver'
|
25
|
+
require 'fog'
|
26
|
+
require 'excon'
|
27
|
+
require 'nokogiri'
|
28
|
+
|
29
|
+
module Deltacloud
|
30
|
+
module Drivers
|
31
|
+
module Terremark
|
32
|
+
|
33
|
+
class TerremarkDriver < Deltacloud::BaseDriver
|
34
|
+
|
35
|
+
feature :instances, :user_name
|
36
|
+
|
37
|
+
#--
|
38
|
+
# Vapp State Map... for use with convert_instance (get an integer back from terremark)
|
39
|
+
#--
|
40
|
+
VAPP_STATE_MAP = { "0" => "PENDING", "1" => "PENDING", "2" => "STOPPED", "4" => "RUNNING" }
|
41
|
+
|
42
|
+
#--
|
43
|
+
# HARDWARE PROFILES
|
44
|
+
#--
|
45
|
+
define_hardware_profile 'default' do
|
46
|
+
cpu [1,2,4,8]
|
47
|
+
memory [512, 1024, 2048, 4096, 8192]
|
48
|
+
storage (1..500).to_a
|
49
|
+
end
|
50
|
+
#storage_disks [1..15]
|
51
|
+
|
52
|
+
#--
|
53
|
+
# IMAGES
|
54
|
+
#--
|
55
|
+
#aka "vapp_templates"
|
56
|
+
def images(credentials, opts=nil)
|
57
|
+
image_list = []
|
58
|
+
terremark_client = new_client(credentials)
|
59
|
+
vdc_id = terremark_client.default_vdc_id
|
60
|
+
catalogItems = terremark_client.get_catalog(vdc_id).body['CatalogItems']
|
61
|
+
catalogItems.each{ |catalog_item|
|
62
|
+
current_item_id = catalog_item['href'].split('/').last
|
63
|
+
current_item = terremark_client.get_catalog_item(current_item_id).body['Entity']
|
64
|
+
if(current_item['type'] == 'application/vnd.vmware.vcloud.vAppTemplate+xml')
|
65
|
+
image_list << convert_image(current_item, credentials.user)
|
66
|
+
end
|
67
|
+
} #end of catalogItems.each
|
68
|
+
image_list = filter_on( image_list, :id, opts )
|
69
|
+
image_list = filter_on( image_list, :architecture, opts )
|
70
|
+
image_list = filter_on( image_list, :owner_id, opts )
|
71
|
+
image_list
|
72
|
+
end
|
73
|
+
|
74
|
+
#--
|
75
|
+
# REALMS
|
76
|
+
#--
|
77
|
+
#only one realm... everything in US?
|
78
|
+
def realms(credentials, opts=nil)
|
79
|
+
[Realm.new( {
|
80
|
+
:id=>"US-Miami",
|
81
|
+
:name=>"United States - Miami",
|
82
|
+
:state=> "AVAILABLE"
|
83
|
+
} )]
|
84
|
+
end
|
85
|
+
|
86
|
+
#--
|
87
|
+
# INSTANCES
|
88
|
+
#--
|
89
|
+
#aka vApps
|
90
|
+
def instances(credentials, opts=nil)
|
91
|
+
instances = []
|
92
|
+
terremark_client = new_client(credentials)
|
93
|
+
vdc_items = terremark_client.get_vdc(terremark_client.default_vdc_id()).body['ResourceEntities']
|
94
|
+
vdc_items.each{|current_item|
|
95
|
+
if(current_item['type'] == 'application/vnd.vmware.vcloud.vApp+xml')
|
96
|
+
vapp_id = current_item['href'].split('/').last
|
97
|
+
vapp = terremark_client.get_vapp(vapp_id)
|
98
|
+
instances << convert_instance(vapp, terremark_client, credentials.user)
|
99
|
+
end
|
100
|
+
}#end vdc_items.each
|
101
|
+
instances = filter_on( instances, :id, opts )
|
102
|
+
instances
|
103
|
+
end
|
104
|
+
|
105
|
+
#--
|
106
|
+
# FINITE STATE MACHINE
|
107
|
+
#--
|
108
|
+
#by default new instance --> powered_off
|
109
|
+
define_instance_states do
|
110
|
+
start.to(:pending) .on( :create )
|
111
|
+
pending.to(:stopped) .automatically
|
112
|
+
stopped.to(:running) .on( :start )
|
113
|
+
running.to(:running) .on( :reboot )
|
114
|
+
running.to(:shutting_down) .on( :stop )
|
115
|
+
shutting_down.to(:stopped) .automatically
|
116
|
+
stopped.to(:end) .on( :destroy )
|
117
|
+
end
|
118
|
+
|
119
|
+
|
120
|
+
#--
|
121
|
+
# CREATE INSTANCE
|
122
|
+
#--
|
123
|
+
#launch a vapp template. Needs a name, ram, no. cpus, id of vapp_template
|
124
|
+
def create_instance(credentials, image_id, opts)
|
125
|
+
new_vapp = nil
|
126
|
+
vapp_opts = {} #assemble options to pass to Fog::Terremark::Real.instantiate_vapp_template
|
127
|
+
terremark_hwp = hardware_profiles(credentials, {:name => 'default'}).first #sanity check values against default
|
128
|
+
name = opts['name'] #name could be nil or length 0 or too long
|
129
|
+
name = "inst#{Time.now.to_i}" if (name.nil? || (name.length == 0))
|
130
|
+
name = name.slice(0..13) #name < 15 chars (says terremark)
|
131
|
+
unless ( (terremark_hwp.include?(:cpu, opts[:hwp_cpu].to_i)) &&
|
132
|
+
(terremark_hwp.include?(:memory, opts[:hwp_memory].to_i)) ) then
|
133
|
+
raise Deltacloud::Validation::Failure.new(Deltacloud::Validation::Param.new(["cpu"]), "Error with cpu and/or memory values. you said cpu->#{opts[:hwp_cpu]} and mem->#{opts[:hwp_memory]}")
|
134
|
+
end
|
135
|
+
vapp_opts['cpus'] = opts[:hwp_cpu]
|
136
|
+
vapp_opts['memory'] = opts[:hwp_memory]
|
137
|
+
terremark_client = new_client(credentials)
|
138
|
+
#######
|
139
|
+
#FIXME# what happens if there is an issue getting the new vapp id? (eg even though created succesfully)
|
140
|
+
#######
|
141
|
+
vapp_id = terremark_client.instantiate_vapp_template(name, image_id, vapp_opts).body['href'].split('/').last
|
142
|
+
new_vapp = terremark_client.get_vapp(vapp_id)
|
143
|
+
return convert_instance(new_vapp, terremark_client, credentials.user) #return an Instance object
|
144
|
+
end
|
145
|
+
|
146
|
+
#--
|
147
|
+
# REBOOT INSTANCE
|
148
|
+
#--
|
149
|
+
def reboot_instance(credentials, id)
|
150
|
+
terremark_client = new_client(credentials)
|
151
|
+
terremark_client.power_reset(id)
|
152
|
+
end
|
153
|
+
|
154
|
+
#--
|
155
|
+
# START INSTANCE
|
156
|
+
#--
|
157
|
+
def start_instance(credentials, id)
|
158
|
+
terremark_client = new_client(credentials)
|
159
|
+
terremark_client.power_on(id)
|
160
|
+
end
|
161
|
+
|
162
|
+
#--
|
163
|
+
# STOP INSTANCE
|
164
|
+
#--
|
165
|
+
def stop_instance(credentials, id)
|
166
|
+
terremark_client = new_client(credentials)
|
167
|
+
terremark_client.power_shutdown(id)
|
168
|
+
end
|
169
|
+
|
170
|
+
#--
|
171
|
+
# DESTROY INSTANCE
|
172
|
+
#--
|
173
|
+
#shuts down... in terremark need to do a futher delete to get rid of a vapp entirely
|
174
|
+
def destroy_instance(credentials, id)
|
175
|
+
terremark_client = new_client(credentials)
|
176
|
+
terremark_client.delete_vapp(id)
|
177
|
+
end
|
178
|
+
|
179
|
+
#--
|
180
|
+
# PRIVATE METHODS:
|
181
|
+
#--
|
182
|
+
|
183
|
+
private
|
184
|
+
|
185
|
+
#--
|
186
|
+
# CONVERT IMAGE
|
187
|
+
#--
|
188
|
+
#gets a vapp_template from a catalog and makes it a Image
|
189
|
+
def convert_image(catalog_vapp_template, account_name)
|
190
|
+
name = catalog_vapp_template['name']
|
191
|
+
#much fudging ensues
|
192
|
+
#arch = name.scan(/(36|24).bit/).first
|
193
|
+
#k enuf o'that now!
|
194
|
+
arch = "n/a" #Leaving out entirely as we don't get one from terremark (could parse but its a fudge)
|
195
|
+
Image.new( {
|
196
|
+
:id => catalog_vapp_template['href'].split('/').last,
|
197
|
+
:name => catalog_vapp_template['name'],
|
198
|
+
:architecture => arch,
|
199
|
+
:owner_id => account_name,
|
200
|
+
:description => catalog_vapp_template['name']
|
201
|
+
})
|
202
|
+
end
|
203
|
+
|
204
|
+
#--
|
205
|
+
# CONVERT INSTANCE
|
206
|
+
#--
|
207
|
+
def convert_instance(vapp, terremark_client, account_name)
|
208
|
+
vapp_private_ip = vapp.body['IpAddress']
|
209
|
+
vapp_public_ip = terremark_client.get_public_ips(terremark_client.default_vdc_id).body['PublicIpAddresses'].first['name']#get_public_address(terremark_client, vapp_private_ip)
|
210
|
+
vapp_status = vapp.body['status']
|
211
|
+
current_state = VAPP_STATE_MAP[vapp_status] #status == 0->BEING_CREATED 2->OFF 4->ON
|
212
|
+
profile = InstanceProfile.new("default")
|
213
|
+
name = vapp.body['name']
|
214
|
+
if current_state != "PENDING" #can only grab this stuff after instance is created
|
215
|
+
profile.cpu = vapp.body['VirtualHardware']['cpu']
|
216
|
+
profile.memory = vapp.body['VirtualHardware']['ram']
|
217
|
+
#######
|
218
|
+
#FIXME# could be more that one disk... but for now capture only first
|
219
|
+
#######
|
220
|
+
disk = ((vapp.body['VirtualHardware']['disks'].first.to_i) / 1024 / 1024).to_s
|
221
|
+
profile.storage = disk
|
222
|
+
#######
|
223
|
+
#FIXME# this is a hack, shouldn't place this info next to name as some clients may rely on name field... probably will introduce
|
224
|
+
####### a new field in the API for this (e.g. description/text field... human readable)
|
225
|
+
#name = "#{name} - [ #{vapp.body['OperatingSystem']['Description']} ]"
|
226
|
+
end
|
227
|
+
Instance.new( {
|
228
|
+
:id => vapp.body['href'].split('/').last,
|
229
|
+
:owner_id => "#{account_name}",
|
230
|
+
#:image_id => "n/a", #cant get this... see https://community.vcloudexpress.terremark.com/en-us/discussion_forums/f/60/t/376.aspx
|
231
|
+
:name => name,
|
232
|
+
:realm_id => "US-Miami",
|
233
|
+
:state => current_state,
|
234
|
+
:actions => instance_actions_for(current_state),
|
235
|
+
:public_addresses => vapp_public_ip,
|
236
|
+
:private_addresses => vapp_private_ip,
|
237
|
+
:instance_profile => profile
|
238
|
+
} )
|
239
|
+
end
|
240
|
+
|
241
|
+
#--
|
242
|
+
# NEW CLIENT
|
243
|
+
#--
|
244
|
+
#use supplied credentials to make a new client for talking to terremark
|
245
|
+
def new_client(credentials)
|
246
|
+
#Fog constructor expecting credentials[:terremark_password] and credentials[:terremark_username]
|
247
|
+
terremark_credentials = {:terremark_vcloud_username => "#{credentials.user}", :terremark_vcloud_password => "#{credentials.password}" }
|
248
|
+
terremark_client = Fog::Terremark::Vcloud.new(terremark_credentials)
|
249
|
+
vdc_id = terremark_client.default_vdc_id
|
250
|
+
if (vdc_id.nil?)
|
251
|
+
raise DeltaCloud::AuthException.new
|
252
|
+
end
|
253
|
+
terremark_client
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
end
|
258
|
+
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
@@ -117,6 +117,28 @@ module Deltacloud
|
|
117
117
|
p && p.default.to_s == v
|
118
118
|
end
|
119
119
|
|
120
|
+
def to_hash
|
121
|
+
props = []
|
122
|
+
self.each_property do |p|
|
123
|
+
if p.kind.eql? :fixed
|
124
|
+
props << { :kind => p.kind, :value => p.value, :name => p.name, :unit => p.unit }
|
125
|
+
else
|
126
|
+
param = { :operation => "create", :method => "post", :name => p.name }
|
127
|
+
if p.kind.eql? :range
|
128
|
+
param[:range] = { :first => p.first, :last => p.last }
|
129
|
+
elsif p.kind.eql? :enum
|
130
|
+
param[:enum] = p.values.collect { |v| { :entry => v } }
|
131
|
+
end
|
132
|
+
param
|
133
|
+
props << { :kind => p.kind, :value => p.default, :name => p.name, :unit => p.unit, :param => param }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
{
|
137
|
+
:id => self.name,
|
138
|
+
:properties => props
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
120
142
|
def include?(prop, v)
|
121
143
|
p = @properties[prop]
|
122
144
|
p.nil? || p.include?(v)
|
@@ -35,4 +35,22 @@ module ApplicationHelper
|
|
35
35
|
end
|
36
36
|
s+="</ul>"
|
37
37
|
end
|
38
|
+
|
39
|
+
def instance_action_method(action)
|
40
|
+
collections[:instances].operations[action.to_sym].method
|
41
|
+
end
|
42
|
+
|
43
|
+
def driver_has_feature?(feature_name)
|
44
|
+
not driver.features(:instances).select{ |f| f.name.eql?(feature_name) }.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
def driver_has_auth_features?
|
48
|
+
driver_has_feature?(:authentication_password) || driver_has_feature?(:authentication_key)
|
49
|
+
end
|
50
|
+
|
51
|
+
def driver_auth_feature_name
|
52
|
+
return 'key' if driver_has_feature?(:authentication_key)
|
53
|
+
return 'password' if driver_has_feature?(:authentication_password)
|
54
|
+
end
|
55
|
+
|
38
56
|
end
|
@@ -17,15 +17,14 @@
|
|
17
17
|
|
18
18
|
|
19
19
|
require 'deltacloud/base_driver'
|
20
|
-
require 'converters/xml_converter'
|
21
20
|
|
22
21
|
module ConversionHelper
|
23
22
|
|
24
23
|
def convert_to_json(type, obj)
|
25
|
-
if ( [ :flavor, :account, :image, :realm, :instance, :storage_volume, :storage_snapshot ].include?( type ) )
|
24
|
+
if ( [ :flavor, :account, :image, :realm, :instance, :storage_volume, :storage_snapshot, :hardware_profile ].include?( type ) )
|
26
25
|
if Array.eql?(obj.class)
|
27
26
|
data = obj.collect do |o|
|
28
|
-
o.to_hash.merge({ :href => self.send(:"#{type}_url", o.id ) })
|
27
|
+
o.to_hash.merge({ :href => self.send(:"#{type}_url", type.eql?(:hardware_profile) ? o.name : o.id ) })
|
29
28
|
end
|
30
29
|
type = type.to_s.pluralize
|
31
30
|
else
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009 Red Hat, Inc.
|
3
|
+
#
|
4
|
+
# This library is free software; you can redistribute it and/or
|
5
|
+
# modify it under the terms of the GNU Lesser General Public
|
6
|
+
# License as published by the Free Software Foundation; either
|
7
|
+
# version 2.1 of the License, or (at your option) any later version.
|
8
|
+
#
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
12
|
+
# Lesser General Public License for more details.
|
13
|
+
#
|
14
|
+
# You should have received a copy of the GNU Lesser General Public
|
15
|
+
# License along with this library; if not, write to the Free Software
|
16
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
17
|
+
|
18
|
+
require 'base64'
|
19
|
+
require 'digest'
|
20
|
+
|
21
|
+
module MethodSerializer
|
22
|
+
|
23
|
+
module Cache
|
24
|
+
|
25
|
+
def cache_dir
|
26
|
+
storage_dir = $methods_cache_dir || File.join(File.dirname(__FILE__), 'cache')
|
27
|
+
class_dir = self.class.name.split('::').last
|
28
|
+
class_dir ||= self.class.name
|
29
|
+
File.join(storage_dir, class_dir.downcase)
|
30
|
+
end
|
31
|
+
|
32
|
+
def serialize_data(method_name, args, data)
|
33
|
+
File.open(cache_file_name(method_name, args), 'w') do |f|
|
34
|
+
f.puts(Base64.encode64(Marshal.dump(data)))
|
35
|
+
end
|
36
|
+
return data
|
37
|
+
end
|
38
|
+
|
39
|
+
def deserialize_data(method_name, args)
|
40
|
+
begin
|
41
|
+
data = File.readlines(cache_file_name(method_name, args)).join
|
42
|
+
Marshal.load(Base64.decode64(data))
|
43
|
+
rescue Errno::ENOENT
|
44
|
+
return false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def args_hash(args)
|
49
|
+
if args.class == Hash
|
50
|
+
args = args.to_a.collect {|i| [i[0].to_s, i[1]]}.sort
|
51
|
+
end
|
52
|
+
Digest::SHA1.hexdigest(args.to_s)
|
53
|
+
end
|
54
|
+
|
55
|
+
def cache_file_name(method_name, args)
|
56
|
+
FileUtils.mkdir_p(cache_dir) unless File.directory?(cache_dir)
|
57
|
+
method_name = $scenario_prefix ? "#{$scenario_prefix}_#{method_name}" : method_name
|
58
|
+
File.join(cache_dir, "#{method_name}.#{args_hash(args)}")
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.wrap_methods(c, opts={})
|
62
|
+
$methods_cache_dir = opts[:cache_dir]
|
63
|
+
$scenario_prefix = nil
|
64
|
+
c.class_eval do
|
65
|
+
cached_methods.each do |m|
|
66
|
+
next if c.instance_methods(false).include?("original_#{m}")
|
67
|
+
alias_method "original_#{m}".to_sym, m.to_sym
|
68
|
+
define_method m.to_sym do |*args|
|
69
|
+
args = args.first if args.size.eql?(1) and not args.first.class.eql?(Array)
|
70
|
+
output = deserialize_data(m, args)
|
71
|
+
unless output
|
72
|
+
output = method("original_#{m}".to_sym).to_proc[args]
|
73
|
+
return serialize_data(m, args, output)
|
74
|
+
else
|
75
|
+
return output
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|