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 157 : ConfigJsonParser::ConfigJsonParser() {
45 157 : }
46 :
47 314 : ConfigJsonParser::~ConfigJsonParser() {
48 314 : }
49 :
50 157 : void ConfigJsonParser::SetupObjectFilter() {
51 157 : ObjectTypeList FilterList;
52 157 : bgp_schema_Server_GenerateObjectTypeList(&FilterList);
53 157 : vnc_cfg_Server_GenerateObjectTypeList(&FilterList);
54 157 : for (ObjectTypeList::iterator it = FilterList.begin();
55 18683 : it != FilterList.end(); it++) {
56 18526 : AddObjectType(*it);
57 : }
58 157 : }
59 :
60 157 : void ConfigJsonParser::SetupSchemaGraphFilter(){
61 157 : vnc_cfg_FilterInfo vnc_filter_info;
62 157 : bgp_schema_FilterInfo bgp_schema_filter_info;
63 :
64 157 : bgp_schema_Server_GenerateGraphFilter(&bgp_schema_filter_info);
65 157 : vnc_cfg_Server_GenerateGraphFilter(&vnc_filter_info);
66 :
67 157 : for (vnc_cfg_FilterInfo::iterator it = vnc_filter_info.begin();
68 60759 : it != vnc_filter_info.end(); it++) {
69 60602 : if (it->is_ref_) {
70 42390 : AddLinkName(make_pair(it->left_, it->right_),
71 84780 : make_pair(it->metadata_, it->linkattr_));
72 : } else {
73 18212 : AddParentName(make_pair(it->left_, it->right_),
74 18212 : it->metadata_);
75 : }
76 : }
77 :
78 157 : for (bgp_schema_FilterInfo::iterator it = bgp_schema_filter_info.begin();
79 1884 : it != bgp_schema_filter_info.end(); it++) {
80 1727 : if (it->is_ref_) {
81 1256 : AddLinkName(make_pair(it->left_, it->right_),
82 2512 : make_pair(it->metadata_, it->linkattr_));
83 : } else {
84 471 : AddParentName(make_pair(it->left_, it->right_),
85 471 : it->metadata_);
86 : }
87 : }
88 157 : }
89 :
90 157 : void ConfigJsonParser::SetupSchemaWrapperPropertyInfo() {
91 157 : WrapperFieldMap wrapper_field_map;
92 157 : bgp_schema_Server_GenerateWrapperPropertyInfo(&wrapper_field_map);
93 157 : vnc_cfg_Server_GenerateWrapperPropertyInfo(&wrapper_field_map);
94 157 : for (WrapperFieldMap::iterator it = wrapper_field_map.begin();
95 22451 : it != wrapper_field_map.end(); it++) {
96 22294 : AddWrapperField(it->first, it->second);
97 : }
98 157 : }
99 :
100 157 : void ConfigJsonParser::SetupGraphFilter() {
101 157 : SetupObjectFilter();
102 157 : SetupSchemaGraphFilter();
103 157 : SetupSchemaWrapperPropertyInfo();
104 157 : }
105 0 : void ConfigJsonParser::EndOfConfig() {
106 0 : ifmap_server_->CleanupStaleEntries();
107 0 : }
108 :
109 117279 : void ConfigJsonParser::MetadataRegister(const string &metadata,
110 : MetadataParseFn parser) {
111 : pair<MetadataParseMap::iterator, bool> result =
112 117279 : metadata_map_.insert(make_pair(metadata, parser));
113 117279 : assert(result.second);
114 117279 : }
115 :
116 154 : void ConfigJsonParser::MetadataClear(const string &module) {
117 154 : metadata_map_.clear();
118 154 : }
119 :
120 8013 : IFMapTable::RequestKey *ConfigJsonParser::CloneKey(
121 : const IFMapTable::RequestKey &src) const {
122 8013 : IFMapTable::RequestKey *retkey = new IFMapTable::RequestKey();
123 8013 : retkey->id_type = src.id_type;
124 8014 : retkey->id_name = src.id_name;
125 : // Tag each DB Request with current generation number
126 8013 : retkey->id_seq_num = GetGenerationNumber();
127 8012 : return retkey;
128 : }
129 :
130 2713 : bool ConfigJsonParser::ParseNameType(const ConfigCass2JsonAdapter &adapter,
131 : IFMapTable::RequestKey *key) const {
132 : // Type is the name of the document.
133 2713 : Value::ConstMemberIterator itr = adapter.document().MemberBegin();
134 2713 : CONFIG_PARSE_ASSERT(Type, autogen::ParseString(itr->name, &key->id_type),
135 : "Name", "Bad name");
136 :
137 2713 : key->id_type = itr->name.GetString();
138 :
139 : // Name is the fq_name field in the document.
140 2713 : const Value &value_node = itr->value;
141 2713 : CONFIG_PARSE_ASSERT(FqName, value_node.HasMember("fq_name"), key->id_type,
142 : "Missing FQ name");
143 2712 : const Value &fq_name_node = value_node["fq_name"];
144 2713 : CONFIG_PARSE_ASSERT(FqName, fq_name_node.IsArray(), key->id_type,
145 : "FQ name is not an array");
146 2713 : CONFIG_PARSE_ASSERT(FqName, fq_name_node.Size(),
147 : key->id_type, "FQ name array is empty");
148 :
149 2713 : size_t i = 0;
150 :
151 : // Iterate over all items except the last one.
152 6769 : for (; i < fq_name_node.Size() - 1; ++i) {
153 4055 : key->id_name += fq_name_node[i].GetString();
154 4055 : key->id_name += string(":");
155 : }
156 2714 : key->id_name += fq_name_node[i].GetString();
157 :
158 2714 : return true;
159 : }
160 :
161 10716 : 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 10716 : string metaname = key_node.GetString();
166 10715 : MetadataParseMap::const_iterator loc = metadata_map_.find(metaname);
167 10713 : if (loc == metadata_map_.end()) {
168 5490 : return true;
169 : }
170 :
171 : // Treat updates with NULL value as deletes.
172 5228 : if (add_change && value_node.IsNull())
173 8 : add_change = false;
174 5227 : std::unique_ptr<AutogenProperty> pvalue;
175 5227 : if (add_change) {
176 5037 : bool success = (loc->second)(value_node, &pvalue);
177 5040 : CONFIG_PARSE_ASSERT(Property, success, metaname,
178 : "No entry in metadata map");
179 : } else {
180 190 : const string key = metaname;
181 191 : if (!IsListOrMapPropEmpty(adapter.uuid(), key)) {
182 32 : return true;
183 : }
184 191 : }
185 5199 : std::replace(metaname.begin(), metaname.end(), '_', '-');
186 5199 : InsertRequestIntoQ(origin, "", "", metaname, pvalue, key,
187 : add_change, req_list);
188 5196 : return true;
189 10718 : }
190 :
191 2714 : bool ConfigJsonParser::ParseProperties(const ConfigCass2JsonAdapter &adapter,
192 : const IFMapTable::RequestKey &key, IFMapOrigin::Origin origin,
193 : RequestList *req_list, bool add_change) const {
194 :
195 2714 : Value::ConstMemberIterator doc_itr = adapter.document().MemberBegin();
196 2714 : const Value &value_node = doc_itr->value;
197 2714 : for (Value::ConstMemberIterator itr = value_node.MemberBegin();
198 13432 : itr != value_node.MemberEnd(); ++itr) {
199 10715 : ParseOneProperty(adapter, itr->name, itr->value, key, origin,
200 : req_list, add_change);
201 : }
202 :
203 2714 : return true;
204 : }
205 :
206 1203 : 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 1203 : const Value& to_node = ref_entry["to"];
211 :
212 1203 : string from_underscore = key.id_type;
213 1203 : std::replace(from_underscore.begin(), from_underscore.end(), '-', '_');
214 : string link_name =
215 1203 : GetLinkName(from_underscore, refer);
216 1203 : CONFIG_PARSE_ASSERT(Reference, !link_name.empty(), refer,
217 : "Link name is empty");
218 1203 : string metaname = link_name;
219 1203 : std::replace(metaname.begin(), metaname.end(), '-', '_');
220 :
221 1203 : MetadataParseMap::const_iterator loc = metadata_map_.find(metaname);
222 1203 : CONFIG_PARSE_ASSERT(Reference, loc != metadata_map_.end(), metaname,
223 : "No entry in metadata map");
224 :
225 1203 : std::unique_ptr<AutogenProperty> pvalue;
226 1203 : if (ref_entry.HasMember("attr")) {
227 1203 : const Value& attr_node = ref_entry["attr"];
228 1203 : bool success = (loc->second)(attr_node, &pvalue);
229 1203 : CONFIG_PARSE_ASSERT(ReferenceLinkAttributes, success, metaname,
230 : "Link attribute parse error");
231 : }
232 :
233 1203 : string neigh_name;
234 1203 : neigh_name += to_node.GetString();
235 :
236 1203 : InsertRequestIntoQ(origin, refer, neigh_name,
237 : link_name, pvalue, key, add_change, req_list);
238 :
239 1203 : return true;
240 1203 : }
241 :
242 1169 : 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 1169 : string refer = key_str.substr(0, pos);
247 1169 : CONFIG_PARSE_ASSERT(Reference, arr.IsArray(), refer, "Invalid referene");
248 2372 : for (size_t i = 0; i < arr.Size(); ++i)
249 1203 : ParseRef(adapter, arr[i], origin, refer, key, req_list, add_change);
250 1169 : return true;
251 1169 : }
252 :
253 2714 : bool ConfigJsonParser::ParseLinks(const ConfigCass2JsonAdapter &adapter,
254 : const IFMapTable::RequestKey &key, IFMapOrigin::Origin origin,
255 : RequestList *req_list, bool add_change) const {
256 2714 : Value::ConstMemberIterator doc_itr = adapter.document().MemberBegin();
257 2714 : const Value &properties = doc_itr->value;
258 2714 : for (Value::ConstMemberIterator itr = properties.MemberBegin();
259 13440 : itr != properties.MemberEnd(); ++itr) {
260 10724 : string key_str = itr->name.GetString();
261 : // Skip all the back-refs.
262 10724 : if (key_str.find("back_refs") != string::npos) {
263 0 : continue;
264 : }
265 10724 : size_t pos = key_str.find("_refs");
266 10726 : if (pos != string::npos) {
267 1169 : ParseOneRef(adapter, itr->value, key, origin, req_list, key_str,
268 : pos, add_change);
269 1169 : continue;
270 : }
271 9557 : if (key_str.compare("parent_type") == 0) {
272 1612 : const Value& ptype_node = itr->value;
273 1612 : CONFIG_PARSE_ASSERT(Parent, ptype_node.IsString(), key_str,
274 : "Invalid parent type");
275 1612 : pos = key.id_name.find_last_of(":");
276 1612 : if (pos != string::npos) {
277 1612 : string parent_type = ptype_node.GetString();
278 : // Get the parent name from our name.
279 1612 : string parent_name = key.id_name.substr(0, pos);
280 : string metaname =
281 1612 : GetParentName(parent_type,key.id_type);
282 1612 : CONFIG_PARSE_ASSERT(Parent, !metaname.empty(), parent_type,
283 : "Missing link name");
284 1612 : std::unique_ptr<AutogenProperty > pvalue;
285 1612 : InsertRequestIntoQ(origin, parent_type,
286 : parent_name, metaname, pvalue, key, add_change, req_list);
287 1612 : } else {
288 0 : continue;
289 : }
290 : }
291 10726 : }
292 :
293 2714 : return true;
294 : }
295 :
296 2713 : 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 2713 : 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 2714 : if (!ParseProperties(adapter, *key, origin, req_list, add_change)){
307 0 : return false;
308 : }
309 :
310 2714 : if (!ParseLinks(adapter, *key, origin, req_list, add_change)) {
311 0 : return false;
312 : }
313 :
314 2714 : return true;
315 : }
316 :
317 8014 : 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 8014 : new IFMapServerTable::RequestData(origin, neigh_type, neigh_name);
325 8013 : data->metadata = metaname;
326 8014 : data->content.reset(pvalue.release());
327 :
328 8014 : DBRequest *db_request = new DBRequest();
329 8013 : db_request->oper = (add_change ? DBRequest::DB_ENTRY_ADD_CHANGE :
330 : DBRequest::DB_ENTRY_DELETE);
331 8013 : db_request->key.reset(CloneKey(key));
332 8010 : db_request->data.reset(data);
333 :
334 8007 : req_list->push_back(db_request);
335 8011 : }
336 :
337 2714 : void ConfigJsonParser::EnqueueListToTables(RequestList *req_list) const {
338 10728 : while (!req_list->empty()) {
339 8013 : unique_ptr<DBRequest> req(req_list->front());
340 8012 : req_list->pop_front();
341 : IFMapTable::RequestKey *key =
342 8011 : static_cast<IFMapTable::RequestKey *>(req->key.get());
343 :
344 8009 : IFMapTable *table = IFMapTable::FindTable(ifmap_server_->database(),
345 8009 : key->id_type);
346 8010 : if (table != NULL) {
347 8010 : table->Enqueue(req.get());
348 : } else {
349 0 : IFMAP_TRACE(IFMapTblNotFoundTrace, "Cant find table", key->id_type);
350 : }
351 8014 : }
352 2713 : }
353 :
354 2713 : bool ConfigJsonParser::Receive(const ConfigCass2JsonAdapter &adapter,
355 : bool add_change) {
356 2713 : RequestList req_list;
357 :
358 2713 : 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 2714 : unique_ptr<IFMapTable::RequestKey> key(new IFMapTable::RequestKey());
369 2712 : if (!ParseDocument(adapter, IFMapOrigin::CASSANDRA, &req_list, key.get(), add_change)) {
370 0 : STLDeleteValues(&req_list);
371 0 : return false;
372 : }
373 2714 : EnqueueListToTables(&req_list);
374 2714 : }
375 2714 : return true;
376 2714 : }
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 : }
|