pagerduty-sdk 1.0.0

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.
Files changed (56) hide show
  1. checksums.yaml +7 -0
  2. data/.DS_Store +0 -0
  3. data/.git/HEAD +1 -0
  4. data/.git/config +13 -0
  5. data/.git/description +1 -0
  6. data/.git/hooks/applypatch-msg.sample +15 -0
  7. data/.git/hooks/commit-msg.sample +24 -0
  8. data/.git/hooks/post-update.sample +8 -0
  9. data/.git/hooks/pre-applypatch.sample +14 -0
  10. data/.git/hooks/pre-commit.sample +50 -0
  11. data/.git/hooks/pre-push.sample +53 -0
  12. data/.git/hooks/pre-rebase.sample +169 -0
  13. data/.git/hooks/prepare-commit-msg.sample +36 -0
  14. data/.git/hooks/update.sample +128 -0
  15. data/.git/index +0 -0
  16. data/.git/info/exclude +6 -0
  17. data/.git/logs/HEAD +1 -0
  18. data/.git/logs/refs/heads/master +1 -0
  19. data/.git/logs/refs/remotes/origin/HEAD +1 -0
  20. data/.git/objects/pack/pack-ef303a32b278847aabbf3023e493ea7a4ca5888f.idx +0 -0
  21. data/.git/objects/pack/pack-ef303a32b278847aabbf3023e493ea7a4ca5888f.pack +0 -0
  22. data/.git/packed-refs +2 -0
  23. data/.git/refs/heads/master +1 -0
  24. data/.git/refs/remotes/origin/HEAD +1 -0
  25. data/.gitignore +18 -0
  26. data/LICENSE +20 -0
  27. data/README.md +4 -0
  28. data/lib/.DS_Store +0 -0
  29. data/lib/.yardoc/checksums +18 -0
  30. data/lib/.yardoc/object_types +0 -0
  31. data/lib/.yardoc/objects/root.dat +0 -0
  32. data/lib/.yardoc/proxy_types +0 -0
  33. data/lib/pagerduty/.DS_Store +0 -0
  34. data/lib/pagerduty/core.rb +12 -0
  35. data/lib/pagerduty/models/agent.rb +5 -0
  36. data/lib/pagerduty/models/alert.rb +10 -0
  37. data/lib/pagerduty/models/assigneduser.rb +8 -0
  38. data/lib/pagerduty/models/channels.rb +44 -0
  39. data/lib/pagerduty/models/escalationpolicies.rb +127 -0
  40. data/lib/pagerduty/models/incident.rb +74 -0
  41. data/lib/pagerduty/models/laststatuschangeby.rb +9 -0
  42. data/lib/pagerduty/models/log_entry.rb +22 -0
  43. data/lib/pagerduty/models/maintenance_window.rb +66 -0
  44. data/lib/pagerduty/models/note.rb +9 -0
  45. data/lib/pagerduty/models/notification.rb +7 -0
  46. data/lib/pagerduty/models/report.rb +54 -0
  47. data/lib/pagerduty/models/resolvedbyuser.rb +9 -0
  48. data/lib/pagerduty/models/schedule.rb +109 -0
  49. data/lib/pagerduty/models/service.rb +9 -0
  50. data/lib/pagerduty/models/services.rb +53 -0
  51. data/lib/pagerduty/models/triggersummarydata.rb +6 -0
  52. data/lib/pagerduty/models/user.rb +74 -0
  53. data/lib/pagerduty/pagerduty.rb +366 -0
  54. data/lib/pagerduty.rb +31 -0
  55. data/pagerduty-sdk.gemspec +26 -0
  56. metadata +141 -0
