LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - feature_flags.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 41 56 73.2 %
Date: 2026-08-03 02:19:58 Functions: 17 17 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2020 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #ifndef BASE_FEATURE_FLAGS_H_
       6             : #define BASE_FEATURE_FLAGS_H_
       7             : 
       8             : #include <string>
       9             : #include <mutex>
      10             : 
      11             : #include <boost/function.hpp>
      12             : #include <boost/scoped_ptr.hpp>
      13             : 
      14             : #include <base/logging.h>
      15             : #include <base/sandesh/process_info_constants.h>
      16             : #include <base/sandesh/process_info_types.h>
      17             : 
      18             : #include "rapidjson/document.h"
      19             : #include "rapidjson/stringbuffer.h"
      20             : #include "rapidjson/writer.h"
      21             : 
      22             : /**
      23             :  * -----------------------------------------------------------------------------
      24             :  * C++ feature flag interface for developers
      25             :  * -----------------------------------------------------------------------------
      26             :  *
      27             :  * The Flag class serves as the interface for modules interested in one or
      28             :  * more feature flags.
      29             :  *
      30             :  * Developers bringing in new features can declare a flag in global scope.
      31             :  * Construction requires specifying a name, description of the flag, and a
      32             :  * default value.
      33             :  *
      34             :  *     Flag flag_enable_hash_v2("Hash V2", "Enable the use of
      35             :  *                               the new generation hash table", false);
      36             :  *
      37             :  * A flag can be declared as belonging to the instance of an object. This
      38             :  * means that it can have a different definition per object.
      39             :  *
      40             :  *     class Module {
      41             :  *       public:
      42             :  *         Module(const std::string interface_name, const Options& options);
      43             :  *       private:
      44             :  *         Flag enable_hash_v2_;
      45             :  *         HashTable* ht_;
      46             :  *     };
      47             :  *
      48             :  * When a module is instantiated, the internal flag is initialized. The
      49             :  * initialization uses the global flag definition and can be personalized.
      50             :  * The second parameter is a key-value dict that provides the context info
      51             :  * and the third parameter is a callback that will be invoked if there are
      52             :  * configuration or run-time updates to the feature flag definition.
      53             :  *
      54             :  *     Module::Module(const std::string name, const Options& options)
      55             :  *         : enable_hash_v2_(flag_enable_hash_v2,
      56             :  *                           {"interface", interface_name},
      57             :  *                           flag_update_cb) {
      58             :  *         if (enable_hash_v2_.Get()) {
      59             :  *             ht_ = NewFancyHashTable();
      60             :  *         } else {
      61             :  *             ht_ = OldHashTable();
      62             :  *         }
      63             :  *     }
      64             :  *
      65             :  * The FlagConfig class serves as an interface for storing user configuration
      66             :  * for features.
      67             :  * User configuration for feature flag is provided to the FlagManager
      68             :  * using this class. Used by servers providing config data (ifmap_server)
      69             :  * Data provided includes
      70             :  * 1. Flag name
      71             :  * 2. bool indicating if flag is enabled
      72             :  * 3. bool indicating default value
      73             :  * 4. Release in which the flag was introduced
      74             :  * 5. Context Info (optional)
      75             :  *
      76             :  * The FlagManager class is a flag store that maintains the list of feature
      77             :  * flags modules are interested in and the user configuration for them if any.
      78             :  * When the Flag class is instantiated, it automatically registers itself with
      79             :  * the flag store. When the FlagConfig class is instantiated, it informs the
      80             :  * flag store of the user configuration for flags. The FlagManager class on
      81             :  * receiving the user configuration for a flag will update the flag and sets
      82             :  * the "enabled" field in accordance with the user configuration. In addition,
      83             :  * it will invoke any callbacks registered by modules.
      84             :  *
      85             :  * A FlagUveManager class is responsible for providing functionality to interface
      86             :  * with analytics/introspect to provide data on the feature flags configured
      87             :  * in each module. Analytics registers callbacks using this class which will
      88             :  * be called when there is a change to flag definition or configuration.
      89             :  * -----------------------------------------------------------------------------
      90             :  */
      91             : 
      92             : namespace process {
      93             : 
      94             : class FlagManager;
      95             : 
      96             : 
      97             : /**
      98             :  * --------------------------------------------------------------------------
      99             :  * Helper structs for representing flag config, state and context
     100             :  * --------------------------------------------------------------------------
     101             :  */
     102             : 
     103             : struct FlagState {
     104             :     enum Type {
     105             :       EXPERIMENTAL = 0,
     106             :       ALPHA = 1,
     107             :       BETA = 2,
     108             :       IN_PROGRESS = 3,
     109             :       PRE_RETIRED = 4,
     110             :       UNKNOWN = 5
     111             :     };
     112             : 
     113          10 :     static std::string ToString(Type state) {
     114          10 :         switch (state) {
     115          10 :         case EXPERIMENTAL:
     116          10 :             return "Experimental";
     117             :         break;
     118           0 :         case ALPHA:
     119           0 :             return "Alpha";
     120             :         break;
     121           0 :         case BETA:
     122           0 :             return "Beta";
     123             :         break;
     124           0 :         case IN_PROGRESS:
     125           0 :             return "In Progress";
     126             :         break;
     127           0 :         case PRE_RETIRED:
     128           0 :             return "Pre Retired";
     129             :         break;
     130           0 :         case UNKNOWN:
     131           0 :             return "Unknown";
     132             :         break;
     133             :         }
     134           0 :         return "Unknown";
     135             :     }
     136             : 
     137             :     static Type FromString(const std::string& type) {
     138             :         if (type == "Experimental") {
     139             :             return EXPERIMENTAL;
     140             :         }
     141             :         if (type == "Alpha") {
     142             :             return ALPHA;
     143             :         }
     144             :         if (type == "Beta") {
     145             :             return BETA;
     146             :         }
     147             :         if (type == "In-Progress") {
     148             :             return IN_PROGRESS;
     149             :         }
     150             :         if (type == "Pre-Retired") {
     151             :             return PRE_RETIRED;
     152             :         }
     153             :         if (type == "Unknown") {
     154             :             return UNKNOWN;
     155             :         }
     156             :         return UNKNOWN;
     157             :     }
     158             : };
     159             : 
     160             : struct FlagContext {
     161           4 :     FlagContext(const std::string& description, const std::string &val)
     162           4 :         : desc(description),
     163           4 :           value(val) {}
     164             : 
     165          22 :     bool operator == (const FlagContext & rhs) const {
     166          22 :       if (!(desc == rhs.desc))
     167           6 :         return false;
     168          16 :       if (!(value == rhs.value))
     169           6 :         return false;
     170          10 :       return true;
     171             :     }
     172             :     bool operator != (const FlagContext &rhs) const {
     173             :       return !(*this == rhs);
     174             :     }
     175             : 
     176             :     std::string desc;
     177             :     std::string value;
     178             : };
     179             : 
     180             : typedef std::vector<FlagContext> ContextVec;
     181             : typedef std::vector<FlagContext>::const_iterator context_iterator;
     182             : typedef std::vector<FlagContext>::size_type context_size;
     183             : 
     184             : class FlagConfig {
     185             : public:
     186           8 :     FlagConfig(const std::string &name,const std::string &version,
     187             :                bool enabled, FlagState::Type state, ContextVec &context_infos)
     188           8 :         : name_(name),
     189           8 :           version_(version),
     190           8 :           enabled_(enabled),
     191           8 :           state_(state),
     192           8 :           context_infos_(context_infos) {}
     193         126 :     ~FlagConfig() {};
     194             : 
     195             :     /**
     196             :      * Getter/Setter functions for members
     197             :      */
     198             :     void set_name(const std::string &val) { name_ = val; }
     199          87 :     const std::string& name() const { return name_; }
     200             : 
     201             :     void set_version(const std::string &val) { version_ = val; }
     202          10 :     const std::string& version() const { return version_; }
     203             : 
     204             :     void set_enabled(bool val) { enabled_ = val; }
     205          22 :     bool enabled() const { return enabled_; }
     206             : 
     207             :     void set_state(const FlagState::Type &val) { state_ = val; }
     208          10 :     const FlagState::Type& state() const { return state_; }
     209             : 
     210             :     void set_context_infos(const ContextVec &val) { context_infos_ = val; }
     211          22 :     const ContextVec &context_infos() const { return context_infos_; }
     212             : 
     213           2 :     bool operator == (const FlagConfig &rhs) const {
     214           2 :         if (!(name_ == rhs.name_))
     215           0 :             return false;
     216           2 :         if (!(version_ == rhs.version_))
     217           0 :             return false;
     218           2 :         if (!(enabled_ == rhs.enabled_))
     219           1 :             return false;
     220           1 :         if (!(state_ == rhs.state_))
     221           0 :             return false;
     222           1 :         if (!(context_infos_ == rhs.context_infos_))
     223           1 :             return false;
     224           0 :         return true;
     225             :     }
     226             : 
     227           2 :     bool operator != (const FlagConfig &rhs) const {
     228           2 :         return !(*this == rhs);
     229             :     }
     230             : private:
     231             :     std::string name_;
     232             :     std::string version_;
     233             :     bool enabled_;
     234             :     FlagState::Type state_;
     235             :     ContextVec context_infos_;
     236             : };
     237             : 
     238             : typedef std::vector<FlagConfig> FlagConfigVec;
     239             : typedef std::vector<FlagConfig>::const_iterator flag_cfg_itr;
     240             : 
     241             : 
     242             : /**
     243             :  * ----------------------------------------------------------------------------
     244             :  * Class representing a feature flag
     245             :  *
     246             :  * Modules can use this class to define flags they are interested in.
     247             :  * Data provided by module includes
     248             :  * 1. Flag name
     249             :  * 2. Description
     250             :  * 3. Context Info (optional)
     251             :  * 4. Callback for run-time updates (optional)
     252             :  * The Flag class will in turn register this Flag with the Flag Manager.
     253             :  *
     254             :  * ----------------------------------------------------------------------------
     255             :  */
     256             : 
     257             : class Flag
     258             : {
     259             : public:
     260             :     /**
     261             :      * ----------------------------------------------------------------------
     262             :      * Callback provided by module to track run-time updates to feature
     263             :      * flag configuration.
     264             :      * ----------------------------------------------------------------------
     265             :      */
     266             :     typedef boost::function<void ()> FlagStateCb;
     267             : 
     268             :     /**
     269             :      * This constructor is used to create a feature flag with basic
     270             :      * information; name, description, default behavior and optional
     271             :      * context information.
     272             :      */
     273             :     Flag(FlagManager *manager, const std::string &name,
     274             :          const std::string &description, bool enabled,
     275             :          ContextVec &context_infos);
     276             : 
     277             :     /**
     278             :      * This constructor takes a Flag object with basic information with
     279             :      * provision for components to act on run-time updates through a callback
     280             :      */
     281             :     Flag(const Flag& flag, FlagStateCb callback);
     282             : 
     283             :     /**
     284             :      * Default Constructor
     285             :      */
     286             :     Flag() {};
     287             :     ~Flag();
     288             : 
     289             :     /**
     290             :      * Method to invoke callback provided by modules for this flag
     291             :      */
     292             :     void InvokeCb();
     293             : 
     294             :     /**
     295             :      * Getter/Setter functions for members
     296             :      */
     297             :     void set_name(const std::string &val) { name_ = val; }
     298          15 :     const std::string& name() const { return name_; }
     299             : 
     300             :     void set_description(const std::string &val) { description_ = val; }
     301             :     const std::string& description() const { return description_; }
     302             : 
     303           4 :     void set_enabled(const bool val) { enabled_ = val; }
     304           9 :     const bool enabled() const { return enabled_; }
     305             : 
     306             :     void set_context_infos(const ContextVec &val) { context_infos_ = val; }
     307           4 :     const ContextVec &context_infos() const { return context_infos_; }
     308             : 
     309             :     bool operator == (const Flag &rhs) const;
     310             :     bool operator != (const Flag &rhs) const;
     311             : private:
     312             :     std::string name_;
     313             :     std::string description_;
     314             :     bool enabled_;
     315             :     ContextVec context_infos_;
     316             : 
     317             :     FlagStateCb flag_state_cb_;
     318             :     FlagManager *manager_;
     319             : 
     320             :     DISALLOW_COPY_AND_ASSIGN(Flag);
     321             : };
     322             : 
     323             : typedef std::vector<Flag> FlagVec;
     324             : 
     325             : /**
     326             :  * -----------------------------------------------------------------------------
     327             :  * User configuration for feature flag is provided to the FlagManager
     328             :  * using this class. Used by servers providing config data (ifmap_server)
     329             :  * Data provided includes
     330             :  * 1. Flag name
     331             :  * 2. bool indicating if flag is enabled
     332             :  * 3. bool indicating default value
     333             :  * 4. Release in which the flag was introduced
     334             :  * 5. Context Info (optional)
     335             :  * -----------------------------------------------------------------------------
     336             :  */
     337             : class FlagConfigManager {
     338             : public:
     339             :     static FlagConfigManager* GetInstance();
     340             :     static void Initialize(const string &build_info);
     341             : 
     342             :     /**
     343             :      * API to set/update user config. Called when run-time updates are
     344             :      * received for feature.
     345             :      */
     346             :     void Set(const std::string &name,const std::string &version_info,
     347             :              bool enabled, FlagState::Type state, ContextVec &context_infos);
     348             : 
     349             :     /**
     350             :      * API to unset user config. Called when user unconfigures feature flag.
     351             :      */
     352             :     void Unset(const std::string &name);
     353             : 
     354             : private:
     355             :     // Singleton
     356             :     FlagConfigManager(FlagManager *manager);
     357             : 
     358             :     static boost::scoped_ptr<FlagConfigManager> instance_;
     359             :     FlagManager *flag_manager_;
     360             : 
     361             :     static std::string version_;
     362             : 
     363             :     DISALLOW_COPY_AND_ASSIGN(FlagConfigManager);
     364             : };
     365             : 
     366             : // ----------------------------------------------------------------------------
     367             : 
     368             : /**
     369             :  * -----------------------------------------------------------------------------
     370             :  *
     371             :  * FlagUveManager class responsible for providing functionality to interface
     372             :  * with analytics/introspect to provide data on the feature flags configured
     373             :  * in each module. Analytics registers callbacks using this class which will
     374             :  * be called when there is a change to flag definition or configuration.
     375             :  *
     376             :  * -----------------------------------------------------------------------------
     377             :  */
     378             : class FlagUveManager {
     379             : public:
     380             :     static FlagUveManager* GetInstance();
     381             : 
     382             :     /**
     383             :      * --------------------
     384             :      *  Analytics Callbacks
     385             :      * --------------------
     386             :      */
     387             : 
     388             :     /**
     389             :      * Helper class handling analytics registers a callback(flag_uve_cb) with
     390             :      * FlagUveManager. This will be invoked when the FlagUveManager
     391             :      * processes any user configuration for the flags.
     392             :      */
     393             :     void SendUVE();
     394             : 
     395             :     /**
     396             :      * API to get all user-configured flags
     397             :     */
     398             :     FlagConfigVec GetFlagInfos(bool lock) const;
     399             : private:
     400             :     friend class ConnectionStateManager;
     401             : 
     402             :     /**
     403             :      * UVE callback from ConnectionStateManager. This is called
     404             :      * to report information on feature flags capability by user
     405             :      * that modules are interested in.
     406             :      */
     407             :     typedef boost::function<void (void)> FlagUveCb;
     408             : 
     409             :     // Singleton
     410             :     FlagUveManager(FlagManager *manager, FlagUveCb send_uve_cb);
     411             :     static void CreateInstance(FlagManager *mgr, FlagUveCb send_uve_cb);
     412             : 
     413             :     static boost::scoped_ptr<FlagUveManager> instance_;
     414             :     FlagManager *flag_manager_;
     415             :     FlagUveCb flag_uve_cb_;
     416             : 
     417             :     DISALLOW_COPY_AND_ASSIGN(FlagUveManager);
     418             : };
     419             : 
     420             : // ----------------------------------------------------------------------------
     421             : 
     422             : /**
     423             :  * -----------------------------------------------------------------------------
     424             :  *
     425             :  * FlagManager class responsible for providing functionality to maintain both
     426             :  * feature flags capability by users and the feature modules are interested in.
     427             :  * It will also interface with analytics/introspect to provide data on the
     428             :  * feature flags capability in each module.
     429             :  *
     430             :  * Accordingly, the class will provide APIs
     431             :  * 1. to interface with the north-bound server providing information on user
     432             :  *    capability feature flags and the feature flags available in the system
     433             :  *    (capability list)
     434             :  * 2. to interface with the modules. These include client APIs for the modules
     435             :  *    a. to query if a feature is enabled/disabled
     436             :  *    b. to get user capability information for a feature flag
     437             :  *    c. to capture module interest in relevant feature flags
     438             :  * 3. to interface with analytics and send module level feature flag information
     439             :  *    to analytics/introspect
     440             :  *
     441             :  * -----------------------------------------------------------------------------
     442             :  */
     443             : 
     444             : class FlagManager
     445             : {
     446             : public:
     447             :     static FlagManager* GetInstance();
     448             : 
     449             :     /**
     450             :      * -------------
     451             :      * FlagMap APIs
     452             :      * -------------
     453             :      */
     454             : 
     455             :     /**
     456             :      * Process feature flags config and update FlagMap
     457             :      */
     458             :     void Set(const std::string &name, const std::string &version, bool enabled,
     459             :              FlagState::Type state, ContextVec &context_infos);
     460             : 
     461             :     /**
     462             :      * Feature flag removed from config. Process delete.
     463             :      */
     464             :     void Unset(const std::string &name);
     465             : 
     466             :     /**
     467             :      * Request from module to check if a feature flag is enabled
     468             :      * Module provides flag name and context for which it wants
     469             :      * to check if flag is enabled.
     470             :      */
     471             :     bool IsFlagEnabled(const std::string &name, bool default_state,
     472             :                        const ContextVec &c_vec) const;
     473             : 
     474             :     /**
     475             :      * Remove all flag data from FlagMap
     476             :      */
     477             :     void ClearFlags();
     478             : 
     479             :     /**
     480             :      * Get the number of flags in FlagMap
     481             :      */
     482             :     size_t GetFlagMapCount() const;
     483             : 
     484             :     /**
     485             :      * -----------------
     486             :      * InterestMap APIs
     487             :      * -----------------
     488             :      */
     489             : 
     490             :     /**
     491             :      * Update InterestMap with feature flags modules are interested in.
     492             :      * The Flag object will be updated when user configuration is received by
     493             :      * the FlagManager.
     494             :      */
     495             :     void Register(Flag *flag);
     496             : 
     497             :     /**
     498             :      * Module is no longer interested in the flag. Remove from InterestMap
     499             :      */
     500             :     void Unregister(const Flag *flag);
     501             : 
     502             :     /**
     503             :      * Check if module has registered this feature flag
     504             :      */
     505             :     bool IsRegistered(const Flag *flag) const;
     506             : 
     507             :     /**
     508             :      * Get the number of flags in InterestMap
     509             :      */
     510             :     size_t GetIntMapCount() const;
     511             : 
     512             :     /**
     513             :      * ---------------------
     514             :      * Analytics helper APIs
     515             :      * ---------------------
     516             :      */
     517             : 
     518             :     /**
     519             :      * API for helper class to get flag configuration information.
     520             :      * Returns vector<FlagConfig>
     521             :      */
     522             :     FlagConfigVec GetFlagInfos() const;
     523             : 
     524             : private:
     525             :     friend class Flag;
     526             :     friend class FlagConfigManager;
     527             :     friend class FlagUveManager;
     528             : 
     529          48 :     FlagManager() {
     530          48 :     }
     531             : 
     532             :     /**
     533             :      * =============================================
     534             :      * FlagMap - User Configuration/Capability list
     535             :      * =============================================
     536             :      */
     537             : 
     538             :     /**
     539             :      * Map that maintains flag information capability by user
     540             :      * User configures flag name, whether it is enabled and
     541             :      * optional flag context info.
     542             :      */
     543             :     typedef std::map<std::string, FlagConfig> FlagMap;
     544             :     typedef std::map<std::string, FlagConfig>::iterator flag_map_itr;
     545             :     typedef std::map<std::string, FlagConfig>::const_iterator flag_map_citr;
     546             : 
     547             :     /**
     548             :      * ===================================
     549             :      * InterestMap - Module interest list
     550             :      * ===================================
     551             :      */
     552             : 
     553             :     /**
     554             :      * Map that maintains flags modules are interested in
     555             :      * Modules provide name, description and a default value
     556             :      * NOTE: modules can define the same flag in multiple ways based on
     557             :      * varying the context. Hence the InteretMap can have multiple entries
     558             :      * for the same flag. For a given (flag name, context_info) though
     559             :      * there will be one unique entry in the InterestMap
     560             :      */
     561             :     typedef std::multimap<std::string, Flag *> InterestMap;
     562             :     typedef std::multimap<std::string, Flag *>::const_iterator int_map_const_itr;
     563             :     typedef std::multimap<std::string, Flag *>::iterator int_map_itr;
     564             : 
     565             :     // ==============================================================
     566             : 
     567             :     FlagConfigVec GetFlagInfosUnlocked() const;
     568             : 
     569             :     static boost::scoped_ptr<FlagManager> instance_;
     570             :     mutable std::mutex mutex_;
     571             : 
     572             :     FlagMap flag_map_; // map for capability-list/user-config
     573             :     InterestMap int_map_; // map for storing module interest
     574             : 
     575             :     DISALLOW_COPY_AND_ASSIGN(FlagManager);
     576             : };
     577             : 
     578             : 
     579             : } // namespace process
     580             : #endif // BASE_FEATURE_FLAGS_H_

Generated by: LCOV version 1.14