Skip to content
This repository was archived by the owner on Jun 4, 2021. It is now read-only.

Commit daad0cd

Browse files
author
Scott McClellan
committed
Fix event ordering
The ordering of events, whether by events, node log, hook log, or commands, previously showed events in counter-intuitive order. This puts the latest entry at the bottom, which should be most useful. Additionally, whenever a limited "fact" collection is requested, it will limit from the bottom up. This means `razor events --limit 5` will show the 5 most recent events, with the most recent at the bottom. Fixes https://tickets.puppetlabs.com/browse/RAZOR-734
1 parent ad49bb4 commit daad0cd

File tree

6 files changed

+87
-33
lines changed

6 files changed

+87
-33
lines changed

app.rb

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,8 @@ def render_template(name)
558558
#
559559
# @todo danielp 2013-06-26: this should be some sort of discovery, not a
560560
# hand-coded list, but ... it will do, for now.
561-
COLLECTIONS = [:brokers, :repos, :tags, :policies,
562-
[:nodes, {'start' => {"type" => "number"}, 'limit' => {"type" => "number"}}], :tasks, :commands,
561+
COLLECTIONS = [:brokers, :repos, :tags, :policies, [:nodes, {'start' => {"type" => "number"}, 'limit' => {"type" => "number"}}],
562+
:tasks, :commands,
563563
[:events, {'start' => {"type" => "number"}, 'limit' => {"type" => "number"}}], :hooks]
564564

565565
#
@@ -692,8 +692,7 @@ def render_template(name)
692692
end
693693

694694
get '/api/collections/commands' do
695-
collection_view Razor::Data::Command.order(:submitted_at).reverse,
696-
'commands'
695+
collection_view Razor::Data::Command.order(:submitted_at).order(:id), 'commands'
697696
end
698697

699698
get '/api/collections/commands/:id' do
@@ -708,47 +707,73 @@ def render_template(name)
708707
end
709708

710709
get '/api/collections/events' do
711-
check_permissions!("query:events")
710+
limit = params[:limit]
711+
start = params[:start]
712+
713+
raise TypeError, _('limit must be a number, but was %{limit}') %
714+
{limit: limit} unless limit.to_i.to_s == limit or limit.nil?
715+
raise TypeError, _('start must be a number, but was %{start}') %
716+
{start: start} unless start.to_i.to_s == start or start.nil?
717+
limit = Integer(limit) if limit
718+
start = Integer(start) if start
712719

713720
# Need to also order by ID here in case the granularity of timestamp is
714721
# not enough to maintain a consistent ordering.
715-
cursor = Razor::Data::Event.order(:timestamp).order(:id).reverse
716-
collection_view cursor, 'events', limit: params[:limit], start: params[:start]
722+
cursor = Razor::Data::Event.order(:timestamp).order(:id)
723+
collection_view cursor, 'events', limit: limit, start: start, facts: true
717724
end
718725

719726
get '/api/collections/events/:id' do
720727
params[:id] =~ /[0-9]+/ or error 400, :error => _("id must be a number but was %{id}") % {id: params[:id]}
721-
check_permissions!("query:events:#{params[:id]}")
728+
722729
event = Razor::Data::Event[:id => params[:id]] or
723730
error 404, :error => _("no event matched id=%{id}") % {id: params[:id]}
724731
event_hash(event).to_json
725732
end
726733

727734
get '/api/collections/hooks' do
728-
check_permissions!("query:hooks")
729-
730735
collection_view Razor::Data::Hook, 'hooks'
731736
end
732737

733738
get '/api/collections/hooks/:name' do
734-
check_permissions!("query:hooks:#{params[:name]}")
735739
hook = Razor::Data::Hook[:name => params[:name]] or
736740
error 404, :error => _("no hook matched name=%{name}") % {name: params[:name]}
737741
hook_hash(hook).to_json
738742
end
739743

740744
get '/api/collections/hooks/:name/log' do
741-
check_permissions!("query:hooks:#{params[:name]}")
745+
check_permissions!("query:hooks:#{params[:name]}:log")
746+
limit = params[:limit]
747+
start = params[:start]
748+
749+
raise TypeError, _('limit must be a number, but was %{limit}') %
750+
{limit: limit} unless limit.to_i.to_s == limit or limit.nil?
751+
raise TypeError, _('start must be a number, but was %{start}') %
752+
{start: start} unless start.to_i.to_s == start or start.nil?
753+
limit = Integer(limit) if limit
754+
start = Integer(start) if start
755+
742756
hook = Razor::Data::Hook[:name => params[:name]] or
743757
error 404, :error => _("no hook matched name=%{name}") % {name: params[:name]}
744758
{
745759
"spec" => spec_url("collections", "hooks", "log"),
746-
"items" => hook.log(limit: params[:limit], start: params[:start])
760+
"items" => hook.log(limit: limit, start: start)
747761
}.to_json
748762
end
749763

750764
get '/api/collections/nodes' do
751-
collection_view Razor::Data::Node.search(params).order(:id), 'nodes', limit: params[:limit], start: params[:start]
765+
limit = params[:limit]
766+
start = params[:start]
767+
768+
raise TypeError, _('limit must be a number, but was %{limit}') %
769+
{limit: limit} unless limit.to_i.to_s == limit or limit.nil?
770+
raise TypeError, _('start must be a number, but was %{start}') %
771+
{start: start} unless start.to_i.to_s == start or start.nil?
772+
limit = Integer(limit) if limit
773+
start = Integer(start) if start
774+
775+
collection_view Razor::Data::Node.search(params).order(:id), 'nodes',
776+
limit: limit, start: start
752777
end
753778

754779
get '/api/collections/nodes/:name' do
@@ -760,6 +785,16 @@ def render_template(name)
760785
get '/api/collections/nodes/:name/log' do
761786
check_permissions!("query:nodes:#{params[:name]}:log")
762787

788+
limit = params[:limit]
789+
start = params[:start]
790+
791+
raise TypeError, _('limit must be a number, but was %{limit}') %
792+
{limit: limit} unless limit.to_i.to_s == limit or limit.nil?
793+
raise TypeError, _('start must be a number, but was %{start}') %
794+
{start: start} unless start.to_i.to_s == start or start.nil?
795+
limit = Integer(limit) if limit
796+
start = Integer(start) if start
797+
763798
# @todo lutter 2013-08-20: There are no tests for this handler
764799
# @todo lutter 2013-08-20: Do we need to send the log through a view ?
765800
node = Razor::Data::Node[:name => params[:name]] or
@@ -769,7 +804,7 @@ def render_template(name)
769804
# view worthwhile without extra querying.
770805
{
771806
"spec" => spec_url("collections", "nodes", "log"),
772-
"items" => node.log(limit: params[:limit], start: params[:start])
807+
"items" => node.log(limit: limit, start: start)
773808
}.to_json
774809
end
775810

lib/razor/data/hook.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,8 +149,15 @@ def validate
149149
end
150150

151151
def log(params = {})
152-
cursor = Razor::Data::Event.order(:timestamp).order(:id).reverse.
153-
where(hook_id: id).limit(params[:limit], params[:start])
152+
cursor = Razor::Data::Event.order(:timestamp).order(:id).
153+
where(hook_id: id)
154+
total = cursor.count if cursor.respond_to?(:count)
155+
if params[:start].nil? and params[:limit] and !total.nil?
156+
# We have a request for a limited list of facts without a starting
157+
# value. Take from the end so the latest entries are included.
158+
params[:start] = [total - params[:limit], 0].max
159+
end
160+
cursor = cursor.limit(params[:limit], params[:start])
154161
cursor.map do |log|
155162
{ 'timestamp' => log.timestamp.xmlschema, 'node' => (log.node ? log.node.name : nil),
156163
'policy' => (log.policy ? log.policy.name : nil)}.update(log.entry).delete_if { |_,v| v.nil? }

lib/razor/data/node.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,15 @@ def shortname
136136
# +log_append+ each entry will also contain the +timestamp+ in ISO8601
137137
# format
138138
def log(params = {})
139-
cursor = Razor::Data::Event.order(:timestamp).order(:id).reverse.
140-
where(node_id: id).limit(params[:limit], params[:start])
139+
cursor = Razor::Data::Event.order(:timestamp).order(:id).
140+
where(node_id: id)
141+
total = cursor.count if cursor.respond_to?(:count)
142+
if params[:start].nil? and params[:limit] and !total.nil?
143+
# We have a request for a limited list of facts without a starting
144+
# value. Take from the end so the latest entries are included.
145+
params[:start] = [total - params[:limit], 0].max
146+
end
147+
cursor = cursor.limit(params[:limit], params[:start])
141148
cursor.map do |log|
142149
{ 'timestamp' => log.timestamp.xmlschema,
143150
'severity' => log.severity, }.update(log.entry)

lib/razor/view.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,11 @@ def hook_hash(hook)
216216
def collection_view(cursor, name, args = {})
217217
perm = "query:#{name}"
218218
total = cursor.count if cursor.respond_to?(:count)
219+
if args[:facts] and args[:start].nil? and args[:limit] and !total.nil?
220+
# We have a request for a limited list of facts without a starting
221+
# value. Take from the end so the latest entries are included.
222+
args[:start] = [total - args[:limit], 0].max
223+
end
219224
# This catches the case where a non-Sequel class is passed in.
220225
cursor = cursor.all if cursor.is_a?(Class) and !cursor.respond_to?(:cursor)
221226
cursor = cursor.limit(args[:limit], args[:start]) if cursor.respond_to?(:limit)

spec/app/api_spec.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ def validate!(schema, json)
848848
let :node do Fabricate(:node) end
849849
let :msgs do [] end
850850
before :each do
851-
5.times { msgs.unshift(Fabricate(:event, node: node).entry[:msg]) }
851+
5.times { msgs.push(Fabricate(:event, node: node).entry[:msg]) }
852852
end
853853
it "should show log" do
854854
get "/api/collections/nodes/#{node.name}/log"
@@ -860,7 +860,7 @@ def validate!(schema, json)
860860
get "/api/collections/nodes/#{node.name}/log?limit=2"
861861
last_response.status.should == 200
862862

863-
last_response.json['items'].map {|e| e['msg']}.should == msgs[0..1]
863+
last_response.json['items'].map {|e| e['msg']}.should == msgs[3..4]
864864
end
865865
it "should show limited log with offset" do
866866
get "/api/collections/nodes/#{node.name}/log?limit=2&start=2"
@@ -1115,7 +1115,7 @@ def validate!(schema, json)
11151115
let :hook do Fabricate(:hook) end
11161116
let :msgs do [] end
11171117
before :each do
1118-
5.times { msgs.unshift(Fabricate(:event, hook: hook).entry[:msg]) }
1118+
5.times { msgs.push(Fabricate(:event, hook: hook).entry[:msg]) }
11191119
end
11201120
it "should show log" do
11211121
get "/api/collections/hooks/#{URI.escape(hook.name)}/log"
@@ -1127,7 +1127,7 @@ def validate!(schema, json)
11271127
get "/api/collections/hooks/#{URI.escape(hook.name)}/log?limit=2"
11281128
last_response.status.should == 200
11291129

1130-
last_response.json['items'].map {|e| e['msg']}.should == msgs[0..1]
1130+
last_response.json['items'].map {|e| e['msg']}.should == msgs[3..4]
11311131
end
11321132
it "should show limited log with offset" do
11331133
get "/api/collections/hooks/#{URI.escape(hook.name)}/log?limit=2&start=2"
@@ -1280,13 +1280,13 @@ def validate!(schema, json)
12801280
events = last_response.json['items']
12811281
events.should be_an_instance_of Array
12821282
events.count.should == 1
1283-
events.first['name'].should == names.last
1283+
events.last['name'].should == names.last
12841284
last_response.json['total'].should == 3
12851285
validate! ObjectRefCollectionSchema, last_response.body
12861286
end
12871287
it "should allow windowing of results" do
12881288
names = []
1289-
6.times { names.unshift Fabricate(:event).name }
1289+
6.times { names.push Fabricate(:event).name }
12901290
get "/api/collections/events?limit=2&start=2"
12911291

12921292
last_response.status.should == 200
@@ -1299,7 +1299,7 @@ def validate!(schema, json)
12991299
end
13001300
it "should allow just an offset" do
13011301
names = []
1302-
6.times { names.unshift Fabricate(:event).name }
1302+
6.times { names.push Fabricate(:event).name }
13031303
get "/api/collections/events?start=2"
13041304

13051305
last_response.status.should == 200

spec/data/node_spec.rb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -219,12 +219,12 @@ def canonicalize(hw_info)
219219

220220
n = Node[node.id]
221221
n.log.size.should == 2
222-
n.log[0]["msg"].should == "M2"
223-
n.log[0]["severity"].should == "error"
224-
n.log[0]["timestamp"].should_not be_nil
225-
n.log[1]["msg"].should == "M1"
226-
n.log[1]["severity"].should == "info"
222+
n.log[1]["msg"].should == "M2"
223+
n.log[1]["severity"].should == "error"
227224
n.log[1]["timestamp"].should_not be_nil
225+
n.log[0]["msg"].should == "M1"
226+
n.log[0]["severity"].should == "info"
227+
n.log[0]["timestamp"].should_not be_nil
228228
end
229229

230230
describe "hostname" do
@@ -295,8 +295,8 @@ def canonicalize(hw_info)
295295
node.modified?.should be_false
296296

297297
node.policy.should == policy
298-
node.log.first["action"].should == "reboot"
299-
node.log.first["policy"].should == policy.name
298+
node.log.last["action"].should == "reboot"
299+
node.log.last["policy"].should == policy.name
300300
end
301301

302302
it "should refuse to bind to a policy if any tag raises an error" do

0 commit comments

Comments
 (0)