Line data Source code
1 : /*
2 : * Copyright (c) 2016 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include "config_json_parser.h"
6 :
7 : #include <boost/lexical_cast.hpp>
8 : #include <sandesh/request_pipeline.h>
9 : #include <string>
10 :
11 : #include "config-client-mgr/config_client_manager.h"
12 : #include "ifmap/ifmap_log.h"
13 : #include "ifmap/ifmap_log_types.h"
14 : #include "ifmap/ifmap_sandesh_context.h"
15 : #include "ifmap/ifmap_server_show_types.h"
16 : #include "base/autogen_util.h"
17 : #include "schema/bgp_schema_types.h"
18 : #include "schema/vnc_cfg_types.h"
19 : #include "config-client-mgr/config_client_show_types.h"
20 : #include "config-client-mgr/config_client_log_types.h"
21 : #include "config-client-mgr/config_cass2json_adapter.h"
22 : #include "config-client-mgr/config_amqp_client.h"
23 : #include "config-client-mgr/config_db_client.h"
24 :
25 : using contrail_rapidjson::Value;
26 : using std::cout;
27 : using std::endl;
28 : using std::string;
29 :
30 : #define CONFIG_PARSE_ASSERT(t, condition, key, value) \
31 : do { \
32 : if (condition) \
33 : break; \
34 : IFMAP_WARN_LOG(ConfigurationMalformed ## t ## Warning ## Log, \
35 : Category::IFMAP, key, value, adapter.type(), \
36 : adapter.uuid()); \
37 : IFMAP_TRACE(ConfigurationMalformed ## t ## Warning ## Trace, \
38 : key, value, adapter.type(), adapter.uuid()); \
39 : if (ConfigCass2JsonAdapter::assert_on_parse_error()) \
40 : assert(false); \
41 : return false; \
42 : } while (false)
43 :
44 158 : ConfigJsonParser::ConfigJsonParser() {
45 158 : }
46 :
47 316 : ConfigJsonParser::~ConfigJsonParser() {
48 316 : }
49 :
50 158 : void ConfigJsonParser::SetupObjectFilter() {
51 158 : ObjectTypeList FilterList;
52 158 : bgp_schema_Server_GenerateObjectTypeList(&FilterList);
53 158 : vnc_cfg_Server_GenerateObjectTypeList(&FilterList);
54 158 : for (ObjectTypeList::iterator it = FilterList.begin();
55 18802 : it != FilterList.end(); it++) {
56 18644 : AddObjectType(*it);
57 : }
58 158 : }
59 :
60 158 : void ConfigJsonParser::SetupSchemaGraphFilter(){
61 158 : vnc_cfg_FilterInfo vnc_filter_info;
62 158 : bgp_schema_FilterInfo bgp_schema_filter_info;
63 :
64 158 : bgp_schema_Server_GenerateGraphFilter(&bgp_schema_filter_info);
65 158 : vnc_cfg_Server_GenerateGraphFilter(&vnc_filter_info);
66 :
67 158 : for (vnc_cfg_FilterInfo::iterator it = vnc_filter_info.begin();
68 61146 : it != vnc_filter_info.end(); it++) {
69 60988 : if (it->is_ref_) {
70 42660 : AddLinkName(make_pair(it->left_, it->right_),
71 85320 : make_pair(it->metadata_, it->linkattr_));
72 : } else {
73 18328 : AddParentName(make_pair(it->left_, it->right_),
74 18328 : it->metadata_);
75 : }
76 : }
77 :
78 158 : for (bgp_schema_FilterInfo::iterator it = bgp_schema_filter_info.begin();
79 1896 : it != bgp_schema_filter_info.end(); it++) {
80 1738 : if (it->is_ref_) {
81 1264 : AddLinkName(make_pair(it->left_, it->right_),
82 2528 : make_pair(it->metadata_, it->linkattr_));
83 : } else {
84 474 : AddParentName(make_pair(it->left_, it->right_),
85 474 : it->metadata_);
86 : }
87 : }
88 158 : }
89 :
90 158 : void ConfigJsonParser::SetupSchemaWrapperPropertyInfo() {
91 158 : WrapperFieldMap wrapper_field_map;
92 158 : bgp_schema_Server_GenerateWrapperPropertyInfo(&wrapper_field_map);
93 158 : vnc_cfg_Server_GenerateWrapperPropertyInfo(&wrapper_field_map);
94 158 : for (WrapperFieldMap::iterator it = wrapper_field_map.begin();
95 22594 : it != wrapper_field_map.end(); it++) {
96 22436 : AddWrapperField(it->first, it->second);
97 : }
98 158 : }
99 :
100 158 : void ConfigJsonParser::SetupGraphFilter() {
101 158 : SetupObjectFilter();
102 158 : SetupSchemaGraphFilter();
103 158 : SetupSchemaWrapperPropertyInfo();
104 158 : }
105 0 : void ConfigJsonParser::EndOfConfig() {
106 0 : ifmap_server_->CleanupStaleEntries();
107 0 : }
108 :
109 118026 : void ConfigJsonParser::MetadataRegister(const string &metadata,
110 : MetadataParseFn parser) {
111 : pair<MetadataParseMap::iterator, bool> result =
112 118026 : metadata_map_.insert(make_pair(metadata, parser));
113 118026 : assert(result.second);
114 118026 : }
115 :
116 158 : void ConfigJsonParser::MetadataClear(const string &module) {
117 158 : metadata_map_.clear();
118 158 : }
119 :
120 6177 : IFMapTable::RequestKey *ConfigJsonParser::CloneKey(
121 : const IFMapTable::RequestKey &src) const {
122 6177 : IFMapTable::RequestKey *retkey = new IFMapTable::RequestKey();
123 6177 : retkey->id_type = src.id_type;
124 6177 : retkey->id_name = src.id_name;
125 : // Tag each DB Request with current generation number
126 6177 : retkey->id_seq_num = GetGenerationNumber();
127 6177 : return retkey;
128 : }
129 :
130 2452 : bool ConfigJsonParser::ParseNameType(const ConfigCass2JsonAdapter &adapter,
131 : IFMapTable::RequestKey *key) const {
132 : // Type is the name of the document.
133 2452 : Value::ConstMemberIterator itr = adapter.document().MemberBegin();
134 2452 : CONFIG_PARSE_ASSERT(Type, autogen::ParseString(itr->name, &key->id_type),
135 : "Name", "Bad name");
136 :
137 2452 : key->id_type = itr->name.GetString();
138 :
139 : // Name is the fq_name field in the document.
140 2452 : const Value &value_node = itr->value;
141 2452 : CONFIG_PARSE_ASSERT(FqName, value_node.HasMember("fq_name"), key->id_type,
142 : "Missing FQ name");
143 2452 : const Value &fq_name_node = value_node["fq_name"];
144 2452 : CONFIG_PARSE_ASSERT(FqName, fq_name_node.IsArray(), key->id_type,
145 : "FQ name is not an array");
146 2452 : CONFIG_PARSE_ASSERT(FqName, fq_name_node.Size(),
147 : key->id_type, "FQ name array is empty");
148 :
149 2452 : size_t i = 0;
150 :
151 : // Iterate over all items except the last one.
152 6114 : for (; i < fq_name_node.Size() - 1; ++i) {
153 3662 : key->id_name += fq_name_node[i].GetString();
154 3662 : key->id_name += string(":");
155 : }
156 2449 : key->id_name += fq_name_node[i].GetString();
157 :
158 2452 : return true;
159 : }
160 :
161 8641 : bool ConfigJsonParser::ParseOneProperty(const ConfigCass2JsonAdapter &adapter,
162 : const Value &key_node, const Value &value_node,
163 : const IFMapTable::RequestKey &key, IFMapOrigin::Origin origin,
164 : RequestList *req_list, bool add_change) const {
165 8641 : string metaname = key_node.GetString();
166 8641 : MetadataParseMap::const_iterator loc = metadata_map_.find(metaname);
167 8641 : if (loc == metadata_map_.end()) {
168 4784 : return true;
169 : }
170 :
171 : // Treat updates with NULL value as deletes.
172 3857 : if (add_change && value_node.IsNull())
173 4 : add_change = false;
174 3857 : std::unique_ptr<AutogenProperty> pvalue;
175 3857 : if (add_change) {
176 3669 : bool success = (loc->second)(value_node, &pvalue);
177 3669 : CONFIG_PARSE_ASSERT(Property, success, metaname,
178 : "No entry in metadata map");
179 : } else {
180 188 : const string key = metaname;
181 188 : if (!IsListOrMapPropEmpty(adapter.uuid(), key)) {
182 32 : return true;
183 : }
184 188 : }
185 3825 : std::replace(metaname.begin(), metaname.end(), '_', '-');
186 3825 : InsertRequestIntoQ(origin, "", "", metaname, pvalue, key,
187 : add_change, req_list);
188 3825 : return true;
189 8641 : }
190 :
191 2452 : bool ConfigJsonParser::ParseProperties(const ConfigCass2JsonAdapter &adapter,
192 : const IFMapTable::RequestKey &key, IFMapOrigin::Origin origin,
193 : RequestList *req_list, bool add_change) const {
194 :
195 2452 : Value::ConstMemberIterator doc_itr = adapter.document().MemberBegin();
196 2452 : const Value &value_node = doc_itr->value;
197 2452 : for (Value::ConstMemberIterator itr = value_node.MemberBegin();
198 11093 : itr != value_node.MemberEnd(); ++itr) {
199 8641 : ParseOneProperty(adapter, itr->name, itr->value, key, origin,
200 : req_list, add_change);
201 : }
202 :
203 2452 : return true;
204 : }
205 :
206 942 : bool ConfigJsonParser::ParseRef(const ConfigCass2JsonAdapter &adapter,
207 : const Value &ref_entry, IFMapOrigin::Origin origin,
208 : const string &refer, const IFMapTable::RequestKey &key,
209 : RequestList *req_list, bool add_change) const {
210 942 : const Value& to_node = ref_entry["to"];
211 :
212 942 : string from_underscore = key.id_type;
213 942 : std::replace(from_underscore.begin(), from_underscore.end(), '-', '_');
214 : string link_name =
215 942 : GetLinkName(from_underscore, refer);
216 942 : CONFIG_PARSE_ASSERT(Reference, !link_name.empty(), refer,
217 : "Link name is empty");
218 942 : string metaname = link_name;
219 942 : std::replace(metaname.begin(), metaname.end(), '-', '_');
220 :
221 942 : MetadataParseMap::const_iterator loc = metadata_map_.find(metaname);
222 942 : CONFIG_PARSE_ASSERT(Reference, loc != metadata_map_.end(), metaname,
223 : "No entry in metadata map");
224 :
225 942 : std::unique_ptr<AutogenProperty> pvalue;
226 942 : if (ref_entry.HasMember("attr")) {
227 942 : const Value& attr_node = ref_entry["attr"];
228 942 : bool success = (loc->second)(attr_node, &pvalue);
229 942 : CONFIG_PARSE_ASSERT(ReferenceLinkAttributes, success, metaname,
230 : "Link attribute parse error");
231 : }
232 :
233 942 : string neigh_name;
234 942 : neigh_name += to_node.GetString();
235 :
236 942 : InsertRequestIntoQ(origin, refer, neigh_name,
237 : link_name, pvalue, key, add_change, req_list);
238 :
239 942 : return true;
240 942 : }
241 :
242 922 : bool ConfigJsonParser::ParseOneRef(const ConfigCass2JsonAdapter &adapter,
243 : const Value &arr, const IFMapTable::RequestKey &key,
244 : IFMapOrigin::Origin origin, RequestList *req_list,
245 : const string &key_str, size_t pos, bool add_change) const {
246 922 : string refer = key_str.substr(0, pos);
247 922 : CONFIG_PARSE_ASSERT(Reference, arr.IsArray(), refer, "Invalid referene");
248 1864 : for (size_t i = 0; i < arr.Size(); ++i)
249 942 : ParseRef(adapter, arr[i], origin, refer, key, req_list, add_change);
250 922 : return true;
251 922 : }
252 :
253 2452 : bool ConfigJsonParser::ParseLinks(const ConfigCass2JsonAdapter &adapter,
254 : const IFMapTable::RequestKey &key, IFMapOrigin::Origin origin,
255 : RequestList *req_list, bool add_change) const {
256 2452 : Value::ConstMemberIterator doc_itr = adapter.document().MemberBegin();
257 2452 : const Value &properties = doc_itr->value;
258 2452 : for (Value::ConstMemberIterator itr = properties.MemberBegin();
259 11093 : itr != properties.MemberEnd(); ++itr) {
260 8641 : string key_str = itr->name.GetString();
261 : // Skip all the back-refs.
262 8641 : if (key_str.find("back_refs") != string::npos) {
263 0 : continue;
264 : }
265 8641 : size_t pos = key_str.find("_refs");
266 8641 : if (pos != string::npos) {
267 922 : ParseOneRef(adapter, itr->value, key, origin, req_list, key_str,
268 : pos, add_change);
269 922 : continue;
270 : }
271 7719 : if (key_str.compare("parent_type") == 0) {
272 1410 : const Value& ptype_node = itr->value;
273 1410 : CONFIG_PARSE_ASSERT(Parent, ptype_node.IsString(), key_str,
274 : "Invalid parent type");
275 1410 : pos = key.id_name.find_last_of(":");
276 1410 : if (pos != string::npos) {
277 1410 : string parent_type = ptype_node.GetString();
278 : // Get the parent name from our name.
279 1410 : string parent_name = key.id_name.substr(0, pos);
280 : string metaname =
281 1410 : GetParentName(parent_type,key.id_type);
282 1410 : CONFIG_PARSE_ASSERT(Parent, !metaname.empty(), parent_type,
283 : "Missing link name");
284 1410 : std::unique_ptr<AutogenProperty > pvalue;
285 1410 : InsertRequestIntoQ(origin, parent_type,
286 : parent_name, metaname, pvalue, key, add_change, req_list);
287 1410 : } else {
288 0 : continue;
289 : }
290 : }
291 8641 : }
292 :
293 2452 : return true;
294 : }
295 :
296 2452 : bool ConfigJsonParser::ParseDocument(const ConfigCass2JsonAdapter &adapter,
297 : IFMapOrigin::Origin origin, RequestList *req_list,
298 : IFMapTable::RequestKey *key, bool add_change) const {
299 : // Update the name and the type into 'key'.
300 2452 : if (!ParseNameType(adapter, key)) {
301 0 : return false;
302 : }
303 :
304 : // For each property, we will clone 'key' to create our DBRequest's i.e.
305 : // 'key' will never become part of any DBRequest.
306 2452 : if (!ParseProperties(adapter, *key, origin, req_list, add_change)){
307 0 : return false;
308 : }
309 :
310 2452 : if (!ParseLinks(adapter, *key, origin, req_list, add_change)) {
311 0 : return false;
312 : }
313 :
314 2452 : return true;
315 : }
316 :
317 6177 : void ConfigJsonParser::InsertRequestIntoQ(IFMapOrigin::Origin origin,
318 : const string &neigh_type, const string &neigh_name,
319 : const string &metaname, std::unique_ptr<AutogenProperty> &pvalue,
320 : const IFMapTable::RequestKey &key, bool add_change,
321 : RequestList *req_list) const {
322 :
323 : IFMapServerTable::RequestData *data =
324 6177 : new IFMapServerTable::RequestData(origin, neigh_type, neigh_name);
325 6177 : data->metadata = metaname;
326 6177 : data->content.reset(pvalue.release());
327 :
328 6177 : DBRequest *db_request = new DBRequest();
329 6177 : db_request->oper = (add_change ? DBRequest::DB_ENTRY_ADD_CHANGE :
330 : DBRequest::DB_ENTRY_DELETE);
331 6177 : db_request->key.reset(CloneKey(key));
332 6177 : db_request->data.reset(data);
333 :
334 6177 : req_list->push_back(db_request);
335 6177 : }
336 :
337 2452 : void ConfigJsonParser::EnqueueListToTables(RequestList *req_list) const {
338 8629 : while (!req_list->empty()) {
339 6177 : unique_ptr<DBRequest> req(req_list->front());
340 6177 : req_list->pop_front();
341 : IFMapTable::RequestKey *key =
342 6177 : static_cast<IFMapTable::RequestKey *>(req->key.get());
343 :
344 6177 : IFMapTable *table = IFMapTable::FindTable(ifmap_server_->database(),
345 6177 : key->id_type);
346 6177 : if (table != NULL) {
347 6177 : table->Enqueue(req.get());
348 : } else {
349 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table", key->id_type);
350 : }
351 6177 : }
352 2452 : }
353 :
354 2452 : bool ConfigJsonParser::Receive(const ConfigCass2JsonAdapter &adapter,
355 : bool add_change) {
356 2452 : RequestList req_list;
357 :
358 2452 : if (adapter.document().HasParseError() || !adapter.document().IsObject()) {
359 0 : size_t pos = adapter.document().GetErrorOffset();
360 : // GetParseError returns const char *
361 0 : IFMAP_WARN(IFMapJsonLoadError,
362 : "Error in parsing JSON message at position",
363 : pos, "with error description",
364 : boost::lexical_cast<string>(
365 : adapter.document().GetParseError()), adapter.uuid());
366 0 : return false;
367 : } else {
368 2452 : unique_ptr<IFMapTable::RequestKey> key(new IFMapTable::RequestKey());
369 2452 : if (!ParseDocument(adapter, IFMapOrigin::CASSANDRA, &req_list, key.get(), add_change)) {
370 0 : STLDeleteValues(&req_list);
371 0 : return false;
372 : }
373 2452 : EnqueueListToTables(&req_list);
374 2452 : }
375 2452 : return true;
376 2452 : }
377 :
378 0 : static bool ConfigClientInfoHandleRequest(const Sandesh *sr,
379 : const RequestPipeline::PipeSpec ps,
380 : int stage, int instNum,
381 : RequestPipeline::InstData *data) {
382 : const ConfigClientInfoReq *request =
383 0 : static_cast<const ConfigClientInfoReq *>(ps.snhRequest_.get());
384 0 : ConfigClientInfoResp *response = new ConfigClientInfoResp();
385 : IFMapSandeshContext *sctx =
386 0 : static_cast<IFMapSandeshContext *>(request->module_context("IFMap"));
387 :
388 : ConfigClientManager *config_mgr =
389 0 : sctx->ifmap_server()->get_config_manager();
390 :
391 0 : if (config_mgr->config_amqp_client()) {
392 0 : ConfigAmqpConnInfo amqp_conn_info;
393 0 : config_mgr->config_amqp_client()->GetConnectionInfo(amqp_conn_info);
394 0 : response->set_amqp_conn_info(amqp_conn_info);
395 0 : }
396 :
397 0 : ConfigDBConnInfo db_conn_info;
398 0 : config_mgr->config_db_client()->GetConnectionInfo(db_conn_info);
399 :
400 0 : ConfigClientManagerInfo client_mgr_info;
401 0 : config_mgr->GetClientManagerInfo(client_mgr_info);
402 :
403 0 : response->set_client_manager_info(client_mgr_info);
404 0 : response->set_db_conn_info(db_conn_info);
405 0 : response->set_context(request->context());
406 0 : response->set_more(false);
407 0 : response->Response();
408 0 : return true;
409 0 : }
410 :
411 0 : void ConfigClientInfoReq::HandleRequest() const {
412 0 : RequestPipeline::StageSpec s0;
413 0 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
414 :
415 0 : s0.taskId_ = scheduler->GetTaskId("config::SandeshCmd");
416 0 : s0.cbFn_ = ConfigClientInfoHandleRequest;
417 0 : s0.instances_.push_back(0);
418 :
419 0 : RequestPipeline::PipeSpec ps(this);
420 0 : ps.stages_= boost::assign::list_of(s0).convert_to_container<
421 0 : std::vector<RequestPipeline::StageSpec> >();
422 0 : RequestPipeline rp(ps);
423 0 : }
424 :
425 0 : static bool ConfigClientReinitHandleRequest(const Sandesh *sr,
426 : const RequestPipeline::PipeSpec ps,
427 : int stage, int instNum,
428 : RequestPipeline::InstData *data) {
429 : const ConfigClientReinitReq *request =
430 0 : static_cast<const ConfigClientReinitReq *>(ps.snhRequest_.get());
431 0 : ConfigClientReinitResp *response = new ConfigClientReinitResp();
432 : IFMapSandeshContext *sctx =
433 0 : static_cast<IFMapSandeshContext *>(request->module_context("IFMap"));
434 :
435 : ConfigClientManager *config_mgr =
436 0 : sctx->ifmap_server()->get_config_manager();
437 :
438 0 : config_mgr->ReinitConfigClient();
439 :
440 0 : response->set_success(true);
441 0 : response->set_context(request->context());
442 0 : response->set_more(false);
443 0 : response->Response();
444 0 : return true;
445 : }
446 :
447 0 : void ConfigClientReinitReq::HandleRequest() const {
448 0 : RequestPipeline::StageSpec s0;
449 0 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
450 :
451 0 : s0.taskId_ = scheduler->GetTaskId("config::SandeshCmd");
452 0 : s0.cbFn_ = ConfigClientReinitHandleRequest;
453 0 : s0.instances_.push_back(0);
454 :
455 0 : RequestPipeline::PipeSpec ps(this);
456 0 : ps.stages_= boost::assign::list_of(s0).convert_to_container<
457 0 : std::vector<RequestPipeline::StageSpec> >();
458 0 : RequestPipeline rp(ps);
459 0 : }
|