Skip to content

Commit c1a8556

Browse files
committed
Maintain un-processed usage event records
Allow consumer_guid to be passed into request for AppUsageEvent and ServiceUsageEvent records. This establishes a consumer of these events. Un-processed consumer records will be maintained by cloud controller. Registered consumers are automatically deleted if associated event is removed.
1 parent a4b02aa commit c1a8556

18 files changed

+420
-17
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
module VCAP::CloudController
2+
class AppUsageConsumerAccess < BaseAccess
3+
def create?(_object, _params=nil)
4+
admin_user?
5+
end
6+
7+
def read?(object)
8+
return @ok_read if instance_variable_defined?(:@ok_read)
9+
10+
@ok_read = admin_user? || admin_read_only_user? || global_auditor? || object_is_visible_to_user?(object, context.user)
11+
end
12+
13+
def read_for_update?(_object, _params=nil)
14+
admin_user?
15+
end
16+
17+
def can_remove_related_object?(object, params=nil)
18+
read_for_update?(object, params)
19+
end
20+
21+
def read_related_object_for_update?(object, params=nil)
22+
read_for_update?(object, params)
23+
end
24+
25+
def update?(_object, _params=nil)
26+
admin_user?
27+
end
28+
29+
def delete?(_object)
30+
admin_user?
31+
end
32+
33+
# These methods should be called first to determine if the user's token has the appropriate scope for the operation
34+
35+
def read_with_token?(_)
36+
admin_user? || admin_read_only_user? || has_read_scope? || global_auditor?
37+
end
38+
39+
def create_with_token?(_)
40+
admin_user? || has_write_scope?
41+
end
42+
43+
def read_for_update_with_token?(_)
44+
admin_user? || has_write_scope?
45+
end
46+
47+
def can_remove_related_object_with_token?(*)
48+
read_for_update_with_token?(*)
49+
end
50+
51+
def read_related_object_for_update_with_token?(*)
52+
read_for_update_with_token?(*)
53+
end
54+
55+
def update_with_token?(_)
56+
admin_user? || has_write_scope?
57+
end
58+
59+
def delete_with_token?(_)
60+
admin_user? || has_write_scope?
61+
end
62+
63+
def index_with_token?(_)
64+
admin_user? || admin_read_only_user?
65+
end
66+
67+
def index?(_object_class, _params=nil)
68+
admin_user? || admin_read_only_user?
69+
end
70+
71+
def reset?(_object_class)
72+
admin_user?
73+
end
74+
75+
def reset_with_token?(_object_class)
76+
admin_user?
77+
end
78+
end
79+
end
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
module VCAP::CloudController
2+
class ServiceUsageConsumerAccess < BaseAccess
3+
def create?(_object, _params=nil)
4+
admin_user?
5+
end
6+
7+
def read?(object)
8+
return @ok_read if instance_variable_defined?(:@ok_read)
9+
10+
@ok_read = admin_user? || admin_read_only_user? || global_auditor? || object_is_visible_to_user?(object, context.user)
11+
end
12+
13+
def read_for_update?(_object, _params=nil)
14+
admin_user?
15+
end
16+
17+
def can_remove_related_object?(object, params=nil)
18+
read_for_update?(object, params)
19+
end
20+
21+
def read_related_object_for_update?(object, params=nil)
22+
read_for_update?(object, params)
23+
end
24+
25+
def update?(_object, _params=nil)
26+
admin_user?
27+
end
28+
29+
def delete?(_object)
30+
admin_user?
31+
end
32+
33+
# These methods should be called first to determine if the user's token has the appropriate scope for the operation
34+
35+
def read_with_token?(_)
36+
admin_user? || admin_read_only_user? || has_read_scope? || global_auditor?
37+
end
38+
39+
def create_with_token?(_)
40+
admin_user? || has_write_scope?
41+
end
42+
43+
def read_for_update_with_token?(_)
44+
admin_user? || has_write_scope?
45+
end
46+
47+
def can_remove_related_object_with_token?(*)
48+
read_for_update_with_token?(*)
49+
end
50+
51+
def read_related_object_for_update_with_token?(*)
52+
read_for_update_with_token?(*)
53+
end
54+
55+
def update_with_token?(_)
56+
admin_user? || has_write_scope?
57+
end
58+
59+
def delete_with_token?(_)
60+
admin_user? || has_write_scope?
61+
end
62+
63+
def index_with_token?(_)
64+
admin_user? || admin_read_only_user?
65+
end
66+
67+
def index?(_object_class, _params=nil)
68+
admin_user? || admin_read_only_user?
69+
end
70+
71+
def reset?(_object_class)
72+
admin_user?
73+
end
74+
75+
def reset_with_token?(_object_class)
76+
admin_user?
77+
end
78+
end
79+
end

app/controllers/v3/app_usage_events_controller.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ def index
1111

1212
app_usage_events = AppUsageEventListFetcher.fetch_all(message, AppUsageEvent.dataset) if permission_queryer.can_read_globally?
1313

