|
2 | 2 |
|
3 | 3 | module VCAP::CloudController |
4 | 4 | class RouteOptionsMessage < BaseMessage |
5 | | - VALID_MANIFEST_ROUTE_OPTIONS = %i[loadbalancing].freeze |
6 | | - VALID_ROUTE_OPTIONS = %i[loadbalancing].freeze |
7 | | - VALID_LOADBALANCING_ALGORITHMS = %w[round-robin least-connection].freeze |
| 5 | + VALID_MANIFEST_ROUTE_OPTIONS = %i[loadbalancing hash_header hash_balance].freeze |
| 6 | + VALID_ROUTE_OPTIONS = %i[loadbalancing hash_header hash_balance].freeze |
| 7 | + VALID_LOADBALANCING_ALGORITHMS_WITH_HASH = %w[round-robin least-connection hash].freeze |
| 8 | + VALID_LOADBALANCING_ALGORITHMS_WITHOUT_HASH = %w[round-robin least-connection].freeze |
8 | 9 |
|
9 | 10 | register_allowed_keys VALID_ROUTE_OPTIONS |
10 | 11 | validates_with NoAdditionalKeysValidator |
11 | | - validates :loadbalancing, |
12 | | - inclusion: { in: VALID_LOADBALANCING_ALGORITHMS, message: "must be one of '#{RouteOptionsMessage::VALID_LOADBALANCING_ALGORITHMS.join(', ')}' if present" }, |
13 | | - presence: true, |
14 | | - allow_nil: true |
| 12 | + validate :validate_loadbalancing_with_feature_flag |
| 13 | + |
| 14 | + validate :validate_hash_options, if: -> { errors[:loadbalancing].empty? } |
| 15 | + |
| 16 | + def self.valid_loadbalancing_algorithms |
| 17 | + if FeatureFlag.enabled?(:hash_based_routing) |
| 18 | + VALID_LOADBALANCING_ALGORITHMS_WITH_HASH |
| 19 | + else |
| 20 | + VALID_LOADBALANCING_ALGORITHMS_WITHOUT_HASH |
| 21 | + end |
| 22 | + end |
| 23 | + |
| 24 | + private |
| 25 | + |
| 26 | + def validate_loadbalancing_with_feature_flag |
| 27 | + return if loadbalancing.nil? |
| 28 | + |
| 29 | + valid_algorithms = self.class.valid_loadbalancing_algorithms |
| 30 | + return if valid_algorithms.include?(loadbalancing) |
| 31 | + |
| 32 | + errors.add(:loadbalancing, "must be one of '#{valid_algorithms.join(', ')}' if present") |
| 33 | + end |
| 34 | + |
| 35 | + def validate_hash_options |
| 36 | + if loadbalancing == 'hash' |
| 37 | + validate_hash_header_present |
| 38 | + validate_hash_balance_format |
| 39 | + else |
| 40 | + validate_hash_options_not_present_for_non_hash |
| 41 | + end |
| 42 | + end |
| 43 | + |
| 44 | + def validate_hash_header_present |
| 45 | + if hash_header.blank? |
| 46 | + errors.add(:hash_header, 'must be present when loadbalancing is set to hash') |
| 47 | + elsif !hash_header.is_a?(String) |
| 48 | + errors.add(:hash_header, 'must be a string') |
| 49 | + end |
| 50 | + end |
| 51 | + |
| 52 | + def validate_hash_balance_format |
| 53 | + return if hash_balance.nil? |
| 54 | + |
| 55 | + # Convert string to float if needed (from CLI input) |
| 56 | + begin |
| 57 | + hash_balance_float = Float(hash_balance) |
| 58 | + errors.add(:hash_balance, 'must be greater than or equal to 0.0') if hash_balance_float < 0.0 |
| 59 | + rescue ArgumentError, TypeError |
| 60 | + errors.add(:hash_balance, 'must be a valid number') |
| 61 | + end |
| 62 | + end |
| 63 | + |
| 64 | + def validate_hash_options_not_present_for_non_hash |
| 65 | + errors.add(:hash_header, 'can only be set when loadbalancing is hash') if hash_header.present? |
| 66 | + return if hash_balance.blank? |
| 67 | + |
| 68 | + errors.add(:hash_balance, 'can only be set when loadbalancing is hash') |
| 69 | + end |
15 | 70 | end |
16 | 71 | end |
0 commit comments