diff --git a/app/controllers/v3/feature_flags_controller.rb b/app/controllers/v3/feature_flags_controller.rb index f68067968e2..d74d6db2cf9 100644 --- a/app/controllers/v3/feature_flags_controller.rb +++ b/app/controllers/v3/feature_flags_controller.rb @@ -6,6 +6,8 @@ require 'fetchers/feature_flag_list_fetcher' class FeatureFlagsController < ApplicationController + OVERRIDE_IN_MANIFEST_MSG = 'The feature flag has an override configured in the bosh manifest and can be overwritten when the deployment is updated.'.freeze + def index message = FeatureFlagsListMessage.from_params(query_params) invalid_param!(message.errors.full_messages) unless message.valid? @@ -38,6 +40,7 @@ def update unprocessable!(message.errors.full_messages) unless message.valid? flag = VCAP::CloudController::FeatureFlagUpdate.new.update(flag, message) + add_warning_headers([OVERRIDE_IN_MANIFEST_MSG]) if VCAP::CloudController::FeatureFlag.config_overridden?(hashed_params[:name].to_sym) render status: :ok, json: Presenters::V3::FeatureFlagPresenter.new(flag) rescue FeatureFlagUpdate::Error => e unprocessable!(e) diff --git a/app/models/runtime/feature_flag.rb b/app/models/runtime/feature_flag.rb index 75c452eb6d7..88a5c24a353 100644 --- a/app/models/runtime/feature_flag.rb +++ b/app/models/runtime/feature_flag.rb @@ -37,6 +37,8 @@ class UndefinedFeatureFlagError < StandardError 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 @@ -104,6 +106,12 @@ def self.override_default_flags(feature_flag_overrides) 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? diff --git a/spec/unit/controllers/v3/feature_flags_controller_spec.rb b/spec/unit/controllers/v3/feature_flags_controller_spec.rb index 6d59fa1c2de..91b86223c1d 100644 --- a/spec/unit/controllers/v3/feature_flags_controller_spec.rb +++ b/spec/unit/controllers/v3/feature_flags_controller_spec.rb @@ -230,6 +230,51 @@ expect(parsed_body['custom_error_message']).to be_nil end end + + context 'when there are overrides in configuration' do + before do + stub_const('VCAP::CloudController::FeatureFlag::DEFAULT_FLAGS', { + flag1: false, flag2: true, flag3: true, flag4: false + }) + VCAP::CloudController::FeatureFlag.override_default_flags({ flag1: false, flag4: true }) + end + + it 'returns a warning message for the overridden flags' do + patch :update, params: { + name: 'flag1', + enabled: false + }, as: :json + + expect(response).to have_http_status :ok + expect(response).to have_warning_message FeatureFlagsController::OVERRIDE_IN_MANIFEST_MSG + + patch :update, params: { + name: 'flag4', + enabled: false + }, as: :json + + expect(response).to have_http_status :ok + expect(response).to have_warning_message FeatureFlagsController::OVERRIDE_IN_MANIFEST_MSG + end + + it 'returns no warning message for not overridden flags' do + patch :update, params: { + name: 'flag2', + enabled: false + }, as: :json + + expect(response).to have_http_status :ok + expect(response.headers['X-Cf-Warnings']).to be_nil + + patch :update, params: { + name: 'flag3', + enabled: false + }, as: :json + + expect(response).to have_http_status :ok + expect(response.headers['X-Cf-Warnings']).to be_nil + end + end end end end diff --git a/spec/unit/models/runtime/feature_flag_spec.rb b/spec/unit/models/runtime/feature_flag_spec.rb index 82dea09e712..458f93c4cdd 100644 --- a/spec/unit/models/runtime/feature_flag_spec.rb +++ b/spec/unit/models/runtime/feature_flag_spec.rb @@ -332,5 +332,33 @@ module VCAP::CloudController end end end + + describe '.config_overridden?' do + context 'when overrides have not been set yet' do + before do + FeatureFlag.instance_variable_set(:@feature_flag_overrides, nil) + end + + it 'returns nil' do + expect(FeatureFlag.config_overridden?(:diego_docker)).to be_nil + end + end + + context 'when overrides have been set' do + let(:default_diego_docker_value) { FeatureFlag::DEFAULT_FLAGS[:diego_docker] } + + before do + FeatureFlag.override_default_flags({ diego_docker: !default_diego_docker_value }) + end + + it 'return true for the overriden flag' do + expect(FeatureFlag.config_overridden?(:diego_docker)).to be true + end + + it 'return false for other flags' do + expect(FeatureFlag.config_overridden?(:potato)).to be false + end + end + end end end