14+
if message.consumer_guid && message.after_guid&.first && permission_queryer.can_write_globally?
15+
begin
16+
consumer = AppUsageConsumer.find_or_create(consumer_guid: message.consumer_guid) do |c|
17+
c.last_processed_guid = message.after_guid.first
18+
end
19+
20+
consumer.update(last_processed_guid: message.after_guid.first) if !consumer.new? && consumer.last_processed_guid != message.after_guid.first
21+
rescue Sequel::ValidationFailed => e
22+
unprocessable!(e.message)
23+
rescue Sequel::Error
24+
error!('Failed to update consumer tracking', 500)
25+
end
26+
end
27+
1428
render status: :ok, json: Presenters::V3::PaginatedListPresenter.new(
1529
presenter: Presenters::V3::AppUsageEventPresenter,
1630
paginated_result: SequelPaginator.new.get_page(app_usage_events, message.try(:pagination_options)),

app/controllers/v3/service_usage_events_controller.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,20 @@ def index
1111

1212
service_usage_events = ServiceUsageEventListFetcher.fetch_all(message, ServiceUsageEvent.dataset) if permission_queryer.can_read_globally?
1313

14+
if message.consumer_guid && message.after_guid&.first && permission_queryer.can_write_globally?
15+
begin
16+
consumer = ServiceUsageConsumer.find_or_create(consumer_guid: message.consumer_guid) do |c|
17+
c.last_processed_guid = message.after_guid.first
18+
end
19+
20+
consumer.update(last_processed_guid: message.after_guid.first) if !consumer.new? && consumer.last_processed_guid != message.after_guid.first
21+
rescue Sequel::ValidationFailed => e
22+
unprocessable!(e.message)
23+
rescue Sequel::Error
24+
error!('Failed to update consumer tracking', 500)
25+
end
26+
end
27+
1428
render status: :ok, json: Presenters::V3::PaginatedListPresenter.new(
1529
presenter: Presenters::V3::ServiceUsageEventPresenter,
1630
paginated_result: SequelPaginator.new.get_page(service_usage_events, message.try(:pagination_options)),

app/messages/app_usage_events_list_message.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22

33
module VCAP::CloudController
44
class AppUsageEventsListMessage < ListMessage
5-
register_allowed_keys [
6-
:after_guid
5+
register_allowed_keys %i[
6+
after_guid
7+
consumer_guid
78
]
89

910
validates_with NoAdditionalParamsValidator
@@ -19,7 +20,7 @@ def valid_order_by_values
1920
end
2021

2122
def self.from_params(params)
22-
super(params, %w[after_guid])
23+
super(params, %w[after_guid consumer_guid])
2324
end
2425
end
2526
end

app/messages/service_usage_events_list_message.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ class ServiceUsageEventsListMessage < ListMessage
66
after_guid
77
service_instance_types
88
service_offering_guids
9+
consumer_guid
910
]
1011

1112
validates_with NoAdditionalParamsValidator
@@ -24,7 +25,7 @@ def valid_order_by_values
2425
end
2526

2627
def self.from_params(params)
27-
super(params, %w[after_guid service_instance_types service_offering_guids])
28+
super(params, %w[after_guid service_instance_types service_offering_guids consumer_guid])
2829
end
2930
end
3031
end

app/models.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
require 'models/runtime/security_group'
1919
require 'models/runtime/security_groups_space'
2020
require 'models/runtime/staging_security_groups_space'
21+
require 'models/runtime/app_usage_consumer'
2122
require 'models/runtime/app_usage_event'
2223
require 'models/runtime/auto_detection_buildpack'
2324
require 'models/runtime/app_event'
@@ -141,6 +142,7 @@
141142
require 'models/services/service_plan_visibility'
142143
require 'models/services/service_plan_annotation_model'
143144
require 'models/services/service_plan_label_model'
145+
require 'models/services/service_usage_consumer'
144146
require 'models/services/service_usage_event'
145147
require 'models/services/service_key'
146148
require 'models/services/service_key_label_model'
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module VCAP::CloudController
2+
class AppUsageConsumer < Sequel::Model
3+
plugin :validation_helpers
4+
5+
many_to_one :last_processed_event,
6+
class: 'VCAP::CloudController::AppUsageEvent',
7+
key: :last_processed_guid,
8+
primary_key: :guid
9+
10+
def validate
11+
validates_presence %i[consumer_guid last_processed_guid]
12+
validates_unique :consumer_guid
13+
validates_max_length 255, :consumer_guid, message: 'must be less than 255 characters'
14+
end
15+
16+
def last_processed_guid=(guid)
17+
self[:last_processed_guid] = guid
18+
end
19+
20+
def last_processed_guid
21+
self[:last_processed_guid]
22+
end
23+
24+
export_attributes :consumer_guid, :last_processed_guid
25+
end
26+
end

app/models/runtime/app_usage_event.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@ module VCAP::CloudController
22
class AppUsageEvent < Sequel::Model
33
plugin :serialization
44

5+
one_to_many :consumers,
6+
class: 'VCAP::CloudController::AppUsageConsumer',
7+
key: :last_processed_guid,
8+
primary_key: :guid
9+
10+
add_association_dependencies consumers: :destroy
11+
512
export_attributes :state, :previous_state,
613
:memory_in_mb_per_instance, :previous_memory_in_mb_per_instance,
714
:instance_count, :previous_instance_count,
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
module VCAP::CloudController
2+
class ServiceUsageConsumer < Sequel::Model
3+
plugin :validation_helpers
4+
5+
many_to_one :last_processed_event,
6+
class: 'VCAP::CloudController::ServiceUsageEvent',
7+
key: :last_processed_guid,
8+
primary_key: :guid
9+
10+
def validate
11+
validates_presence %i[consumer_guid last_processed_guid]
12+
validates_unique :consumer_guid
13+
validates_max_length 255, :consumer_guid, message: 'must be less than 255 characters'
14+
end
15+
16+
def last_processed_guid=(guid)
17+
self[:last_processed_guid] = guid
18+
end
19+
20+
def last_processed_guid
21+
self[:last_processed_guid]
22+
end
23+
24+
export_attributes :consumer_guid, :last_processed_guid
25+
end
26+
end

0 commit comments

Comments
 (0)