spiderfw 0.6.6 → 0.6.7

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/CHANGELOG CHANGED
@@ -1,3 +1,7 @@
1
+ = 0.6.7
2
+ == 26 July, 2011
3
+ * Process management and app setup enhancements
4
+
1
5
  = 0.6.6
2
6
  == 19 July, 2011
3
7
  * Fix: use SEE_OTHER as default redirect code to avoid FF 5 caching
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.6.6
1
+ 0.6.7
data/apps/master/_init.rb CHANGED
@@ -14,6 +14,8 @@ require 'apps/master/master'
14
14
  require 'apps/master/models/admin'
15
15
  require 'apps/master/models/customer'
16
16
  require 'apps/master/models/installation'
17
+ require 'apps/master/models/command'
18
+ require 'apps/master/models/event'
17
19
  require 'apps/master/models/remote_log'
18
20
  require 'apps/master/models/server'
19
21
  require 'apps/master/models/scout_plugin_info'
@@ -18,7 +18,7 @@ module Spider; module Master
18
18
  #route /servers\/([^\/]+)/, ServerController, :do => lambda{ |id| @request.misc[:server] = Server.new(id) }
19
19
  route 'login', LoginController
20
20
 
21
- require_user Master::Admin, :unless => [:login, :admin, :ping], :redirect => 'login'
21
+ require_user Master::Admin, :unless => [:login, :admin, :ping, :servant_event], :redirect => 'login'
22
22
  require_user Spider::Auth::SuperUser, :only => [:admin]
23
23
 
24
24
 
@@ -118,28 +118,34 @@ module Spider; module Master
118
118
  @installation = Installation.new(id) unless id == 'new'
119
119
  @scene.edit = (@request.params['_w'] && @request.params['_w'].key?('installation_form')) || @request.params.key?('edit') || id == 'new'
120
120
  @scene.pk = id
121
-
122
- # if id == 'new'
123
- # if @request.params.key?('installation_create') && !@request.params['installation_name'].empty?
124
- # i = Installation.new(:name => @request.params['installation_name'])
125
- # i.customer = @customer
126
- # i.save
127
- # redirect(File.dirname(@request.path)+"/#{i.id}")
128
- # end
129
- # else
130
- # if @request.params.key?('save_apps')
131
- # @installation.apps = @request.params['apps'].keys.join(',')
132
- # @installation.save
133
- # redirect(request.path)
134
- # end
135
- # @scene.install_apps = JSON.parse(@installation.apps) unless @installation.apps.blank?
136
- # @scene.install_apps ||= []
137
- # @scene.apps = Spider::AppServer.apps_by_id
138
- # end
121
+
122
+ if @request.params['add_command']
123
+ command = @request.params['command']
124
+ args = @request.params['arguments']
125
+ arguments = args
126
+ # FIXME: move somewhere else
127
+ case command
128
+ when 'gems', 'apps'
129
+ arguments = args.split(/\s*,\s*/).to_json
130
+ end
131
+ Master::Command.create(
132
+ :installation => @installation,
133
+ :name => @request.params['command'],
134
+ :arguments => arguments,
135
+ :status => 'pending'
136
+ )
137
+ redirect(@request.path)
138
+
139
+ end
139
140
  @scene.install_apps = JSON.parse(@installation.apps) unless @installation.apps.blank?
140
141
  @scene.install_apps ||= []
141
142
  @scene.apps = Spider::AppServer.apps_by_id
142
143
  @scene.logs = RemoteLog.where(:installation => @installation)
