LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/config-client-mgr - config_cass2json_adapter.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 127 147 86.4 %
Date: 2026-11-09 02:10:49 Functions: 3 5 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
       3             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "config_cass2json_adapter.h"
       7             : 
       8             : #include <assert.h>
       9             : #include <boost/algorithm/string/predicate.hpp>
      10             : #include <boost/assign/list_of.hpp>
      11             : #include <string>
      12             : #include <iostream>
      13             : 
      14             : #include "base/string_util.h"
      15             : #include "config_cassandra_client.h"
      16             : #include "config_client_log.h"
      17             : #include "config_client_log_types.h"
      18             : #include "rapidjson/stringbuffer.h"
      19             : #include "rapidjson/writer.h"
      20             : 
      21             : using boost::assign::list_of;
      22             : using contrail_rapidjson::Document;
      23             : using contrail_rapidjson::StringBuffer;
      24             : using contrail_rapidjson::Value;
      25             : using contrail_rapidjson::Writer;
      26             : using std::cout;
      27             : using std::endl;
      28             : using std::set;
      29             : using std::string;
      30             : 
      31             : const string ConfigCass2JsonAdapter::fq_name_prefix = "fq_name";
      32             : const string ConfigCass2JsonAdapter::prop_prefix = "prop:";
      33             : const string ConfigCass2JsonAdapter::list_prop_prefix = "propl:";
      34             : const string ConfigCass2JsonAdapter::map_prop_prefix = "propm:";
      35             : const string ConfigCass2JsonAdapter::ref_prefix = "ref:";
      36             : const string ConfigCass2JsonAdapter::parent_prefix = "parent:";
      37             : const string ConfigCass2JsonAdapter::parent_type_prefix = "parent_type";
      38             : 
      39             : const set<string> ConfigCass2JsonAdapter::allowed_properties =
      40             :              list_of(prop_prefix)(map_prop_prefix)
      41             :                     (list_prop_prefix)(ref_prefix)(parent_prefix);
      42             : 
      43             : bool ConfigCass2JsonAdapter::assert_on_parse_error_ =
      44             :     getenv("CONTRAIL_CONFIG_ASSERT_ON_PARSE_ERROR") != NULL;
      45             : 
      46             : #define CONFIG_PARSE_ASSERT(t, condition)                                      \
      47             :     do {                                                                       \
      48             :         if (condition)                                                         \
      49             :             break;                                                             \
      50             :         CONFIG_CLIENT_WARN_LOG(ConfigurationMalformed ## t ## Warning ## Log,  \
      51             :             Category::CONFIG_CLIENT, c.key, c.value, type_, uuid_);            \
      52             :         CONFIG_CLIENT_TRACE(ConfigurationMalformed ## t ## Warning ## Trace,   \
      53             :             c.key, c.value, type_, uuid_);                                     \
      54             :         cout << "CONFIG_PARSE_ERROR " << __FILE__ << ":" << __LINE__ << " ";   \
      55             :         cout << type_ << " " << c.key << " " << c.value << " ";                \
      56             :         cout << uuid_ << endl;                                                 \
      57             :         if (assert_on_parse_error_)                                            \
      58             :             assert(false);                                                     \
      59             :         return;                                                                \
      60             :     } while (false)
      61             : 
      62        2752 : ConfigCass2JsonAdapter::ConfigCass2JsonAdapter(const string &uuid,
      63             :        ConfigCassandraClient *cassandra_client, const string &obj_type,
      64        2752 :        const CassColumnKVVec &cdvec) : cassandra_client_(cassandra_client),
      65        2752 :        uuid_(uuid) {
      66        2752 :     CreateJsonString(obj_type, cdvec);
      67        2752 : }
      68             : 
      69           0 : ConfigCass2JsonAdapter::ConfigCass2JsonAdapter(const string &uuid,
      70           0 :        const string &type, const Document &doc) : uuid_(uuid) {
      71             :     /**
      72             :       * Construct the final Json Document.
      73             :       */
      74           0 :     Document::AllocatorType &a = json_document_.GetAllocator();
      75           0 :     Value v;
      76           0 :     v.CopyFrom(doc, a);
      77             : 
      78           0 :     Value vk;
      79           0 :     json_document_.SetObject().AddMember(vk.SetString(type.c_str(), a),
      80             :                                          v, a);
      81           0 : }
      82             : 
      83           0 : string ConfigCass2JsonAdapter::GetJsonString(const Value &attr_value) {
      84           0 :     StringBuffer buffer;
      85           0 :     Writer<StringBuffer> writer(buffer);
      86           0 :     attr_value.Accept(writer);
      87           0 :     return buffer.GetString();
      88           0 : }
      89             : 
      90       16013 : void ConfigCass2JsonAdapter::AddOneEntry(Value *jsonObject,
      91             :     const string &obj_type, const JsonAdapterDataType &c,
      92             :     Document::AllocatorType &a) {
      93             : 
      94             :     // Process scalar property values.
      95       16013 :     if (boost::starts_with(c.key, prop_prefix)) {
      96        4990 :         string c_value = c.value;
      97        4990 :         if (c.key == "prop:bgpaas_session_attributes")
      98           0 :             c_value = "\"\"";
      99        4990 :         Document prop_document(&a);
     100        4990 :         prop_document.Parse<0>(c_value.c_str());
     101        4989 :         CONFIG_PARSE_ASSERT(Property, !prop_document.HasParseError());
     102        4989 :         Value vk;
     103        4989 :         jsonObject->AddMember(
     104        9979 :             vk.SetString(c.key.substr(prop_prefix.size()).c_str(), a),
     105             :                          prop_document, a);
     106        4990 :         return;
     107        4990 :     }
     108             : 
     109             :     // Process property list and  property map values.
     110       11023 :     bool is_map = false;
     111       21781 :     if ((is_map = boost::starts_with(c.key, map_prop_prefix)) ||
     112       10757 :             boost::starts_with(c.key, list_prop_prefix)) {
     113         528 :         size_t from_front_pos = c.key.find(':');
     114         528 :         size_t from_back_pos = c.key.rfind(':');
     115             :         string prop_map = c.key.substr(from_front_pos + 1,
     116         528 :                                        from_back_pos - from_front_pos - 1);
     117         528 :         string wrapper = cassandra_client_->mgr()-> \
     118         528 :                  config_json_parser()->GetWrapperFieldName(type_,
     119         528 :                                                        prop_map);
     120         528 :         if (wrapper.empty()) {
     121           0 :             return;
     122             :         }
     123         528 :         if (!jsonObject->HasMember(prop_map.c_str())) {
     124         280 :             Value v;
     125         280 :             Value vk;
     126         280 :             jsonObject->AddMember(
     127             :                 vk.SetString(prop_map.c_str(), a), v.SetObject(), a);
     128         280 :             Value va;
     129         280 :             Value vak;
     130         280 :             (*jsonObject)[prop_map.c_str()].AddMember(
     131             :                 vak.SetString(wrapper.c_str(), a), va.SetArray(), a);
     132         280 :         }
     133             : 
     134         528 :         Document map_document(&a);
     135         528 :         map_document.Parse<0>(c.value.c_str());
     136         528 :         if (is_map)
     137         268 :             CONFIG_PARSE_ASSERT(PropertyMap, !map_document.HasParseError());
     138             :         else
     139         260 :             CONFIG_PARSE_ASSERT(PropertyList, !map_document.HasParseError());
     140             : 
     141         528 :         (*jsonObject)[prop_map.c_str()][wrapper.c_str()].PushBack(
     142             :             map_document, a);
     143         528 :         return;
     144         528 :     }
     145             : 
     146       10498 :     if (boost::starts_with(c.key, ref_prefix)) {
     147        1224 :         size_t from_front_pos = c.key.find(':');
     148        1224 :         size_t from_back_pos = c.key.rfind(':');
     149        1224 :         CONFIG_PARSE_ASSERT(Reference, from_front_pos != string::npos);
     150        1224 :         CONFIG_PARSE_ASSERT(Reference, from_back_pos != string::npos);
     151             :         string ref_type = c.key.substr(from_front_pos + 1,
     152        1224 :                                        from_back_pos-from_front_pos - 1);
     153        1224 :         string ref_uuid = c.key.substr(from_back_pos + 1);
     154        1224 :         string fq_name_ref = c.ref_fq_name;
     155        1224 :         string r = ref_type + "_refs";
     156        1224 :         if (!jsonObject->HasMember(r.c_str())) {
     157        1190 :             Value v;
     158        1190 :             Value vk;
     159        1190 :             jsonObject->AddMember(vk.SetString(r.c_str(), a), v.SetArray(), a);
     160        1190 :         }
     161             : 
     162        1224 :         Value v;
     163        1224 :         v.SetObject();
     164             : 
     165        1224 :         Value vs1;
     166        1224 :         Value vs2;
     167        1224 :         v.AddMember("to", vs1.SetString(fq_name_ref.c_str(), a), a);
     168        1224 :         v.AddMember("uuid", vs2.SetString(ref_uuid.c_str(), a), a);
     169             : 
     170             :         bool link_with_attr =
     171        1224 :             cassandra_client_->mgr()->config_json_parser()->\
     172        1224 :             IsLinkWithAttr(obj_type, ref_type);
     173        1224 :         if (link_with_attr) {
     174         482 :             Document ref_document(&a);
     175         482 :             ref_document.Parse<0>(c.value.c_str());
     176         482 :             CONFIG_PARSE_ASSERT(ReferenceLinkAttributes,
     177             :                                 !ref_document.HasParseError());
     178         482 :             CONFIG_PARSE_ASSERT(ReferenceLinkAttributes,
     179             :                                 ref_document.HasMember("attr"));
     180         482 :             Value &attr_value = ref_document["attr"];
     181         482 :             if (!attr_value.IsNull()) {
     182         476 :                 v.AddMember("attr", attr_value, a);
     183             :             } else {
     184           6 :                 Value vm;
     185           6 :                 v.AddMember("attr", vm.SetObject(), a);
     186           6 :             }
     187         482 :         } else {
     188         742 :             Value vm;
     189         742 :             v.AddMember("attr", vm.SetObject(), a);
     190         742 :         }
     191        1224 :         (*jsonObject)[r.c_str()].PushBack(v, a);
     192        1224 :         return;
     193        1224 :     }
     194             : 
     195        9273 :     if (boost::starts_with(c.key, parent_prefix)) {
     196        1632 :         size_t pos = c.key.rfind(':');
     197        1632 :         CONFIG_PARSE_ASSERT(Parent, pos != string::npos);
     198        1632 :         size_t type_pos = c.key.find(':');
     199        1632 :         CONFIG_PARSE_ASSERT(Parent, type_pos != string::npos);
     200        1632 :         Value v;
     201        1632 :         Value vk;
     202        1632 :         jsonObject->AddMember(vk.SetString(parent_type_prefix.c_str(), a),
     203        1632 :                     v.SetString(c.key.substr(type_pos + 1,
     204        1632 :                                              pos-type_pos - 1).c_str(), a), a);
     205        1632 :         return;
     206        1632 :     }
     207             : 
     208        7641 :     if (!c.key.compare(fq_name_prefix)) {
     209        2751 :         Document fq_name_document(&a);
     210        2751 :         fq_name_document.Parse<0>(c.value.c_str());
     211        2751 :         CONFIG_PARSE_ASSERT(FqName, !fq_name_document.HasParseError());
     212        2752 :         Value vk;
     213        2752 :         jsonObject->AddMember(vk.SetString(c.key.c_str(), a),
     214             :                               fq_name_document, a);
     215        2752 :         return;
     216        2752 :     }
     217             : 
     218        4890 :     if (!c.key.compare("type")) {
     219             :         // Prepend the 'type'. This is "our key", with value being the json
     220             :         // sub-document containing all other columns.
     221        2752 :         CONFIG_PARSE_ASSERT(Type, type_ != obj_type);
     222        2752 :         type_ = c.value;
     223        2752 :         type_.erase(remove(type_.begin(), type_.end(), '\"'), type_.end());
     224        2752 :         return;
     225             :     }
     226             : }
     227             : 
     228        2752 : void ConfigCass2JsonAdapter::CreateJsonString(const string &obj_type,
     229             :                                               const CassColumnKVVec &cdvec) {
     230        2752 :     if (cdvec.empty())
     231           0 :         return;
     232        2752 :     Document::AllocatorType &a = json_document_.GetAllocator();
     233        2752 :     Value jsonObject;
     234        2752 :     jsonObject.SetObject();
     235             : 
     236             :     // First look for and part "type" field. We usually expect it to be at the
     237             :     // end as column keys are suppose to be allways sorted lexicographically.
     238        2752 :     size_t type_index = -1;
     239        2752 :     size_t i = cdvec.size();
     240        7133 :     while (i--) {
     241        7133 :         if (!cdvec[i].key.compare("type")) {
     242        2752 :             AddOneEntry(&jsonObject, obj_type, cdvec[i], a);
     243        2752 :             type_index = i;
     244        2752 :             break;
     245             :         }
     246             :     }
     247             : 
     248        2752 :     if (type_.empty()) {
     249             : 
     250           0 :         CONFIG_CLIENT_WARN_LOG(ConfigurationMissingTypeWarningLog,
     251             :                                Category::CONFIG_CLIENT, uuid_, obj_type);
     252           0 :         CONFIG_CLIENT_TRACE(ConfigurationMissingTypeWarningTrace, uuid_,
     253             :                             obj_type);
     254           0 :         return;
     255             :     }
     256             : 
     257       18767 :     for (size_t i = 0; i < cdvec.size(); ++i) {
     258       16014 :         if (i != type_index)
     259       13261 :             AddOneEntry(&jsonObject, obj_type, cdvec[i], a);
     260             :     }
     261             : 
     262        2752 :     Value vk;
     263        2752 :     json_document_.SetObject().AddMember(vk.SetString(type_.c_str(), a),
     264             :                                          jsonObject, a);
     265        2752 : }

Generated by: LCOV version 1.14