-
Notifications
You must be signed in to change notification settings - Fork 368
Expand file tree
/
Copy pathfeature_flag.rb
More file actions
121 lines (98 loc) · 3.82 KB
/
feature_flag.rb
File metadata and controls
121 lines (98 loc) · 3.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
module VCAP::CloudController
class FeatureFlag < Sequel::Model
FF_ERROR_MESSAGE_REGEX = /\A[[:alnum:][:punct:][:print:]]+\Z/
class UndefinedFeatureFlagError < StandardError
end
DEFAULT_FLAGS = {
user_org_creation: false,
private_domain_creation: true,
app_bits_upload: true,
app_scaling: true,
route_creation: true,
service_instance_creation: true,
diego_docker: false,
diego_cnb: false,
set_roles_by_username: true,
unset_roles_by_username: true,
task_creation: true,
env_var_visibility: true,
space_scoped_private_broker_creation: true,
space_developer_env_var_visibility: true,
service_instance_sharing: false,
hide_marketplace_from_unauthenticated_users: false,
resource_matching: true,
route_sharing: false,
hash_based_routing: false,
app_to_app_mtls_routing: false
}.freeze
ADMIN_SKIPPABLE = %i[
app_bits_upload
app_scaling
set_roles_by_username
space_developer_env_var_visibility
task_creation
unset_roles_by_username
].freeze
ADMIN_READ_ONLY_SKIPPABLE = [:space_developer_env_var_visibility].freeze
@feature_flag_overrides = nil
export_attributes :name, :enabled, :error_message
import_attributes :name, :enabled, :error_message
def validate
validates_presence :name
validates_unique :name
validates_presence :enabled
validates_includes DEFAULT_FLAGS.keys.map(&:to_s), :name
validates_format FF_ERROR_MESSAGE_REGEX, :error_message if error_message
end
def self.enabled?(feature_flag_name, raise_unless_enabled: false)
return true if ADMIN_SKIPPABLE.include?(feature_flag_name) && admin?
return true if ADMIN_READ_ONLY_SKIPPABLE.include?(feature_flag_name) && admin_read_only?
feature_flag = FeatureFlag.find(name: feature_flag_name.to_s)
enabled = if feature_flag
feature_flag.enabled
else
DEFAULT_FLAGS.fetch(feature_flag_name)
end
if raise_unless_enabled && !enabled
err_message = feature_flag&.error_message ? feature_flag.error_message : feature_flag_name
raise CloudController::Errors::ApiError.new_from_details('FeatureDisabled', err_message)
end
enabled
rescue KeyError
raise UndefinedFeatureFlagError.new "invalid key: #{feature_flag_name}"
end
def self.disabled?(feature_flag_name)
!enabled?(feature_flag_name)
end
def self.raise_unless_enabled!(feature_flag_name)
enabled?(feature_flag_name, raise_unless_enabled: true)
end
def self.admin?
VCAP::CloudController::SecurityContext.admin?
end
def self.admin_read_only?
VCAP::CloudController::SecurityContext.admin_read_only?
end
def self.override_default_flags(feature_flag_overrides)
invalid_keys = feature_flag_overrides.keys.to_set - FeatureFlag::DEFAULT_FLAGS.keys.to_set
raise "Invalid feature flag name(s): #{invalid_keys.to_a}" if invalid_keys.any?
invalid_values = feature_flag_overrides.reject { |_, v| v.is_a?(TrueClass) || v.is_a?(FalseClass) }
raise "Invalid feature flag value(s): #{invalid_values}" if invalid_values.any?
feature_flag_overrides.each do |flag_name, flag_value|
feature_flag = FeatureFlag.find(name: flag_name.to_s)
if feature_flag
next if feature_flag.enabled == flag_value
else
feature_flag = FeatureFlag.new(name: flag_name.to_s)
end
feature_flag.enabled = flag_value
feature_flag.save
end
@feature_flag_overrides = feature_flag_overrides
end
def self.config_overridden?(feature_flag_name)
@feature_flag_overrides && @feature_flag_overrides.keys.include?(feature_flag_name)
end
private_class_method :admin?
end
end