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