deltacloud-core 0.0.1 → 0.0.2
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.
- 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
|