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

Generated by: LCOV version 1.14