Class: Kennel::Models::Record
- Includes:
- OptionalValidations
- Defined in:
- lib/kennel/models/record.rb
Direct Known Subclasses
Defined Under Namespace
Classes: PrepareError
Constant Summary collapse
- UnvalidatedRecordError =
Class.new(StandardError)
- MARKER_TEXT =
Apart from if you just don’t like the default for some reason, overriding MARKER_TEXT allows for namespacing within the same Datadog account. If you run one Kennel setup with marker text A and another with marker text B (assuming that A isn’t a substring of B and vice versa), then the two Kennel setups will operate independently of each other, not trampling over each other’s objects.
This could be useful for allowing multiple products / projects / teams to share a Datadog account but otherwise largely operate independently of each other. In particular, it can be useful for running a “dev” or “staging” instance of Kennel in the same account as, but mostly isolated from, a “production” instance.
ENV.fetch("KENNEL_MARKER_TEXT", "Managed by kennel")
- LOCK =
"\u{1F512}"
- TRACKING_FIELDS =
[:message, :description].freeze
- READONLY_ATTRIBUTES =
[ :deleted, :id, :created, :created_at, :creator, :org_id, :modified, :modified_at, :klass, :tracking_id # added by syncer.rb ].freeze
- ALLOWED_KENNEL_ID_CHARS =
"a-zA-Z_\\d.-"
- ALLOWED_KENNEL_ID_SEGMENT =
/[#{ALLOWED_KENNEL_ID_CHARS}]+/
- ALLOWED_KENNEL_ID_FULL =
"#{ALLOWED_KENNEL_ID_SEGMENT}:#{ALLOWED_KENNEL_ID_SEGMENT}".freeze
- ALLOWED_KENNEL_ID_REGEX =
/\A#{ALLOWED_KENNEL_ID_FULL}\z/
Constants included from OptionalValidations
OptionalValidations::UNIGNORABLE
Constants inherited from Base
Base::SETTING_OVERRIDABLE_METHODS
Constants included from SettingsAsMethods
SettingsAsMethods::AS_PROCS, SettingsAsMethods::SETTING_OVERRIDABLE_METHODS
Instance Attribute Summary collapse
-
#filtered_validation_errors ⇒ Object
readonly
Returns the value of attribute filtered_validation_errors.
-
#project ⇒ Object
readonly
Returns the value of attribute project.
-
#unfiltered_validation_errors ⇒ Object
readonly
Returns the value of attribute unfiltered_validation_errors.
Class Method Summary collapse
- .api_resource_map ⇒ Object
- .parse_any_url(url) ⇒ Object
- .parse_tracking_id(a) ⇒ Object
-
.remove_tracking_id(a) ⇒ Object
TODO: combine with parse into a single method or a single regex.
Instance Method Summary collapse
- #add_tracking_id ⇒ Object
- #as_json ⇒ Object
- #build ⇒ Object
- #build_json ⇒ Object
- #diff(actual) ⇒ Object
-
#initialize(project, *args) ⇒ Record
constructor
A new instance of Record.
- #invalid_update!(field, old_value, new_value) ⇒ Object
- #remove_tracking_id ⇒ Object
- #resolve_linked_tracking_ids! ⇒ Object
-
#safe_tracking_id ⇒ Object
For use during error handling.
- #tracking_id ⇒ Object
-
#validate_update!(_diffs) ⇒ Object
Can raise DisallowedUpdateError.
Methods included from OptionalValidations
Methods inherited from Base
Methods included from SubclassTracking
#recursive_subclasses, #subclasses
Methods included from SettingsAsMethods
Constructor Details
#initialize(project, *args) ⇒ Record
Returns a new instance of Record.
90 91 92 93 94 |
# File 'lib/kennel/models/record.rb', line 90 def initialize(project, *args) raise ArgumentError, "First argument must be a project, not #{project.class}" unless project.is_a?(Project) @project = project super(*args) end |
Instance Attribute Details
#filtered_validation_errors ⇒ Object (readonly)
Returns the value of attribute filtered_validation_errors.
88 89 90 |
# File 'lib/kennel/models/record.rb', line 88 def filtered_validation_errors @filtered_validation_errors end |
#project ⇒ Object (readonly)
Returns the value of attribute project.
88 89 90 |
# File 'lib/kennel/models/record.rb', line 88 def project @project end |
#unfiltered_validation_errors ⇒ Object (readonly)
Returns the value of attribute unfiltered_validation_errors.
88 89 90 |
# File 'lib/kennel/models/record.rb', line 88 def unfiltered_validation_errors @unfiltered_validation_errors end |
Class Method Details
.api_resource_map ⇒ Object
55 56 57 |
# File 'lib/kennel/models/record.rb', line 55 def api_resource_map subclasses.to_h { |s| [s.api_resource, s] } end |
.parse_any_url(url) ⇒ Object
47 48 49 50 51 52 53 |
# File 'lib/kennel/models/record.rb', line 47 def parse_any_url(url) subclasses.detect do |s| if id = s.parse_url(url) break s.api_resource, id end end end |
.parse_tracking_id(a) ⇒ Object
59 60 61 |
# File 'lib/kennel/models/record.rb', line 59 def parse_tracking_id(a) a[self::TRACKING_FIELD].to_s[/-- #{Regexp.escape(MARKER_TEXT)} (#{ALLOWED_KENNEL_ID_FULL})/, 1] end |
.remove_tracking_id(a) ⇒ Object
TODO: combine with parse into a single method or a single regex
64 65 66 67 68 69 |
# File 'lib/kennel/models/record.rb', line 64 def remove_tracking_id(a) value = a[self::TRACKING_FIELD] a[self::TRACKING_FIELD] = value.dup.sub!(/\n?-- #{Regexp.escape(MARKER_TEXT)} .*/, "") || raise("did not find tracking id in #{value}") end |
Instance Method Details
#add_tracking_id ⇒ Object
123 124 125 126 127 128 129 130 131 |
# File 'lib/kennel/models/record.rb', line 123 def add_tracking_id json = as_json if self.class.parse_tracking_id(json) raise "#{safe_tracking_id} Remove \"-- #{MARKER_TEXT}\" line from #{self.class::TRACKING_FIELD} to copy a resource" end json[self.class::TRACKING_FIELD] = "#{json[self.class::TRACKING_FIELD]}\n" \ "-- #{MARKER_TEXT} #{tracking_id} in #{project.class.file_location}, do not modify manually".lstrip end |
#as_json ⇒ Object
162 163 164 165 166 167 168 |
# File 'lib/kennel/models/record.rb', line 162 def as_json # A courtesy to those tests that still expect as_json to perform validation and raise on error build if @unfiltered_validation_errors.nil? raise UnvalidatedRecordError, "#{safe_tracking_id} as_json called on invalid part" unless filtered_validation_errors.empty? @as_json end |
#build ⇒ Object
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/kennel/models/record.rb', line 143 def build @unfiltered_validation_errors = [] json = nil begin json = build_json (id = json.delete(:id)) && json[:id] = id validate_json(json) rescue StandardError if unfiltered_validation_errors.empty? @unfiltered_validation_errors = nil raise PrepareError, safe_tracking_id # FIXME: this makes errors hard to debug when running tests end end @filtered_validation_errors = filter_validation_errors @as_json = json # Only valid if filtered_validation_errors.empty? end |
#build_json ⇒ Object
137 138 139 140 141 |
# File 'lib/kennel/models/record.rb', line 137 def build_json { id: id }.compact end |
#diff(actual) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/kennel/models/record.rb', line 96 def diff(actual) expected = as_json expected.delete(:id) self.class.send(:normalize, expected, actual) return [] if actual == expected # Hashdiff is slow, this is fast # strict: ignore Integer vs Float # similarity: show diff when not 100% similar # use_lcs: saner output Hashdiff.diff(actual, expected, use_lcs: false, strict: false, similarity: 1) end |
#invalid_update!(field, old_value, new_value) ⇒ Object
174 175 176 |
# File 'lib/kennel/models/record.rb', line 174 def invalid_update!(field, old_value, new_value) raise DisallowedUpdateError, "#{safe_tracking_id} Datadog does not allow update of #{field} (#{old_value.inspect} -> #{new_value.inspect})" end |
#remove_tracking_id ⇒ Object
133 134 135 |
# File 'lib/kennel/models/record.rb', line 133 def remove_tracking_id self.class.remove_tracking_id(as_json) end |
#resolve_linked_tracking_ids! ⇒ Object
120 121 |
# File 'lib/kennel/models/record.rb', line 120 def resolve_linked_tracking_ids!(*) end |
#safe_tracking_id ⇒ Object
For use during error handling
179 180 181 182 183 |
# File 'lib/kennel/models/record.rb', line 179 def safe_tracking_id tracking_id rescue StandardError "<unknown; #tracking_id crashed>" end |
#tracking_id ⇒ Object
110 111 112 113 114 115 116 117 118 |
# File 'lib/kennel/models/record.rb', line 110 def tracking_id @tracking_id ||= begin id = "#{project.kennel_id}:#{kennel_id}" unless id.match?(ALLOWED_KENNEL_ID_REGEX) # <-> parse_tracking_id raise "Bad kennel/tracking id: #{id.inspect} must match #{ALLOWED_KENNEL_ID_REGEX}" end id end end |
#validate_update!(_diffs) ⇒ Object
Can raise DisallowedUpdateError
171 172 |
# File 'lib/kennel/models/record.rb', line 171 def validate_update!(_diffs) end |