@@ -0,0 +1,10 @@
1
+ class Alert
2
+ include Virtus.model
3
+
4
+ attribute :id
5
+ attribute :type
6
+ attribute :started_at
7
+ attribute :user, Pagerduty::User
8
+ attribute :address
9
+
10
+ end
@@ -0,0 +1,8 @@
1
+ class AssignedUser
2
+ include Virtus.model
3
+
4
+ attribute :id
5
+ attribute :name
6
+ attribute :email
7
+ attribute :html_url
8
+ end
@@ -0,0 +1,44 @@
1
+ class Nagios
2
+ include Virtus.model
3
+
4
+ attribute :type
5
+ attribute :summary
6
+ attribute :host
7
+ attribute :service
8
+ attribute :state
9
+ attribute :details
10
+ end
11
+
12
+ class Api
13
+ include Virtus.model
14
+
15
+ attribute :type
16
+ attribute :summary
17
+ attribute :service_key
18
+ attribute :description
19
+ attribute :incident_key
20
+ attribute :details
21
+ end
22
+
23
+ class Email
24
+ include Virtus.model
25
+
26
+ attribute :type
27
+ attribute :summary
28
+ attribute :to
29
+ attribute :from
30
+ attribute :subject
31
+ attribute :body
32
+ attribute :content_type
33
+ attribute :raw_url
34
+ attribute :html_url
35
+ end
36
+
37
+ class WebTrigger
38
+ include Virtus.model
39
+
40
+ attribute :type
41
+ attribute :summary
42
+ attribute :subject
43
+ attribute :details
44
+ end
@@ -0,0 +1,127 @@
1
+ class RuleObject
2
+ include Virtus.model
3
+
4
+ attribute :id
5
+ attribute :name
6
+ attribute :type
7
+ attribute :email
8
+ attribute :time_zone
9
+ attribute :color
10
+
11
+ end
12
+
13
+ class EscalationService
14
+ include Virtus.model
15
+
16
+ attribute :id
17
+ attribute :name
18
+ attribute :service_url
19
+ attribute :service_key
20
+ attribute :auto_resolve_timeout
21
+ attribute :acknowledgement_timeout
22
+ attribute :created_at
23
+ attribute :deleted_at
24
+ attribute :status
25
+ attribute :last_incident_timestamp
26
+ attribute :email_incident_creation
27
+ attribute :incident_counts
28
+ attribute :email_filter_mode
29
+ attribute :type
30
+ end
31
+
32
+ class EscalationRule < Pagerduty
33
+ include Virtus.model
34
+
35
+ attribute :id
36
+ attribute :escalation_delay_in_minutes
37
+ attribute :rule_object, RuleObject
38
+
39
+ def hashify
40
+ self.attributes.inject({}) { |attrs, (k,v)|
41
+ v.class == RuleObject ? attrs[k] = v.to_hash : attrs[k] = v
42
+ attrs
43
+ }
44
+ end
45
+
46
+ def parent_policy
47
+ escalation_policies.detect { |policy|
48
+ policy.escalation_rules.detect { |p| p.id == self.id }
49
+ }
50
+ end
51
+
52
+ def delete
53
+ res = curl({
54
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/escalation_policies/#{parent_policy.id}/escalation_rules/#{self.id}",
55
+ method: 'DELETE'
56
+ })
57
+
58
+ res.code == '200' ? 'Successfully deleted' : JSON.parse(res.body)
59
+ end
60
+
61
+ def save
62
+ self.attributes = JSON.parse(curl({
63
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/escalation_policies/#{parent_policy.id}/escalation_rules/#{self.id}",
64
+ data: self.hashify,
65
+ method: 'PUT'
66
+ }).body)['escalation_rule']
67
+ end
68
+
69
+ end
70
+
71
+ class EscalationPolicy < Pagerduty
72
+ include Virtus.model
73
+
74
+ attribute :id
75
+ attribute :name
76
+ attribute :description
77
+ attribute :escalation_rules, Array[EscalationRule]
78
+ attribute :services, Set[EscalationService]
79
+ attribute :num_loops
80
+
81
+ def save
82
+ self.escalation_rules = self.escalation_rules.map { |rule|
83
+ rule.class == EscalationRule ? rule.hashify : rule
84
+ }
85
+
86
+ saved_policy = EscalationPolicy.new(JSON.parse(curl({
87
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/escalation_policies/#{self.id}",
88
+ data: { escalation_policy: self.attributes },
89
+ method: 'PUT'
90
+ }).body)['escalation_policy'])
91
+
92
+ self.attributes = saved_policy.attributes
93
+ end
94
+
95
+ def delete
96
+ res = curl({
97
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/escalation_policies/#{self.id}",
98
+ method: 'DELETE'
99
+ })
100
+
101
+ res.code == '204' ? 'Successfully deleted policy' : JSON.parse(res.body)
102
+
103
+ end
104
+
105
+ def add_escalation_rule(options={})
106
+ EscalationRule.new(JSON.parse(curl({
107
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/escalation_policies/#{self.id}/escalation_rules",
108
+ data: { escalation_rule: options.hashify },
109
+ method: 'POST'
110
+ }).body)['escalation_rule'])
111
+ end
112
+
113
+ def update_escalation_rules(options={})
114
+ options[:rules] = options[:rules].map { |rule| rule.class == EscalationRule ? rule.hashify : rule }
115
+
116
+ JSON.parse(curl({
117
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/escalation_policies/#{self.id}/escalation_rules",
118
+ data: { escalation_rules: options[:rules] },
119
+ method: 'PUT'
120
+ }).body)
121
+ end
122
+
123
+ def refresh
124
+ self.attributes = get_escalation_policy(id: self.id)
125
+ end
126
+
127
+ end
@@ -0,0 +1,74 @@
1
+ class Incident < Pagerduty
2
+ include Virtus.model
3
+
4
+ attribute :id
5
+ attribute :incident_number
6
+ attribute :created_on
7
+ attribute :status
8
+ attribute :html_url
9
+ attribute :incident_key
10
+ attribute :service, Service
11
+ attribute :escalation_policy, EscalationPolicy
12
+ attribute :assigned_to_user, AssignedUser
13
+ attribute :trigger_summary_data, TriggerSummaryData
14
+ attribute :trigger_details_html_url
15
+ attribute :trigger_type
16
+ attribute :last_status_change_on
17
+ attribute :last_status_change_by, LastStatusChangeBy
18
+ attribute :number_of_escalations
19
+ attribute :resolved_by_user, ResolvedByUser
20
+
21
+ def inspect
22
+ puts "<Pagerduty::#{self.class}"
23
+ self.attributes.each { |attr,val|
24
+ puts "\t#{attr}=#{val.class == Class ? "BLOCK" : val.inspect}"
25
+ }
26
+ puts ">"
27
+
28
+ self.attributes
29
+ end
30
+
31
+ def notes
32
+ super(self.id)
33
+ end
34
+
35
+ def acknowledge
36
+ JSON.parse(curl({
37
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/incidents/#{self.id}/acknowledge",
38
+ params: { 'requester_id' => self.assigned_to_user.id },
39
+ method: 'PUT'
40
+ }).body)
41
+ end
42
+
43
+ def resolve
44
+ JSON.parse(curl({
45
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/incidents/#{self.id}/resolve",
46
+ params: { 'requester_id' => self.assigned_to_user.id },
47
+ method: 'PUT'
48
+ }).body)
49
+ end
50
+
51
+ def reassign(options={})
52
+
53
+ unless has_requirements?([:escalation_level, :assigned_to_user], options)
54
+ puts "#> This function requires arguments :escalation_level, :assigned_to_user"
55
+ puts "Please see: http://developer.pagerduty.com/documentation/rest/incidents/reassign"
56
+ return
57
+ end
58
+
59
+ JSON.parse(curl({
60
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/incidents/#{self.id}/resolve",
61
+ params: { 'requester_id' => self.assigned_to_user.id, }.merge(options),
62
+ method: 'PUT'
63
+ }).body)
64
+ end
65
+
66
+ def log_entries(options={})
67
+ LogEntries.new(JSON.parse(curl({
68
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/incidents/#{self.id}/log_entries",
69
+ params: options,
70
+ method: 'GET'
71
+ }).body))
72
+ end
73
+ end
74
+
@@ -0,0 +1,9 @@
1
+ class LastStatusChangeBy
2
+ include Virtus.model
3
+
4
+ attribute :id
5
+ attribute :name
6
+ attribute :email
7
+ attribute :html_url
8
+ end
9
+
@@ -0,0 +1,22 @@
1
+ class Pagerduty
2
+ class LogEntry
3
+ include Virtus.model
4
+
5
+ attribute :id
6
+ attribute :type
7
+ attribute :created_at
8
+ attribute :note
9
+ attribute :agent, Pagerduty::User
10
+ attribute :user, Pagerduty::User
11
+ attribute :channel
12
+ end
13
+ end
14
+
15
+ class LogEntries
16
+ include Virtus.model
17
+
18
+ attribute :log_entries, Array[Pagerduty::LogEntry]
19
+ attribute :limit
20
+ attribute :offset
21
+ attribute :total
22
+ end
@@ -0,0 +1,66 @@
1
+ class Pagerduty
2
+ class MaintenanceWindow < Pagerduty
3
+ include Virtus.model
4
+
5
+ attribute :id
6
+ attribute :sequence_number
7
+ attribute :start_time
8
+ attribute :end_time
9
+ attribute :description
10
+ attribute :created_by, Pagerduty::User
11
+ attribute :services, Array[Service]
12
+ attribute :service_ids
13
+
14
+ class Count
15
+ include Virtus.model
16
+
17
+ attribute :ongoing
18
+ attribute :future
19
+ attribute :past
20
+ attribute :all
21
+ end
22
+
23
+ def initialize(attributes)
24
+ self.attributes = attributes
25
+ self.service_ids = self.services.map(&:id)
26
+ end
27
+
28
+ def save(options={})
29
+ Pagerduty::MaintenanceWindow.new(JSON.parse(curl({
30
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/maintenance_windows/#{self.id}",
31
+ data: {
32
+ start_time: self.start_time,
33
+ end_time: self.end_time,
34
+ description: self.description,
35
+ service_ids: self.service_ids
36
+ },
37
+ method: 'PUT'
38
+ }).body)['maintenance_window'])
39
+ end
40
+
41
+ def delete
42
+ res = curl({
43
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/maintenance_windows/#{self.id}",
44
+ method: 'DELETE'
45
+ })
46
+
47
+ res.code == '204' ? "Successfully deleted Maintenance Window #{self.id}" : JSON.parse(response.body)
48
+
49
+ end
50
+
51
+ end
52
+ end
53
+
54
+ class Pagerduty
55
+ class MaintenanceWindows
56
+ include Virtus.model
57
+
58
+ attribute :maintenance_windows, Array[Pagerduty::MaintenanceWindow]
59
+ attribute :limit
60
+ attribute :offset
61
+ attribute :total
62
+ attribute :query
63
+ attribute :counts, Pagerduty::MaintenanceWindow::Count
64
+
65
+ end
66
+ end
@@ -0,0 +1,9 @@
1
+ class Note
2
+ include Virtus.model
3
+
4
+ attribute :id
5
+ attribute :user, Pagerduty::User
6
+ attribute :content
7
+ attribute :created_at
8
+ end
9
+
@@ -0,0 +1,7 @@
1
+ class Notification
2
+ include Virtus.model
3
+
4
+ attribute :type
5
+ attribute :address
6
+ attribute :status
7
+ end
@@ -0,0 +1,54 @@
1
+ class Pagerduty
2
+ class Reports
3
+ class Alert
4
+ include Virtus.model
5
+
6
+ attribute :number_of_alerts
7
+ attribute :number_of_phone_alerts
8
+ attribute :number_of_sms_alerts
9
+ attribute :number_of_email_alerts
10
+ attribute :start
11
+ attribute :end
12
+ end
13
+ end
14
+ end
15
+
16
+ class Pagerduty
17
+ class Reports
18
+ class Incident
19
+ include Virtus.model
20
+
21
+ attribute :start
22
+ attribute :number_of_incidents
23
+ attribute :end
24
+ end
25
+ end
26
+ end
27
+
28
+ class Pagerduty
29
+ class Reports
30
+ class Incidents
31
+ include Virtus.model
32
+
33
+ attribute :incidents, Array[Pagerduty::Reports::Incident]
34
+ end
35
+ end
36
+ end
37
+
38
+ class Pagerduty
39
+ class Reports
40
+ class Alerts
41
+
42
+ include Virtus.model
43
+
44
+ attribute :alerts, Array[Pagerduty::Reports::Alert]
45
+ attribute :total_number_of_alerts
46
+ attribute :total_number_of_phone_alerts
47
+ attribute :total_number_of_sms_alerts
48
+ attribute :total_number_of_email_alerts
49
+ attribute :total_number_of_billable_alerts
50
+ end
51
+ end
52
+
53
+ end
54
+
@@ -0,0 +1,9 @@
1
+ class ResolvedByUser
2
+ include Virtus.model
3
+
4
+ attribute :id
5
+ attribute :name
6
+ attribute :email
7
+ attribute :html_url
8
+ end
9
+
@@ -0,0 +1,109 @@
1
+ class Pagerduty
2
+ class Schedules
3
+ class Schedule
4
+ include Virtus.model
5
+
6
+ attribute :id
7
+ attribute :name
8
+ attribute :time_zone
9
+ attribute :today
10
+ attribute :escalation_policies, Array[EscalationPolicy]
11
+ end
12
+ end
13
+ end
14
+
15
+ class Pagerduty
16
+ class Schedules
17
+ class ScheduleLayer
18
+ class User
19
+ include Virtus.model
20
+
21
+ attribute :member_order
22
+ attribute :user, Pagerduty::User
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ class Pagerduty
29
+ class Schedules
30
+ class Restriction
31
+ include Virtus.model
32
+
33
+ attribute :start_time_of_day
34
+ attribute :duration_seconds
35
+ end
36
+ end
37
+ end
38
+
39
+ class Pagerduty
40
+ class Schedules
41
+ class ScheduleLayer
42
+ include Virtus.model
43
+
44
+ attribute :name
45
+ attribute :rendered_schedule_entries, Array
46
+ attribute :id
47
+ attribute :priority
48
+ attribute :start
49
+ attribute :end
50
+ attribute :restriction_type
51
+ attribute :rotation_virtual_start
52
+ attribute :rotation_turn_length_seconds
53
+ attribute :users, Array[Pagerduty::Schedules::ScheduleLayer::User]
54
+ attribute :restrictions, Array[Pagerduty::Schedules::Restriction]
55
+ attribute :rendered_coverage_percentage
56
+
57
+ end
58
+ end
59
+ end
60
+
61
+ class Pagerduty
62
+ class Schedules
63
+ include Virtus.model
64
+
65
+ attribute :schedules, Array[Pagerduty::Schedules::Schedule]
66
+ attribute :limit
67
+ attribute :offset
68
+ attribute :total
69
+ end
70
+ end
71
+
72
+ class Pagerduty
73
+ class Schedules
74
+ class Override
75
+ include Virtus.model
76
+
77
+ attribute :name
78
+ attribute :rendered_schedule_entries, Array[Pagerduty::Schedules::ScheduleLayer]
79
+ end
80
+ end
81
+ end
82
+
83
+ class Pagerduty
84
+ class Schedules
85
+ class FinalSchedule
86
+ include Virtus.model
87
+
88
+ attribute :name
89
+ attribute :rendered_schedule_entries, Array[Pagerduty::Schedules::ScheduleLayer]
90
+ attribute :rendered_coverage_percentage
91
+ end
92
+ end
93
+ end
94
+
95
+ class Pagerduty
96
+ class ScheduleInfo
97
+ include Virtus.model
98
+
99
+ attribute :id
100
+ attribute :name
101
+ attribute :time_zone
102
+ attribute :today
103
+ attribute :escalation_policies, Array[EscalationPolicy]
104
+ attribute :schedule_layers, Array[Pagerduty::Schedules::ScheduleLayer]
105
+ attribute :overrides_subschedule, Pagerduty::Schedules::Override
106
+ attribute :final_schedule, Pagerduty::Schedules::FinalSchedule
107
+
108
+ end
109
+ end
@@ -0,0 +1,9 @@
1
+ class Service
2
+ include Virtus.model
3
+
4
+ attribute :id
5
+ attribute :name
6
+ attribute :html_url
7
+ attribute :delete_at
8
+ end
9
+
@@ -0,0 +1,53 @@
1
+ class Pagerduty
2
+ class Services
3
+ class Objects
4
+ include Virtus.model
5
+
6
+ class IncidentCount < Pagerduty::Services::Objects
7
+ attribute :triggered
8
+ attribute :acknowledged
9
+ attribute :resolved
10
+ attribute :total
11
+ end
12
+
13
+ class EmailFilter < Pagerduty::Services::Objects
14
+ attribute :subject_mode
15
+ attribute :subject_regex
16
+ attribute :body_mode
17
+ attribute :body_regex
18
+ attribute :from_email_mode
19
+ attribute :from_email_regex
20
+ attribute :id
21
+ end
22
+
23
+ class Service < Pagerduty::Services::Objects
24
+ attribute :id
25
+ attribute :name
26
+ attribute :description
27
+ attribute :service_url
28
+ attribute :service_key
29
+ attribute :auto_resolve_timeout
30
+ attribute :acknowledgement_timeout
31
+ attribute :created_at
32
+ attribute :status
33
+ attribute :last_incident_timestamp
34
+ attribute :email_incident_creation
35
+ attribute :incident_counts
36
+ attribute :email_filter_mode
37
+ attribute :type
38
+ attribute :escalation_policy, 'EscalationPolicy'
39
+ attribute :email_filters, Pagerduty::Services::Objects::EmailFilter
40
+ attribute :severity_filter
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+
47
+ class Pagerduty
48
+ class Services
49
+ include Virtus.model
50
+
51
+ attribute :services, Array[Pagerduty::Services::Objects::Service]
52
+ end
53
+ end
@@ -0,0 +1,6 @@
1
+ class TriggerSummaryData
2
+ include Virtus.model
3
+
4
+ attribute :subject
5
+ end
6
+
@@ -0,0 +1,74 @@
1
+ class Pagerduty
2
+ class User < Pagerduty
3
+ include Virtus.model
4
+
5
+ attribute :id
6
+ attribute :name
7
+ attribute :email
8
+ attribute :time_zone
9
+ attribute :color
10
+ attribute :role
11
+ attribute :avatar_url
12
+ attribute :user_url
13
+ attribute :invitation_sent
14
+ attribute :marketing
15
+ attribute :marketing_opt_out
16
+ attribute :type, String, default: 'user'
17
+
18
+ #def inspect
19
+ #puts "<Pagerduty::#{self.class}"
20
+ #self.attributes.each { |attr,val|
21
+ #puts "\t#{attr}=#{val.inspect}"
22
+ #}
23
+ #puts ">"
24
+
25
+ #self.attributes
26
+ #end
27
+
28
+ def log_entries(options={})
29
+ LogEntries.new(JSON.parse(curl({
30
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/users/#{self.id}/log_entries",
31
+ params: options,
32
+ method: 'GET'
33
+ }).body))
34
+ end
35
+
36
+ def delete
37
+ res = curl({
38
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/users/#{self.id}",
39
+ method: 'DELETE'
40
+ })
41
+
42
+ res.code == '204' ? "Successfully deleted User #{self.id}" : JSON.parse(response.body)
43
+ end
44
+
45
+ def save
46
+ saved_user = User.new(JSON.parse(curl({
47
+ uri: "https://#@@subdomain.pagerduty.com/api/v1/users/#{self.id}",
48
+ data: {
49
+ role: self.role,
50
+ name: self.name,
51
+ email: self.email,
52
+ time_zone: self.time_zone
53
+ },
54
+ method: 'PUT'
55
+ }).body)['user'])
56
+
57
+ self.role = saved_user.role
58
+ self.name = saved_user.name
59
+ self.email = saved_user.email
60
+ self.time_zone = saved_user.time_zone
61
+ self
62
+ end
63
+ end
64
+ end
65
+
66
+ class Users
67
+ include Virtus.model
68
+
69
+ attribute :active_account_users
70
+ attribute :limit
71
+ attribute :offset
72
+ attribute :total
73
+ attribute :users, Array[Pagerduty::User]
74
+ end