canvas-lms/lib/feature_flags.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

245 lines
8.7 KiB
Ruby
Raw Normal View History

# frozen_string_literal: true
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
#
# Copyright (C) 2013 - present Instructure, Inc.
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
module FeatureFlags
def self.included(base)
base.has_many :feature_flags, as: :context, dependent: :destroy
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
def feature_enabled?(feature)
# This method is doing a bit more than initially appears. 🤞 this helps you in your
# future travels, fellow spelunker.
#
# persist_result - takes the feature state, logs it to Datadog, then returns it.
#
# The feature state is determined by three different cases:
# 1. the context's id is zero, in which case it should always be false
# 2. feature lookup fails, in which case it should always be false
# 3. feature lookup succeeds, in which case it should be the evaluation of enabled?
persist_result(feature, !id&.zero? && !!lookup_feature_flag(feature)&.enabled?)
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
def feature_allowed?(feature)
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
flag = lookup_feature_flag(feature)
rip out copying logic for grading periods remove the copying of grading periods. teachers and sub-account admins can no longer create grading periods (although they can still edit and delete previously-created grading periods), and they cannot edit root account grading periods. closes CNVS-26727 test plan: 1. Course level - sign in as a teacher in a course with multiple grading periods enabled - navigate to the grading periods page at /courses/:course_id/grading_standards - if there are existing course-level grading periods, verify you can edit and delete them - verify you cannot create new grading periods - if there are not existing course-level grading periods, verify account level grading periods show up and they are not editable (if the sub-account owning the course has grading periods, sub-account periods should be displayed. if the sub-account does not exist or does not have grading periods, the root-account grading periods should be displayed) 2. Root account level - sign in as a root account admin and go to the account grading periods page at /accounts/:account_id/grading_standards - verify you can still add new grading periods and you can edit existing grading periods 3. Sub-account level - sign in as a sub-account admin and go to the sub-account grading periods page at /accounts/:sub_account_id/grading_standards - if there are existing sub-account grading periods, verify you can edit and delete them - verify you cannot create new grading periods - if there are not existing sub-account grading periods, verify root account grading periods show up and they are not editable Change-Id: If2083defa524a81cbc557e39350b553c417e6f81 Reviewed-on: https://gerrit.instructure.com/77396 Tested-by: Jenkins Reviewed-by: Jeremy Neander <jneander@instructure.com> Reviewed-by: Derek Bender <djbender@instructure.com> QA-Review: KC Naegle <knaegle@instructure.com> Product-Review: Christi Wruck
2016-03-23 22:35:18 +08:00
return false unless flag
flag.enabled? || flag.can_override?
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
def set_feature_flag!(feature, state)
feature = feature.to_s
flag = feature_flags.find_or_initialize_by(feature: feature)
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
flag.state = state
@feature_flag_cache ||= {}
@feature_flag_cache[feature] = flag
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
flag.save!
association(:feature_flags).reset
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
def allow_feature!(feature)
set_feature_flag!(feature, Feature::STATE_DEFAULT_OFF)
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
def enable_feature!(feature)
set_feature_flag!(feature, Feature::STATE_ON)
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
def disable_feature!(feature)
set_feature_flag!(feature, Feature::STATE_OFF)
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
def reset_feature!(feature)
feature_flags.where(feature: feature.to_s).destroy_all
end
def feature_flag_cache_key(feature)
["feature_flag3", self.class.name, global_id, feature.to_s].cache_key
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
Compute and send stats about feature evaluations This PS adds logic to compute context about a feature flag being evaluated at the time it is checked, and pushed to an SQS queue if configured. Whether or not to push the result of the evaluation to the queue is both sampled and cached so as to not overwhelm the queue or produce too much overhead on the Canvas side. The general process is: 1. Feature flag is evaluated 2. A random value between 0-1 is checked against a threshold stored in the dynamic setting feature_analytics.sampling_rate. 3. If under the threshold, the LocalCache is checked for any recent evaluations of the same flag / context / value combo. 4. If the result isn't already cached, the message is sent to SQS. 5. If anything unexpectedly goes wrong, an error is sent to Sentry and feature evaluation continues normally (no user-facing error). refs DE-926 flag = none Test plan: - Set up config in dynamic_settings.yml like the following: feature_analytics: cache_expiry: '60' sampling_rate: '1.0' queue_url: <canvas-feature-analytics SQS queue url in inseng> region: 'us-west-2' - Start canvas from a vaulted shell with inseng credentials - Go to a user's dashboard, a few coures pages, etc.. - Expect to see messages show up in the SQS queue / its consumers after a minute or two delay - Expect to not see the same feature / context / value combo show up on repeated evaluations - Update the sampling_rate in dynamic_settings.yml to '0.0' and restart canvas - Flush redis cache - Go to the same pages as before - Expect to not see any more evaluations show up in SQS Change-Id: I189e127dd5f31dc5d504bf45d354e93f7208107a Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/278885 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeff Largent <jeff.largent@instructure.com> Product-Review: Jeff Largent <jeff.largent@instructure.com>
2021-11-19 23:04:48 +08:00
def feature_analytics_cache_key(feature, result)
["feature_flag_analytics", feature.to_s, self.class.name, global_id, result].cache_key
end
def feature_flag_cache
Rails.cache
end
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
# return the feature flag for the given feature that is defined on this object, if any.
# (helper method. use lookup_feature_flag to test policy.)
def feature_flag(feature, skip_cache: false)
return nil unless id
shard.activate do
if feature_flags.loaded?
feature_flags.detect { |ff| ff.feature == feature.to_s }
elsif skip_cache
feature_flags.where(feature: feature.to_s).first
else
result = RequestCache.cache("feature_flag", self, feature) do
feature_flag_cache.fetch(feature_flag_cache_key(feature)) do
# keep have the context association unloaded in case we can't marshal it
FeatureFlag.where(feature: feature.to_s, context: self).first
end
end
result.context = self if result
result
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
end
end
# each account that needs to be searched for a feature flag, in priority order,
# starting with site admin
def feature_flag_account_ids
return [Account.site_admin.global_id] if is_a?(User)
return [] if is_a?(Account) && site_admin?
# don't use a cache at all for root account, because
# it won't even hit the database
if is_a?(Account) && root_account?
chain = account_chain(include_site_admin: true).dup
chain.shift
return chain.reverse.map(&:global_id)
end
RequestCache.cache("feature_flag_account_ids", self) do
shard.activate do
Rails.cache.fetch(["feature_flag_account_ids", self].cache_key) do
chain = account_chain(include_site_admin: true).dup
chain.shift if is_a?(Account)
chain.reverse.map(&:global_id)
end
end
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
end
# find the feature flag setting that applies to this object
# it may be defined on the object or inherited
def lookup_feature_flag(feature, override_hidden: false, skip_cache: false, hide_inherited_enabled: false, inherited_only: false)
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
feature = feature.to_s
feature_def = Feature.definitions[feature]
raise "no such feature - #{feature}" unless feature_def
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
return nil unless feature_def.applies_to_object(self)
return nil if feature_def.visible_on.is_a?(Proc) && !feature_def.visible_on.call(self)
return return_flag(feature_def, hide_inherited_enabled) unless feature_def.can_override? || feature_def.hidden?
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
is_root_account = is_a?(Account) && root_account?
is_site_admin = is_a?(Account) && site_admin?
# inherit the feature definition as a default unless it's a hidden feature
retval = feature_def.clone_for_cache unless feature_def.hidden? && !is_site_admin && !override_hidden
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
@feature_flag_cache ||= {}
return return_flag(@feature_flag_cache[feature], hide_inherited_enabled) if @feature_flag_cache.key?(feature) && !inherited_only
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
# find the highest flag that doesn't allow override,
# or the most specific flag otherwise
accounts = feature_flag_account_ids.map do |id|
# optimizations for accounts we likely already have loaded (including their feature flags!)
next Account.site_admin if id == Account.site_admin.global_id
next Account.current_domain_root_account if id == Account.current_domain_root_account&.global_id
account = Account.new
account.id = id
account.shard = Shard.shard_for(id, shard)
account.readonly!
account
end
all_contexts = (accounts + [self]).uniq
all_contexts -= [self] if inherited_only
all_contexts.each do |context|
flag = context.feature_flag(feature, skip_cache: context == self && skip_cache)
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
next unless flag
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
retval = flag
break unless flag.can_override?
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
# if this feature requires root account opt-in, reject a default or site admin flag
# if the context is beneath a root account
if retval && (retval.state == Feature::STATE_DEFAULT_OFF || retval.hidden?) && feature_def.root_opt_in && !is_site_admin &&
(retval.default? || (retval.context_type == "Account" && retval.context_id == Account.site_admin.id))
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
if is_root_account
# create a virtual feature flag in corresponding default state state
retval = feature_flags.temp_record feature: feature, state: "off" unless retval.hidden?
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
elsif inherited_only
# the feature doesn't exist beneath the root account until the root account opts in
return nil
else
return @feature_flag_cache[feature] = nil
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
end
@feature_flag_cache[feature] = retval unless inherited_only
return_flag(retval, hide_inherited_enabled)
end
def return_flag(retval, hide_inherited_enabled)
return nil unless retval
unless hide_inherited_enabled && retval.enabled? && !retval.can_override? && (
# Hide feature flag configs if they belong to a different context
(!retval.default? && (retval.context_type != self.class.name || retval.context_id != id)) ||
# Hide flags that are forced on in config as well
retval.default?
)
retval
end
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end
private
def persist_result(feature, result)
Compute and send stats about feature evaluations This PS adds logic to compute context about a feature flag being evaluated at the time it is checked, and pushed to an SQS queue if configured. Whether or not to push the result of the evaluation to the queue is both sampled and cached so as to not overwhelm the queue or produce too much overhead on the Canvas side. The general process is: 1. Feature flag is evaluated 2. A random value between 0-1 is checked against a threshold stored in the dynamic setting feature_analytics.sampling_rate. 3. If under the threshold, the LocalCache is checked for any recent evaluations of the same flag / context / value combo. 4. If the result isn't already cached, the message is sent to SQS. 5. If anything unexpectedly goes wrong, an error is sent to Sentry and feature evaluation continues normally (no user-facing error). refs DE-926 flag = none Test plan: - Set up config in dynamic_settings.yml like the following: feature_analytics: cache_expiry: '60' sampling_rate: '1.0' queue_url: <canvas-feature-analytics SQS queue url in inseng> region: 'us-west-2' - Start canvas from a vaulted shell with inseng credentials - Go to a user's dashboard, a few coures pages, etc.. - Expect to see messages show up in the SQS queue / its consumers after a minute or two delay - Expect to not see the same feature / context / value combo show up on repeated evaluations - Update the sampling_rate in dynamic_settings.yml to '0.0' and restart canvas - Flush redis cache - Go to the same pages as before - Expect to not see any more evaluations show up in SQS Change-Id: I189e127dd5f31dc5d504bf45d354e93f7208107a Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/278885 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeff Largent <jeff.largent@instructure.com> Product-Review: Jeff Largent <jeff.largent@instructure.com>
2021-11-19 23:04:48 +08:00
persist_result_context(feature, result)
InstStatsd::Statsd.increment("feature_flag_check", tags: { feature: feature, enabled: result.to_s })
result
end
Compute and send stats about feature evaluations This PS adds logic to compute context about a feature flag being evaluated at the time it is checked, and pushed to an SQS queue if configured. Whether or not to push the result of the evaluation to the queue is both sampled and cached so as to not overwhelm the queue or produce too much overhead on the Canvas side. The general process is: 1. Feature flag is evaluated 2. A random value between 0-1 is checked against a threshold stored in the dynamic setting feature_analytics.sampling_rate. 3. If under the threshold, the LocalCache is checked for any recent evaluations of the same flag / context / value combo. 4. If the result isn't already cached, the message is sent to SQS. 5. If anything unexpectedly goes wrong, an error is sent to Sentry and feature evaluation continues normally (no user-facing error). refs DE-926 flag = none Test plan: - Set up config in dynamic_settings.yml like the following: feature_analytics: cache_expiry: '60' sampling_rate: '1.0' queue_url: <canvas-feature-analytics SQS queue url in inseng> region: 'us-west-2' - Start canvas from a vaulted shell with inseng credentials - Go to a user's dashboard, a few coures pages, etc.. - Expect to see messages show up in the SQS queue / its consumers after a minute or two delay - Expect to not see the same feature / context / value combo show up on repeated evaluations - Update the sampling_rate in dynamic_settings.yml to '0.0' and restart canvas - Flush redis cache - Go to the same pages as before - Expect to not see any more evaluations show up in SQS Change-Id: I189e127dd5f31dc5d504bf45d354e93f7208107a Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/278885 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeff Largent <jeff.largent@instructure.com> Product-Review: Jeff Largent <jeff.largent@instructure.com>
2021-11-19 23:04:48 +08:00
def persist_result_context(feature, result)
context_type = self.class.name
return unless %w[Course Account].include?(context_type)
config = DynamicSettings.find("feature_analytics", tree: :private)
Compute and send stats about feature evaluations This PS adds logic to compute context about a feature flag being evaluated at the time it is checked, and pushed to an SQS queue if configured. Whether or not to push the result of the evaluation to the queue is both sampled and cached so as to not overwhelm the queue or produce too much overhead on the Canvas side. The general process is: 1. Feature flag is evaluated 2. A random value between 0-1 is checked against a threshold stored in the dynamic setting feature_analytics.sampling_rate. 3. If under the threshold, the LocalCache is checked for any recent evaluations of the same flag / context / value combo. 4. If the result isn't already cached, the message is sent to SQS. 5. If anything unexpectedly goes wrong, an error is sent to Sentry and feature evaluation continues normally (no user-facing error). refs DE-926 flag = none Test plan: - Set up config in dynamic_settings.yml like the following: feature_analytics: cache_expiry: '60' sampling_rate: '1.0' queue_url: <canvas-feature-analytics SQS queue url in inseng> region: 'us-west-2' - Start canvas from a vaulted shell with inseng credentials - Go to a user's dashboard, a few coures pages, etc.. - Expect to see messages show up in the SQS queue / its consumers after a minute or two delay - Expect to not see the same feature / context / value combo show up on repeated evaluations - Update the sampling_rate in dynamic_settings.yml to '0.0' and restart canvas - Flush redis cache - Go to the same pages as before - Expect to not see any more evaluations show up in SQS Change-Id: I189e127dd5f31dc5d504bf45d354e93f7208107a Reviewed-on: https://gerrit.instructure.com/c/canvas-lms/+/278885 Tested-by: Service Cloud Jenkins <svc.cloudjenkins@instructure.com> Reviewed-by: Simon Williams <simon@instructure.com> QA-Review: Jeff Largent <jeff.largent@instructure.com> Product-Review: Jeff Largent <jeff.largent@instructure.com>
2021-11-19 23:04:48 +08:00
cache_expiry = (config[:cache_expiry] || 1.day).to_i
sampling_rate = (config[:sampling_rate] || 0).to_f
return unless rand < sampling_rate
LocalCache.fetch(feature_analytics_cache_key(feature, result), expires_in: cache_expiry) do
message = {
feature: feature,
env: Canvas.environment,
context: context_type,
root_account_id: try(:root_account?) ? global_id : try(:global_root_account_id),
account_id: is_a?(Account) ? global_id : try(:global_account_id),
course_id: is_a?(Course) ? global_id : nil,
state: result,
timestamp: Time.now.to_f
}
Services::FeatureAnalyticsService.persist_feature_evaluation(message)
true
end
rescue => e
Canvas::Errors.capture_exception(:feature_analytics, e)
Rails.logger.error(e)
raise e if Rails.env.development?
end
feature flags infrastructure and API test plan: - install the test_features plugin (since no real features exist yet) - render and consult the feature flags documentation - have a test environment with a root account, sub-account, course in sub-account, and user - Use the "list features" endpoint as a root account admin (with no site admin privileges), on the root account context, and confirm that hidden features do not show up - Use the "list features" endpoint as a site admin user, on the root account context, and confirm that hidden features show up - Use the "list features" endpoint on the site admin account and confirm the hidden features show up - Use the "set feature flag" endpoint on a hidden feature on site admin and ensure the feature becomes visible in all root accounts - Use the "set feature flag endpoint" on a hidden feature on a single root account, and ensure the feature becomes visible to that root account and not others - Confirm that root_opt_in features appear "Off" by default in root accounts, after being "Allowed" in code or site admin - Confirm a feature flag that is set to "on" or "off" (vs. "allowed") cannot be overridden in a lower context (and the API returns locked=true for them) - Confirm that setting locking_account_id requires admin rights in the locking account - Confirm that a feature flag with locking_account_id cannot be changed without admin rights in the locking account (e.g., set a feature flag on a course, locked with the root account's id, and make sure a teacher who is not an account admin can't change it) - Confirm feature flags can be deleted with the "remove feature flag" endpoint (and they are only deleted where they are defined, not when called on an object that inherits a flag) Change-Id: I3e12e23b4454889b6e8b263f1315e82d8f2ada52 Reviewed-on: https://gerrit.instructure.com/25502 Tested-by: Jenkins <jenkins@instructure.com> QA-Review: Matt Fairbourn <mfairbourn@instructure.com> Product-Review: Matt Goodwin <mattg@instructure.com> Reviewed-by: Zach Pendleton <zachp@instructure.com>
2013-10-22 23:28:26 +08:00
end