https://www.aeolusproject.org/redmine/issues/3273
REST api to turn the rufus scheduler on (:new) and off (:destroy)
and to check its status (:index).
A singleton class JobScheduler encapsulates the rufus scheduler
so that only a single scheduler instance runs at any time.
Only users who have the ROLE view and modify permissions may
control the scheduler.
---
aeolus-conductor.spec.in | 2 +
src/app/controllers/job_scheduler_controller.rb | 45 +++++++++
src/app/views/job_scheduler/destroy.xml.haml | 2 +
src/app/views/job_scheduler/index.xml.haml | 2 +
src/app/views/job_scheduler/new.xml.haml | 2 +
src/config/routes.rb | 2 +
src/lib/job_scheduler.rb | 94 ++++++++++++++++++++
.../controllers/job_scheduler_controller_spec.rb | 84 +++++++++++++++++
8 files changed, 233 insertions(+), 0 deletions(-)
create mode 100644 src/app/controllers/job_scheduler_controller.rb
create mode 100644 src/app/views/job_scheduler/destroy.xml.haml
create mode 100644 src/app/views/job_scheduler/index.xml.haml
create mode 100644 src/app/views/job_scheduler/new.xml.haml
create mode 100644 src/lib/job_scheduler.rb
create mode 100644 src/spec/controllers/job_scheduler_controller_spec.rb
diff --git a/aeolus-conductor.spec.in b/aeolus-conductor.spec.in
index a40d517..6cca32f 100644
--- a/aeolus-conductor.spec.in
+++ b/aeolus-conductor.spec.in
@@ -47,6 +47,7 @@ Requires: rubygem(oauth)
Requires: rubygem(rake)
Requires: rubygem(delayed_job)>= 2.1.4
Requires: rubygem(paranoia)
+Requires: rubygem(rufus-scheduler)
Requires: postgresql
Requires: postgresql-server
Requires: system-logos
@@ -189,6 +190,7 @@ haml="app/views/hardware_profiles app/views/realm_mappings \
app/views/deployables app/views/catalogs \
app/views/provider_types app/views/api/images \
app/views/config_servers app/views/provider_realms \
+ app/views/job_scheduler \
app/views/logs \
app/views/api/hooks \
app/views/api \
diff --git a/src/app/controllers/job_scheduler_controller.rb
b/src/app/controllers/job_scheduler_controller.rb
new file mode 100644
index 0000000..b1a2701
--- /dev/null
+++ b/src/app/controllers/job_scheduler_controller.rb
@@ -0,0 +1,45 @@
+#
+# Copyright 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#
http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'job_scheduler'
+
+class JobSchedulerController< ApplicationController
+ before_filter :require_user_api
+ respond_to :xml
+ layout :false
+
+ # GET /jobscheduler
+ # GET /jobscheduler.xml
+ def index
+ require_privilege(Privilege::PERM_VIEW)
+ respond_with(JobScheduler.activated?)
+ end
+
+ # GET /jobscheduler/new
+ # GET /jobscheduler/new.xml
+ def new
+ require_privilege(Privilege::PERM_SET)
+ respond_with(JobScheduler.start)
+ end
+
+ # DELETE /jobscheduler/1
+ # DELETE /jobscheduler/1.xml
+ def destroy
+ require_privilege(Privilege::PERM_SET)
+ respond_with(JobScheduler.stop)
+ end
+
+end
diff --git a/src/app/views/job_scheduler/destroy.xml.haml
b/src/app/views/job_scheduler/destroy.xml.haml
new file mode 100644
index 0000000..18e796d
--- /dev/null
+++ b/src/app/views/job_scheduler/destroy.xml.haml
@@ -0,0 +1,2 @@
+!!! XML
+%activated=JobScheduler.activated?
\ No newline at end of file
diff --git a/src/app/views/job_scheduler/index.xml.haml
b/src/app/views/job_scheduler/index.xml.haml
new file mode 100644
index 0000000..b5c75d6
--- /dev/null
+++ b/src/app/views/job_scheduler/index.xml.haml
@@ -0,0 +1,2 @@
+!!! XML
+%activated=JobScheduler.activated?
diff --git a/src/app/views/job_scheduler/new.xml.haml
b/src/app/views/job_scheduler/new.xml.haml
new file mode 100644
index 0000000..18e796d
--- /dev/null
+++ b/src/app/views/job_scheduler/new.xml.haml
@@ -0,0 +1,2 @@
+!!! XML
+%activated=JobScheduler.activated?
\ No newline at end of file
diff --git a/src/config/routes.rb b/src/config/routes.rb
index 265f752..518b013 100644
--- a/src/config/routes.rb
+++ b/src/config/routes.rb
@@ -238,6 +238,8 @@ Conductor::Application.routes.draw do
resources :provider_images
end
+ resources :job_scheduler, :only => [:index, :new, :destroy]
+
get 'api', :controller => 'api/entrypoint', :action =>
'index'
namespace :api do
resources :images do
diff --git a/src/lib/job_scheduler.rb b/src/lib/job_scheduler.rb
new file mode 100644
index 0000000..1050ecd
--- /dev/null
+++ b/src/lib/job_scheduler.rb
@@ -0,0 +1,94 @@
+#
+# Copyright 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#
http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'curb'
+require 'rufus-scheduler'
+
+class JobScheduler
+
+ @@scheduler = nil
+
+ def self.initialize
+ self.start
+ end
+
+ def self.start
+ if @(a)scheduler.nil?
+ @@scheduler = Rufus::Scheduler::PlainScheduler.start_new
+ schedule_tasks(@@scheduler)
+ end
+ end
+
+ def self.stop
+ if @@scheduler
+ @(a)scheduler.stop
+ @@scheduler = nil
+ end
+ end
+
+ def self.activated?
+ if @@scheduler
+ true
+ else
+ false
+ end
+ end
+
+ def self.status_via_http(login, password, hostname)
+ curl = self.curl_request(login, password)
+ curl.url = job_scheduler_url(hostname, '')
+ curl.http_get
+ curl.body_str.to_s
+ end
+
+ def self.start_via_http(login, password, hostname)
+ curl = self.curl_request(login, password)
+ curl.url = job_scheduler_url(hostname, 'new')
+ curl.http_get
+ curl.body_str.to_s
+ end
+
+ def self.stop_via_http(login, password, hostname)
+ curl = self.curl_request(login, password)
+ curl.url = job_scheduler_url(hostname, '1')
+ curl.http_delete
+ curl.body_str.to_s
+ end
+
+ private
+
+ def self.schedule_tasks(scheduler)
+ scheduler.every("1m") do
+ puts "job scheduler is running"
+ end
+ end
+
+ def self.job_scheduler_url(hostname, suffix)
+ # TODO: is there a better way to generate this url?
+ url =
"https://#{hostname}/conductor/#{JobSchedulerController.controller_path}/#{suffix}"
+ end
+
+ def self.curl_request(login, password)
+ curl = Curl::Easy.new
+ curl.username = login
+ curl.password = password
+ curl.headers['HTTP_ACCEPT'] = 'application/xml'
+ curl.headers['CONTENT_TYPE'] = 'application/xml'
+ curl.http_auth_types = :basic
+ return curl
+ end
+
+end
diff --git a/src/spec/controllers/job_scheduler_controller_spec.rb
b/src/spec/controllers/job_scheduler_controller_spec.rb
new file mode 100644
index 0000000..75726ec
--- /dev/null
+++ b/src/spec/controllers/job_scheduler_controller_spec.rb
@@ -0,0 +1,84 @@
+#
+# Copyright 2012 Red Hat, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#
http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'spec_helper'
+
+describe JobSchedulerController do
+ render_views
+
+ context "when authenticated as admin" do
+
+ before(:each) do
+ @admin_permission = FactoryGirl.create :admin_permission
+ @admin = @admin_permission.user
+ mock_warden(@admin)
+ end
+
+ describe "scheduler controls" do
+
+ it "scheduler status from 'GET index'" do
+ send_and_accept_xml
+ get :index
+ response.should be_success
+ response.body.strip.should ==
"<activated>false</activated>"
+ end
+
+ it "turn on scheduler by 'GET new'" do
+ send_and_accept_xml
+ get :new
+ response.should be_success
+ response.body.strip.should ==
"<activated>true</activated>"
+ end
+
+ it "turn off scheduler by 'POST destroy'" do
+ send_and_accept_xml
+ post :destroy, :id => 1
+ response.should be_success
+ response.body.strip.should ==
"<activated>false</activated>"
+ end
+
+ it "turn scheduler on and then off" do
+ send_and_accept_xml
+ get :index
+ response.should be_success
+ response.body.strip.should ==
"<activated>false</activated>"
+ get :new
+ response.should be_success
+ response.body.strip.should ==
"<activated>true</activated>"
+ post :destroy, :id => 1
+ response.should be_success
+ response.body.strip.should ==
"<activated>false</activated>"
+ end
+ end
+ end
+
+ context "when not authenticated as admin" do
+
+ before(:each) do
+ @non_admin_permission = FactoryGirl.create :pool_user_permission
+ @user = @non_admin_permission.user
+ mock_warden(@user)
+ end
+
+ it "requests should be denied" do
+ send_and_accept_xml
+ get :index
+ response.should_not be_success
+ end
+
+ end
+
+end
Hi Richard,
based on plans from last week (DC is going to implement some kind of
Cloud State app), I'm not sure for what purposes we will need rufus
scheduler? Instances/realms would be potentially handled by the Cloud
State app (though nothing is confirmed yet), and remaining candidate for
scheduler was LDAP sync which we finally not gonna do too. Is there some
other usage of the scheduler?
Jan