144
+ @scene.commands = Master::Command.where{ |c| (c.installation == @installation) }.order_by(:obj_created)
145
+ @scene.available_commands = {
146
+ 'gems' => _('Install or update gems'),
147
+ 'apps' => _('Install or update apps')
148
+ }
143
149
  @scene << {
144
150
  :customer => @customer,
145
151
  :installation => @installation
@@ -345,15 +351,66 @@ module Spider; module Master
345
351
  RemoteLog.create(:text => desc, :level => level, :time => time, :installation => install)
346
352
  end
347
353
  response = {
348
- :pong => DateTime.new
354
+ :pong => DateTime.now
349
355
  }
350
- # server.pending_commands.each do |command|
351
- # response[:commands] ||= []
352
- # response[:commands] << command.to_h
353
- # end
356
+ commands = []
357
+ Master::Command.where{ |c| (c.installation == install) & (c.status == 'pending') }.each do |c|
358
+ commands << {
359
+ :id => c.uuid,
360
+ :name => c.name,
361
+ :arguments => c.arguments ? JSON.parse(c.arguments) : nil
362
+ }
363
+ end
364
+ response[:commands] = commands unless commands.empty?
354
365
  $out << response.to_json
366
+ Master::Command.where{ |c| (c.installation == install) & (c.status == 'pending') }.each do |c|
367
+ c.sent = DateTime.now
368
+ c.status = 'sent'
369
+ c.save
370
+ end
355
371
  end
356
372
 
373
+ __.json
374
+ def servant_event
375
+ params = @request.params.clone
376
+ name = params.delete('event')
377
+ install_id = params.delete('install_id')
378
+ unless install_id
379
+ Spider.logger.error("No install_id passed in ping")
380
+ done
381
+ end
382
+ install = Spider::Master::Installation.load_or_create(:uuid => install_id)
383
+ details = @request.params['details']
384
+ params = JSON.parse(details)
385
+ Event.create(
386
+ :installation => install,
387
+ :name => name,
388
+ :details => details
389
+ )
390
+ case name.to_sym
391
+ when :command_done
392
+ cmd = Master::Command.load(:uuid => params['id'])
393
+ cmd.done = DateTime.now
394
+ cmd.result = params['res'].to_json
395
+ cmd.status = 'success'
396
+ cmd.save
397
+ when :plan_done
398
+ results = params['results']
399
+ results.each do |res|
400
+ cmd = Master::Command.load(:uuid => res['command_id'])
401
+ if res['previous_error']
402
+ cmd.status = 'not_done'
403
+ cmd.save
404
+ elsif res['error']
405
+ cmd.status = 'error'
406
+ cmd.save
407
+ end
408
+ end
409
+ end
410
+ end
411
+
412
+
413
+
357
414
  private
358
415
 
359
416
  def decompress_string(str)
@@ -1,17 +1,24 @@
1
1
  module Spider; module Master
2
2
 
3
- class Command < Spider::Model::BaseModel
4
- remove_element :id
5
- element :id, UUID
3
+ class Command < Spider::Model::Managed
4
+ element :installation, Installation, :add_multiple_reverse => :commands
5
+ element :uuid, UUID
6
6
  element :name, String
7
7
  element :arguments, Text
8
8
  element :status, {
9
9
  'pending' => 'Pending',
10
+ 'sent' => 'Sent',
10
11
  'success' => 'Success',
11
- 'failure' => 'Failure'
12
+ 'failure' => 'Failure',
13
+ 'not_done' => 'Not done'
12
14
  }, :default => 'pending'
13
- element :executed, DateTime
15
+ element :sent, DateTime
16
+ element :done, DateTime
14
17
  element :result, Text
18
+
19
+ def to_s
20
+ "#{self.name} '#{self.arguments}' - #{self.status}"
21
+ end
15
22
  end
16
23
 
17
24
  end; end
@@ -0,0 +1,9 @@
1
+ module Spider; module Master
2
+
3
+ class Event < Spider::Model::Managed
4
+ element :installation, Installation, :add_multiple_reverse => :events
5
+ element :name, String
6
+ element :details, Text
7
+ end
8
+
9
+ end; end
@@ -20,6 +20,12 @@
20
20
  <h2>_(Installation "%s") % [@installation]</h2>
21
21
  <a href="?edit" class="manage edit">_(Edit)</a>
22
22
  </div>
23
+ <div class="details">
24
+ _(Last check-in): { @installation.last_check.lformat(:short) }
25
+ <tpl:pass sp:if="@installation.interval">
26
+ _(Next check-in): { (@installation.last_check + @installation.interval).lformat(:short) }
27
+ </tpl:pass>
28
+ </div>
23
29
  <core:tabs id="tabs">
24
30
  <tab label="_(Apps)" id="apps">
25
31
  <div class="apps">
@@ -43,6 +49,22 @@
43
49
  <core:table id="logs_table" queryset="@logs" sort="time,desc" />
44
50
  </div>
45
51
  </tab>
52
+ <tab label="_(Commands)" id="commands">
53
+ <div class="commands">
54
+ <h4>_(Commands)</h4><a href="#" class="manage add">_(Add command)</a>
55
+ <div id="add_command">
56
+ <form>
57
+ <select name="command">
58
+ <option></option>
59
+ <option sp:each="@available_commands |k, v|" value="{ k }">{ v }</option>
60
+ </select>
61
+ <input type="text" name="arguments">
62
+ <input type="submit" name="add_command" value="_(Ok)">
63
+ </form>
64
+ </div>
65
+ <core:list id="commands_list" queryset="@commands" delete="true" />
66
+ </div>
67
+ </tab>
46
68
  </core:tabs>
47
69
  </div>
48
70
  </div>
@@ -10,9 +10,14 @@ module Spider
10
10
  def initialize(url)
11
11
  @url = url
12
12
  end
13
+
14
+ def http_client
15
+ HTTPClient.new
16
+ end
13
17
 
14
- def ping_server(url=@url)
15
- clnt = HTTPClient.new
18
+ def ping_server(url=nil)
19
+ url ||= @url
20
+ clnt = self.http_client
16
21
  status = Servant.status
17
22
  status[:apps] = status[:apps].to_json
18
23
  last_check_file = File.join(Spider.paths[:var], 'memory', 'servant_last_check')
@@ -29,15 +34,24 @@ module Spider
29
34
  end
30
35
  File.open(last_check_file, 'w'){ |f| f << Time.now.to_s }
31
36
  res = JSON.parse(res.content)
32
- if res[:commands]
33
- res[:commands].each do |command|
34
- command_result = execute_command(command[:name], command[:arguments])
35
- clnt.post()
36
- end
37
+ if res['commands']
38
+ processor = Servant.command_processor.new(url)
39
+ processor.run_commands(res['commands'])
37
40
  end
38
41
  end
39
42
 
43
+ def process_commands(commands)
44
+ end
45
+
46
+ def send_event(name, details)
47
+ self.http_client.post("#{@url}/servant_event", {
48
+ :event => name, :install_id => Servant.install_id, :details => details.to_json
49
+ })
50
+ end
51
+
52
+
40
53
  private
54
+
41
55
 
42
56
  def compress_string(str)
43
57
  compr = ""
@@ -0,0 +1,109 @@
1
+ module Spider; module Servant
2
+
3
+ class CommandsProcessor
4
+ attr_reader :client
5
+
6
+ def self.plan_file
7
+ File.join(Spider.paths[:var], 'servant_command_plan')
8
+ end
9
+
10
+ def self.progress_file
11
+ File.join(Spider.paths[:var], 'servant_command_progress')
12
+ end
13
+
14
+ def self.save_plan(commands)
15
+ File.open(self.plan_file, 'w'){ |f| f << commands.to_json }
16
+ end
17
+
18
+ def self.read_plan
19
+ return nil unless File.exists?(self.plan_file)
20
+ JSON.parse(File.readfile(self.plan_file))
21
+ end
22
+
23
+ def self.unfinished_plan?
24
+ File.exists?(self.plan_file)
25
+ end
26
+
27
+ def initialize(master_url)
28
+ @url = master_url
29
+ @client = Servant::Client.new(@url)
30
+ @progress = {}
31
+ end
32
+
33
+ def resume_plan
34
+ plan = self.class.read_plan
35
+ progress = JSON.parse(File.read(self.progress_file)) if File.exists?(self.progress_file)
36
+ progress ||= {}
37
+ plan.reject!{ |c| progress[c['id']] }
38
+ process_commands(plan)
39
+ end
40
+
41
+ def save_progress
42
+ File.open(self.class.progress_file, 'w'){ |f| f << @progress.to_json }
43
+ end
44
+
45
+ def run_commands(commands)
46
+ self.class.save_plan(commands)
47
+ process_commands(commands)
48
+ end
49
+
50
+ def process_commands(commands)
51
+ results = []
52
+ error = nil
53
+ commands.each do |command|
54
+ command_result = {:command_id => command['id']}
55
+ if error
56
+ command_result[:previous_error] = true
57
+ else
58
+ begin
59
+ command_result[:res] = execute_command(command)
60
+ rescue => exc
61
+ error = exc.message
62
+ command_result[:error] = error
63
+ end
64
+ end
65
+ results << command_result
66
+ end
67
+ self.client.send_event(:plan_done, {:results => results})
68
+ File.unlink(self.class.plan_file) if File.exists?(self.class.plan_file)
69
+ File.unlink(self.class.progress_file) if File.exists?(self.class.progress_file)
70
+ end
71
+
72
+ def execute_command(command)
73
+ args = command["arguments"]
74
+ res = case command["name"]
75
+ when "gems"
76
+ install_gems(args)
77
+ when "apps"
78
+ install_apps(args)
79
+ when "configure"
80
+
81
+ end
82
+ @progress[command['id']] = true
83
+ save_progress
84
+ self.client.send_event(:command_done, {:id => command['id'], :res => res})
85
+ res
86
+ end
87
+
88
+ def install_gems(gems)
89
+ inst = Gem::DependencyInstaller.new
90
+ installed = []
91
+ gems.each do |g|
92
+ v = g['version'] || Gem::Requirement.default
93
+ unless Gem.available?(g['name'], v)
94
+ inst.install g['name'], v
95
+ installed << g
96
+ end
97
+
98
+ end
99
+ return {:installed => gems}
100
+ end
101
+
102
+ def install_apps(apps)
103
+ require 'spiderfw/setup/app_manager'
104
+ Spider::AppManager.install_or_update(apps)
105
+ end
106
+
107
+ end
108
+
109
+ end; end
@@ -1,9 +1,19 @@
1
1
  require 'uuidtools'
2
+ require 'apps/servant/lib/client'
3
+ require 'apps/servant/lib/commands_processor'
2
4
 
3
5
  module Spider
4
6
 
5
7
  module Servant
8
+
9
+ def self.command_processor
10
+ @command_processor ||= Spider::Servant::CommandsProcessor
11
+ end
6
12
 
13
+ def self.command_processor=(klass)
14
+ @command_processor = klass
15
+ end
16
+
7
17
  def self.install_id
8
18
  uuid_file = File.join(Spider.paths[:var], 'install_id')
9
19
  return File.read(uuid_file) if File.exists?(uuid_file)
@@ -5,7 +5,6 @@ class AppCommand < CmdParse::Command
5
5
  super('app', true, true )
6
6
  @short_desc = _("Manage apps")
7
7
 
8
- @server_url = 'http://www.soluzionipa.it/euroservizi/spider/app_server'
9
8
 
10
9
  self.options = CmdParse::OptionParserWrapper.new do |opt|
11
10
  opt.on("--proxy [SERVER]", _("Proxy server to use (http://user:pass@host:port)"), "-p"){ |p|
@@ -57,6 +56,11 @@ class AppCommand < CmdParse::Command
57
56
  end
58
57
  if @remote
59
58
  require 'spiderfw/setup/app_server_client'
59
+ unless @server_url
60
+ require 'spiderfw/spider'
61
+ Spider.init_base
62
+ @server_url = Spider.config.get('app_server.url')
63
+ end
60
64
  client = Spider::AppServerClient.new(@server_url)
61
65
  remote = {}
62
66
  client.specs.each do |app|
@@ -119,56 +123,26 @@ class AppCommand < CmdParse::Command
119
123
  puts _("Please execute this command from the home folder")
120
124
  exit
121
125
  end
122
- require 'spiderfw/setup/app_server_client'
123
- use_git = false
124
- unless @no_git
125
- begin
126
- require 'grit'
127
- use_git = true
128
- rescue => exc
129
- puts exc.message
130
- puts "Grit not available; install Grit for Git support"
131
- end
132
- end
133
-
134
- apps = args
135
- existent = []
136
- apps.each do |app|
137
- if File.exist?("apps/#{app}")
138
- puts _("%s already exists, skipping") % app
139
- existent << app
140
- end
141
- end
142
126
  require 'spiderfw/setup/app_manager'
143
- specs = []
144
- client = Spider::AppServerClient.new(@server_url)
145
- if @no_deps
146
- specs = client.get_specs(apps)
147
- else
148
- specs = client.get_deps(apps, :no_optional => @no_optional)
149
- end
150
- deps = specs.map{ |s| s.app_id }
151
- unless (deps - apps).empty?
152
- puts _("The following apps will be installed as a dependency:")
153
- puts (deps - apps).inspect
154
- end
155
127
  options = {
156
- :use_git => use_git,
157
- :no_gems => @no_gems,
158
- :no_optional_gems => @no_optional_gems
128
+ :no_git => @no_git, :all => @all, :no_deps => @no_deps, :no_optional => @no_optional,
129
+ :no_gems => @no_gems, :no_optional_gems => @no_optional_gems, :no_activate => @no_activate
159
130
  }
160
- options[:ssh_user] = @ssh_user if @ssh_user
161
- inst_specs = specs.reject!{ |s| existent.include? s.app_id }
162
- Spider::AppManager.install(inst_specs, Dir.pwd, options)
163
- unless @no_activate
164
- require 'spiderfw/spider'
165
- specs_hash = {}
166
- specs.each{ |s| specs_hash[s.app_id] = s }
167
- Spider.activate_apps(deps, specs_hash)
168
- end
131
+ options[:url] = @server_url if @server_url
132
+ Spider::AppManager.install_apps(args, options)
169
133
  end
170
134
  self.add_command(install)
171
135
 
136
+ activate = CmdParse::Command.new('activate', false )
137
+ activate.short_desc = _("Activate an app")
138
+ activate.set_execution_block do |args|
139
+ apps = args
140
+ require 'spiderfw/spider'
141
+ apps = Spider.get_app_deps(apps)
142
+ Spider.activate_apps(apps)
143
+ end
144
+ self.add_command(activate)
145
+
172
146
  update = CmdParse::Command.new( 'update', false )
173
147
  update.short_desc = _("Update an app")
174
148
  update.options = CmdParse::OptionParserWrapper.new do |opt|
@@ -188,44 +162,13 @@ class AppCommand < CmdParse::Command
188
162
  puts _("Please execute this command from the home folder")
189
163
  exit
190
164
  end
191
- require 'spiderfw/setup/app_server_client'
192
- use_git = false
193
- unless @no_git
194
- begin
195
- require 'grit'
196
- use_git = true
197
- rescue
198
- puts "Grit not available; install Grit for Git support"
199
- end
200
- end
201
- apps = args
202
- if @all
203
- require 'spiderfw/home'
204
- home = Spider::Home.new(Dir.pwd)
205
- apps = home.list_apps
206
- end
207
- if apps.empty?
208
- puts _("No app to update")
209
- exit
210
- end
211
165
  require 'spiderfw/setup/app_manager'
212
- specs = []
213
- client = Spider::AppServerClient.new(@server_url)
214
- if @no_deps
215
- specs = client.get_specs(apps)
216
- else
217
- specs = client.get_deps(apps, :no_optional => @no_optional)
218
- end
219
- deps = specs.map{ |s| s.app_id }
220
- unless (deps - apps).empty?
221
- puts _("The following apps will be updated as a dependency:")
222
- puts (deps - apps).inspect
223
- end
224
- Spider::AppManager.update(specs, Dir.pwd, {
225
- :use_git => use_git,
226
- :no_gems => @no_gems,
227
- :no_optional_gems => @no_optional_gems
228
- })
166
+ options = {
167
+ :no_git => @no_git, :all => @all, :no_deps => @no_deps, :no_optional => @no_optional,
168
+ :no_gems => @no_gems, :no_optional_gems => @no_optional_gems
169
+ }
170
+ options[:url] = @server_url if @server_url
171
+ Spider::AppManager.update_apps(args, options)
229
172
  end
230
173
  self.add_command(update)
231
174
 
@@ -33,7 +33,7 @@ module Spider
33
33
  :default => Proc.new{ RUBY_VERSION_PARTS[1] == '8' && !Object.const_defined?(:PhusionPassenger) ? true : false }
34
34
  config_option 'webserver.timeout', _("Time allowed for each request (in seconds)"), :type=> Fixnum, :default => nil
35
35
  config_option 'webserver.respawn_on_change', _("Restart the webserver when application code changes"), :type => Spider::Bool,
36
- :default => Proc.new{ Spider.config.get('runmode') == 'devel' ? true : false }
36
+ :default => Proc.new{ RUBY_PLATFORM !~ /win32|mingw32/ && Spider.config.get('runmode') == 'devel' ? true : false }
37
37
  config_option 'static_content.mode', _("Mode to use for serving static files"), :type => String,
38
38
  :choices => [nil, 'x-sendfile', 'x-accel-redirect', 'published'], :default => nil
39
39
  config_option 'static_content.auto_publish', _("Automatically publish content to the home's public folder"),
@@ -22,6 +22,9 @@ module Spider
22
22
  class ControllerError < RuntimeError
23
23
  end
24
24
 
25
+ class Maintenance < RuntimeError
26
+ end
27
+
25
28
  end
26
29
 
27
30
  end
@@ -40,6 +40,11 @@ module Spider
40
40
 
41
41
  end
42
42
 
43
+ def try_rescue(exc)
44
+ super
45
+ self.done = true
46
+ end
47
+
43
48
 
44
49
  end
45
50
 
@@ -1,7 +1,7 @@
1
1
  module Spider
2
2
 
3
3
  class HomeController < Controller
4
- include StaticContent
4
+ include StaticContent, HTTPMixin
5
5
  route 'spider/public', Spider.controller, :prepend => 'public/'
6
6
  # route 'spider', Spider.controller
7
7
 
@@ -89,9 +89,13 @@ module Spider; module ControllerMixins
89
89
  super
90
90
  end
91
91
 
92
- def base_url()
92
+ def self.base_url
93
93
  HTTPMixin.reverse_proxy_mapping("")
94
94
  end
95
+
96
+ def base_url
97
+ self.class.base_url
98
+ end
95
99
 
96
100
  def prepare_scene(scene)
97
101
  scene = super
@@ -101,7 +105,6 @@ module Spider; module ControllerMixins
101
105
  end
102
106
 
103
107
  def try_rescue(exc)
104
- self.done = true
105
108
  if (exc.is_a?(Spider::Controller::NotFound))
106
109
  @response.status = Spider::HTTP::NOT_FOUND
107
110
  elsif (exc.is_a?(Spider::Controller::BadRequest))
@@ -40,6 +40,9 @@ module Spider; module ControllerMixins
40
40
  output_format_headers(format)
41
41
  @executed_format = format
42
42
  @executed_format_params = format_params
43
+ if Spider.runmode != 'devel' && File.exists?(File.join(Spider.paths[:tmp], 'maintenance.txt'))
44
+ raise Spider::Controller::Maintenance
45
+ end
43
46
  super
44
47
  end
45
48
 
@@ -182,7 +185,7 @@ module Spider; module ControllerMixins
182
185
  def render(path=nil, options={})
183
186
  scene = options[:scene] || @scene
184
187
  scene ||= get_scene
185
- scene = prepare_scene(scene)
188
+ scene = prepare_scene(scene) unless options[:no_prepare_scene]
186
189
  request = options[:request] || @request
187
190
  response = options[:response] || @response
188
191
  if (path.is_a?(Spider::Template))
@@ -215,6 +218,11 @@ module Spider; module ControllerMixins
215
218
  return template
216
219
  end
217
220
 
221
+ def render_error(path, options)
222
+ options[:no_prepare_scene] = true
223
+ render(path, options)
224
+ end
225
+
218
226
  def find_widget(name)
219
227
  @template.find_widget(name)
220
228
  end
@@ -239,19 +247,26 @@ module Spider; module ControllerMixins
239
247
  return obj
240
248
  end
241
249
 
242
- def try_rescue(exc)
250
+ def try_rescue(exc)
243
251
  exc.uuid = UUIDTools::UUID.random_create.to_s if exc.respond_to?(:uuid=)
244
252
  format = self.class.output_format(:error) || :html
245
- return super unless @executed_format == :html
246
- return super unless action_target?
247
- return super if target_mode?
253
+ unless exc.is_a?(Spider::Controller::Maintenance) || exc.is_a?(Spider::Controller::NotFound)
254
+ return super unless @executed_format == :html
255
+ return super unless action_target?
256
+ return super if target_mode?
257
+ end
248
258
  output_format_headers(format)
249
- if (exc.is_a?(Spider::Controller::NotFound))
250
- error_page = '404'
259
+ layout = 'errors/error'
260
+ if exc.is_a?(Spider::Controller::Maintenance)
261
+ error_page = 'maintenance'
262
+ layout = 'generic'
263
+ elsif exc.is_a?(Spider::Controller::NotFound)
264
+ error_page = 'errors/404'
265
+ layout = 'errors/simple'
251
266
  @scene.error_msg = _("Page not found")
252
267
  @scene.email_subject = @scene.error_msg
253
268
  else
254
- error_page = 'error_generic'
269
+ error_page = 'errors/error_generic'
255
270
  if (exc.is_a?(HTTPMixin::HTTPStatus))
256
271
  @scene.error_msg = exc.status_message
257
272
  end
@@ -259,13 +274,13 @@ module Spider; module ControllerMixins
259
274
  @scene.email_subject = @scene.error_msg
260
275
  end
261
276
 
262
- if (exc.respond_to?(:uuid))
277
+ if exc.respond_to?(:uuid)
263
278
  exc.extend(UUIDExceptionMessage)
264
279
  @scene.exception_uuid = exc.uuid
265
- @scene.email_subject += " (#{exc.uuid})"
280
+ @scene.email_subject += " (#{exc.uuid})" if @scene.email_subject
266
281
  end
267
282
  @scene.admin_email = Spider.conf.get('site.tech_admin.email')
268
- if (Spider.runmode == 'devel')
283
+ if Spider.runmode == 'devel'
269
284
  begin
270
285
  @scene.devel = true
271
286
  @scene.backtrace = build_backtrace(exc)
@@ -294,7 +309,7 @@ module Spider; module ControllerMixins
294
309
  rescue => exc2
295
310
  end
296
311
  end
297
- render "errors/#{error_page}", :layout => "errors/error"
312
+ render_error "#{error_page}", :layout => layout
298
313
  super
299
314
  end
300
315
 
@@ -166,7 +166,6 @@ module Spider; module HTTP
166
166
  Process.kill 'KILL', @monitor_thread[:spawner_child_pid]
167
167
  }
168
168
  Spider.on_main_process_shutdown(&exit_spawner)
169
- Spider.main_process_startup
170
169
  $SPIDER_SCRIPT ||= $0
171
170
  $0 = 'spider-spawner'
172
171
  end
@@ -4,6 +4,129 @@ require 'fileutils'
4
4
  module Spider
5
5
 
6
6
  module AppManager
7
+
8
+ def self.install_or_update(apps, options={})
9
+ require 'spiderfw/home'
10
+ home = Spider::Home.new(Dir.pwd)
11
+ installed = {}
12
+ Spider.init_base
13
+ active = Spider.config.get('apps')
14
+ Spider.home.apps.each do |app, info|
15
+ installed[app] = {
16
+ :active => active.include?(app)
17
+ }
18
+ if spec = info[:spec]
19
+ installed[app].merge!({
20
+ :version => spec.version
21
+ })
22
+ end
23
+ end
24
+ to_inst = apps.select{ |a| !installed[a] }
25
+ to_upd = apps.select{ |a| installed[a] }
26
+ install_apps(to_inst, options)
27
+ update_apps(to_upd, options)
28
+ return {:installed => to_inst, :updated => to_upd}
29
+ end
30
+
31
+ def self.install_apps(apps, options={})
32
+ return if apps.empty?
33
+ require 'spiderfw/setup/app_server_client'
34
+ use_git = false
35
+ unless options[:no_git]
36
+ begin
37
+ require 'grit'
38
+ use_git = true
39
+ rescue => exc
40
+ puts exc.message
41
+ puts "Grit not available; install Grit for Git support"
42
+ end
43
+ end
44
+
45
+ existent = []
46
+ apps.each do |app|
47
+ if File.exist?("apps/#{app}")
48
+ puts _("%s already exists, skipping") % app
49
+ existent << app
50
+ end
51
+ end
52
+ require 'spiderfw/setup/app_manager'
53
+ specs = []
54
+ url = options[:url]
55
+ unless url
56
+ require 'spiderfw/spider'
57
+ Spider.init_base
58
+ url = Spider.config.get('app_server.url')
59
+ end
60
+ client = Spider::AppServerClient.new(url)
61
+ if options[:no_deps]
62
+ specs = client.get_specs(apps)
63
+ else
64
+ specs = client.get_deps(apps, :no_optional => options[:no_optional])
65
+ end
66
+ deps = specs.map{ |s| s.app_id }
67
+ unless (deps - apps).empty?
68
+ puts _("The following apps will be installed as a dependency:")
69
+ puts (deps - apps).inspect
70
+ end
71
+ i_options = {
72
+ :use_git => use_git,
73
+ :no_gems => options[:no_gems],
74
+ :no_optional_gems => options[:no_optional_gems]
75
+ }
76
+ i_options[:ssh_user] = options[:ssh_user] if options[:ssh_user]
77
+ inst_specs = specs.reject!{ |s| existent.include? s.app_id }
78
+ Spider::AppManager.install(inst_specs, Dir.pwd, i_options)
79
+ unless options[:no_activate]
80
+ require 'spiderfw/spider'
81
+ specs_hash = {}
82
+ specs.each{ |s| specs_hash[s.app_id] = s }
83
+ Spider.activate_apps(deps, specs_hash)
84
+ end
85
+
86
+ end
87
+
88
+ def self.update_apps(apps, options={})
89
+ require 'spiderfw/spider'
90
+ require 'spiderfw/setup/app_server_client'
91
+ Spider.init_base
92
+ url = options[:url] || Spider.conf.get('app_server.url')
93
+ use_git = false
94
+ unless options[:no_git]
95
+ begin
96
+ require 'grit'
97
+ use_git = true
98
+ rescue
99
+ puts "Grit not available; install Grit for Git support"
100
+ end
101
+ end
102
+ if options[:all]
103
+ require 'spiderfw/home'
104
+ home = Spider::Home.new(Dir.pwd)
105
+ apps = home.list_apps
106
+ end
107
+ if apps.empty?
108
+ puts _("No app to update")
109
+ exit
110
+ end
111
+ require 'spiderfw/setup/app_manager'
112
+ specs = []
113
+ client = Spider::AppServerClient.new(url)
114
+ if options[:no_deps]
115
+ specs = client.get_specs(apps)
116
+ else
117
+ specs = client.get_deps(apps, :no_optional => options[:no_optional])
118
+ end
119
+ deps = specs.map{ |s| s.app_id }
120
+ unless (deps - apps).empty?
121
+ puts _("The following apps will be updated as a dependency:")
122
+ puts (deps - apps).inspect
123
+ end
124
+ Spider::AppManager.update(specs, Dir.pwd, {
125
+ :use_git => use_git,
126
+ :no_gems => options[:no_gems],
127
+ :no_optional_gems => options[:no_optional_gems]
128
+ })
129
+ end
7
130
 
8
131
  def self.install(specs, home_path, options)
9
132
  options[:use_git] = true unless options[:use_git] == false
@@ -77,7 +200,7 @@ module Spider
77
200
  end
78
201
  end
79
202
 
80
- def pre_update
203
+ def self.pre_update(specs, options={})
81
204
  end
82
205
 
83
206
  def self.post_setup(specs, options={})
@@ -89,7 +212,7 @@ module Spider
89
212
  options[:use_git] = true unless options[:use_git] == false
90
213
  specs = [specs] unless specs.is_a?(Array)
91
214
  pre_setup(specs, options)
92
- pre_update(specs, option)
215
+ pre_update(specs, options)
93
216
  specs.each do |spec|
94
217
  if spec.git_repo && options[:use_git]
95
218
  git_update(spec, home_path, options)
@@ -78,6 +78,11 @@ module Spider
78
78
  @home.instance_eval(File.read(init_file), init_file)
79
79
  end
80
80
 
81
+ init_apps
82
+ @init_done=true
83
+ end
84
+
85
+ def init_apps
81
86
  @apps.each do |name, mod|
82
87
  mod.app_init if mod.respond_to?(:app_init)
83
88
  end
@@ -87,7 +92,6 @@ module Spider
87
92
  GetText.bindtextdomain(mod.short_name)
88
93
  end
89
94
  end
90
- @init_done=true
91
95
  end
92
96
 
93
97
  def init_done?
@@ -175,9 +179,9 @@ module Spider
175
179
  @fssm_thread = Thread.new do
176
180
  monitor.run
177
181
  end
178
- Spider.logger.debug("Monitoring restart.txt")
182
+ Spider.logger.debug("Monitoring restart.txt") if Spider.logger
179
183
  else
180
- Spider.logger.debug("FSSM not installed, unable to monitor restart.txt")
184
+ Spider.logger.debug("FSSM not installed, unable to monitor restart.txt") if Spider.logger
181
185
  end
182
186
  trap('TERM'){ Spider.main_process_shutdown; exit }
183
187
  trap('INT'){ Spider.main_process_shutdown; exit }
@@ -314,6 +318,7 @@ module Spider
314
318
  @paths[:tmp] = File.join(root, 'tmp')
315
319
  @paths[:data] = File.join(root, 'data')
316
320
  @paths[:log] = File.join(@paths[:var], 'log')
321
+ @paths[:restart_file] = File.join(@paths[:tmp], 'restart.txt')
317
322
  @paths.each do |k, path|
318
323
  @paths[k] = File.expand_path(File.readlink(path)) if File.symlink?(path)
319
324
  end
@@ -422,6 +427,20 @@ module Spider
422
427
  return false
423
428
  end
424
429
 
430
+ def get_app_deps(apps, options={})
431
+ new_apps = apps.clone
432
+ specs = {}
433
+ init_base
434
+ while !new_apps.empty? && curr = new_apps.pop
435
+ raise "Could not find app #{curr}" unless Spider.home.apps[curr]
436
+ spec = Spider.home.apps[curr][:spec]
437
+ specs[curr] = spec
438
+ new_apps += spec.depends.reject{ |app| specs[app] }
439
+ new_apps += spec.depends_optional.reject{ |app| specs[app] } if options[:optional]
440
+ end
441
+ specs.keys
442
+ end
443
+
425
444
  def activate_apps(apps, specs=nil)
426
445
  require 'spiderfw/config/configuration_editor'
427
446
  init_base
@@ -448,7 +467,7 @@ module Spider
448
467
  apps.each do |a|
449
468
  sort.add(specs[a] ? specs[a] : a)
450
469
  end
451
- sort.tsort
470
+ sort.tsort.reject{ |a| a.nil? }
452
471
  end
453
472
 
454
473
  def load_configuration(path)
@@ -3,4 +3,7 @@
3
3
  <div class="error_description">
4
4
  _(We are sorry, but the required page was not found).
5
5
  </div>
6
+ <div class="link_back">
7
+ <a href="{ Spider.site }/{ Spider::ControllerMixins::HTTPMixin.base_url }">_(Return to the site)</a>
8
+ </div>
6
9
  </div>
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <tpl:asset type="css" src="css/error_page.css" />
4
+ <head>
5
+ <title>{ @error_msg }</title>
6
+ <script sp:each='@assets[:js] |script|' type="text/javascript" src="{ script }"></script>
7
+ <link sp:each='@assets[:css] |css_file|' rel='stylesheet' href='{ css_file }' />
8
+ </head>
9
+ <body>
10
+ <div id="header">
11
+ </div>
12
+ <div id="content">
13
+ <sp:yield />
14
+ </div>
15
+ </div>
16
+ </div>
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE HTML>
2
+ <html>
3
+ <tpl:asset type="css" src="css/error_page.css" />
4
+ <head>
5
+ <title>{ @error_msg }</title>
6
+ <script sp:each='@assets[:js] |script|' type="text/javascript" src="{ script }"></script>
7
+ <link sp:each='@assets[:css] |css_file|' rel='stylesheet' href='{ css_file }' />
8
+ </head>
9
+ <body>
10
+ <div id="header">
11
+ </div>
12
+ <div id="content">
13
+ <sp:yield />
14
+ </div>
15
+ </div>
16
+ </div>
@@ -0,0 +1,6 @@
1
+ <div>
2
+ <h3 class="error_message">_(Under maintenance)</h3>
3
+ <div class="error_description">
4
+ _(The server is currently under maintenance. Please come back shortly).
5
+ </div>
6
+ </div>
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spiderfw
3
3
  version: !ruby/object:Gem::Version
4
- hash: 11
4
+ hash: 9
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 6
9
- - 6
10
- version: 0.6.6
9
+ - 7
10
+ version: 0.6.7
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ivan Pirlik
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-07-19 00:00:00 +02:00
18
+ date: 2011-07-26 00:00:00 +02:00
19
19
  default_executable: spider
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -850,6 +850,7 @@ files:
850
850
  - apps/master/models/admin.rb
851
851
  - apps/master/models/command.rb
852
852
  - apps/master/models/customer.rb
853
+ - apps/master/models/event.rb
853
854
  - apps/master/models/installation.rb
854
855
  - apps/master/models/remote_log.rb
855
856
  - apps/master/models/resource.rb
@@ -935,6 +936,7 @@ files:
935
936
  - apps/servant/controllers/servant_controller.rb
936
937
  - apps/servant/Gemfile
937
938
  - apps/servant/lib/client.rb
939
+ - apps/servant/lib/commands_processor.rb
938
940
  - apps/servant/servant.appspec
939
941
  - apps/servant/servant.rb
940
942
  - apps/soap/_init.rb
@@ -1211,6 +1213,9 @@ files:
1211
1213
  - views/errors/404.shtml
1212
1214
  - views/errors/error.layout.shtml
1213
1215
  - views/errors/error_generic.shtml
1216
+ - views/errors/simple.layout.shtml
1217
+ - views/generic.layout.shtml
1218
+ - views/maintenance.shtml
1214
1219
  has_rdoc: true
1215
1220
  homepage: http://github.com/me/spider
1216
1221
  licenses: []