OpenSDN source code
vncapi.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
3  */
4 
5 #include <boost/bind/bind.hpp>
6 #include <boost/function.hpp>
7 #include "base/util.h"
8 #include "base/address_util.h"
9 #include "base/logging.h"
10 #include "base/test/task_test_util.h"
11 #include <iomanip>
12 #include <ctype.h>
13 #include <iostream>
14 #include <algorithm>
15 #include <sstream>
16 #include <unistd.h>
17 #include <stdlib.h>
18 #include <rapidjson/stringbuffer.h>
19 #include <boost/algorithm/string.hpp>
20 #include <boost/algorithm/string/predicate.hpp>
21 #include <boost/property_tree/ini_parser.hpp>
22 #include <boost/property_tree/ptree.hpp>
23 
24 #include "vncapi.h"
25 
26 using namespace boost::placeholders;
27 
29  boost::function<void(contrail_rapidjson::Document&,
30  boost::system::error_code&, std::string, int, std::string,
31  std::map<std::string, std::string>*)> cb):
32  conn_(c), uri_(uri), cb_(cb)
33 {
34 }
35 
38 {
39  return conn_;
40 }
41 
42 void
43 RespBlock::AddBody(std::string s)
44 {
45  body_ += s;
46 }
47 
48 void
50 {
51  body_.clear();
52  if (c)
53  conn_ = c;
54 }
55 
56 std::string
58 {
59  return body_;
60 }
61 
62 std::string
64 {
65  return uri_;
66 }
67 
68 void
70 {
71  std::cout << conn_->Version() << "->"
72  << conn_->Reason() << "(" << conn_->Status() << ")\n";
73 }
74 
75 boost::function<void(contrail_rapidjson::Document&, boost::system::error_code&,
76  std::string, int, std::string, std::map<std::string, std::string>*)>
78 {
79  return cb_;
80 }
81 
82 
83 #define CHR_PER_LN 16
84 void
85 VncApi::hex_dump(std::string s)
86 {
87 //#define __DEBUG__ 1
88 #ifdef __DEBUG__
89  unsigned long a = 0;
90  int rem = s.length();
91  const char *p = s.c_str();
92  while (rem > 0) {
93  std::cout << std::setfill('0') << std::setw(8) << std::hex << a;
94  for (int i = 0; i < CHR_PER_LN; i++) {
95  if( i % 8 == 0 ) std::cout << ' ';
96  if ( i < rem )
97  std::cout << ' ' << std::setfill('0') << std::setw(2) <<
98  std::hex << (unsigned) p[i];
99  else
100  std::cout << " ";
101  }
102  std::cout << " ";
103  for (int i = 0; i < rem && i < CHR_PER_LN; i++)
104  if (isprint(p[i]))
105  std::cout << p[i];
106  else
107  std::cout << '.';
108  std::cout << '\n';
109  a += CHR_PER_LN;
110  p += CHR_PER_LN;
111  rem -= CHR_PER_LN;
112  }
113  std::cout << std::dec;
114 #endif
115 }
116 
117 void
119 {
120  if (client_) {
122  cfg_->ks_srv_port);
123  if (cfg_->ks_protocol == "https") {
124  conn->set_use_ssl(true);
126  conn->set_client_cert_type("PEM");
128  conn->set_ca_cert(cfg_->ks_cafile);
129  }
130  RespBlock *rb = new RespBlock(conn, "v2.0/tokens", 0);
131  std::ostringstream pstrm;
132  pstrm << "{\"auth\": {\"passwordCredentials\": {\"username\": \"" <<
133  cfg_->ks_user << "\", \"password\": \"" << cfg_->ks_password <<
134  "\"}, \"tenantName\": \"" << cfg_->ks_tenant << "\"}}";
135  rb->GetConnection()->HttpPost(pstrm.str(), rb->GetUri(), false, false,
136  true, kshdr_, boost::bind(&VncApi::KsRespHandler,
137  shared_from_this(), rb, orb, _1, _2));
138  }
139 }
140 
141 bool
142 VncApi::CondTest(std::string s)
143 //VncApi::CondTest(std::string s)
144 {
145  return boost::starts_with(s, "X-AUTH-TOKEN:");
146 }
147 
148 std::string VncApi::GetToken(RespBlock *rb) const {
149  contrail_rapidjson::Document jdoc;
150  jdoc.Parse<0>(rb->GetBody().c_str());
151 
152  if (!jdoc.IsObject() || !jdoc.HasMember("access"))
153  return "";
154 
155  if (!jdoc["access"].IsObject() || !jdoc["access"].HasMember("token"))
156  return "";
157 
158  if (!jdoc["access"]["token"].IsObject())
159  return "";
160 
161  if (!jdoc["access"]["token"].HasMember("id"))
162  return "";
163 
164  if (!jdoc["access"]["token"]["id"].IsString())
165  return "";
166 
167  return jdoc["access"]["token"]["id"].GetString();
168 }
169 
170 void
171 VncApi::KsRespHandler(RespBlock *rb, RespBlock *orb, std::string &str,
172  boost::system::error_code &ec)
173 {
174  if (client_) {
175  if (str == "") {
176  if (rb->GetConnection()->Status() == 200) {
177  contrail_rapidjson::Document jdoc;
178  jdoc.Parse<0>(rb->GetBody().c_str());
179 
180  std::string token = GetToken(rb);
181  if (!token.empty()) {
182  hdr_.erase(std::remove_if(hdr_.begin(), hdr_.end(),
183  boost::bind(&VncApi::CondTest,
184  shared_from_this(), _1)), hdr_.end());
185  hdr_.push_back(std::string("X-AUTH-TOKEN: ") + token);
186  orb->GetConnection()->HttpGet(orb->GetUri(), false,
187  false, true, hdr_, boost::bind(
189  shared_from_this(), orb, _1, _2));
191  delete rb;
192  return;
193  }
194  }
196  delete orb;
198  delete rb;
199  } else {
200  rb->AddBody(str);
201  }
202  } else {
203  delete orb;
204  delete rb;
205  }
206 }
207 
208 void
209 VncApi::Add2URI(std::ostringstream &uri, std::string &qadded, std::string key,
210  std::vector<std::string> data)
211 {
212  if (data.size() > 0) {
213  uri << qadded << key << "=";
214  qadded = "&";
215  for (std::vector<std::string>::iterator i = data.begin();
216  i != data.end(); i++) {
217  uri << *i;
218  if (i + 1 != data.end())
219  uri << ",";
220  }
221  }
222 }
223 
224 std::string
225 VncApi::MakeUri(std::string type, std::vector<std::string> ids,
226  std::vector<std::string> filters, std::vector<std::string> parents,
227  std::vector<std::string> refs, std::vector<std::string> fields)
228 {
229  std::ostringstream uri;
230  uri << type << "s";
231  std::string qadded = "?";
232  Add2URI(uri, qadded, "id", ids);
233  Add2URI(uri, qadded, "filters", filters);
234  Add2URI(uri, qadded, "parent_id", parents);
235  Add2URI(uri, qadded, "refs", refs);
236  Add2URI(uri, qadded, "fields", fields);
237 
238  return uri.str();
239 }
240 
241 VncApi::VncApi(EventManager *evm, VncApiConfig *cfg) : evm_(evm), cfg_(cfg),
242  client_(new HttpClient(evm_, "vnc-api http client"))
243 {
244  client_->Init();
245  hdr_.push_back(std::string(
246  "Content-Type: application/json; charset=\"UTF-8\""));
247  hdr_.push_back(std::string("X-Contrail-Useragent: a7s30:vncapi.cc"));
248  //hdr_.push_back(std::string("X-AUTH-TOKEN: ") + GetTokenFromKeystone());
249  //hdr_.push_back(std::string("X-AUTH-TOKEN: some junk"));
250  kshdr_ = hdr_;
251 
252  if (cfg_->api_use_ssl) {
253  boost::property_tree::ptree pt;
254  try {
255  boost::property_tree::ini_parser::read_ini(
256  "/etc/contrail/vnc_api_lib.ini", pt);
257  } catch (const boost::property_tree::ptree_error &e) {
258  LOG(ERROR, "Failed to parse /etc/contrail/vnc_api_lib.ini : " <<
259  e.what());
260  exit(1);
261  }
262  cfg_->api_keyfile = pt.get<std::string>("global.keyfile", "");
263  cfg_->api_certfile = pt.get<std::string>("global.certfile", "");
264  cfg_->api_cafile = pt.get<std::string>("global.cafile", "");
265  }
266 }
267 
268 void
270 {
271  std::cout << "VncApi::Stop\n";
273  client_ = 0;
274  {
275  hdr_.clear();
276  kshdr_.clear();
277  }
278 }
279 
280 void
281 VncApi::GetConfig(std::string type, std::vector<std::string> ids,
282  std::vector<std::string> filters, std::vector<std::string> parents,
283  std::vector<std::string> refs, std::vector<std::string> fields,
284  boost::function<void(contrail_rapidjson::Document&,
285  boost::system::error_code &ec, std::string version, int status,
286  std::string reason,
287  std::map<std::string, std::string> *headers)> cb)
288 {
289  if (client_) {
291  cfg_->api_srv_port);
292  if (cfg_->api_use_ssl) {
293  conn->set_use_ssl(true);
295  conn->set_client_cert_type("PEM");
297  conn->set_ca_cert(cfg_->api_cafile);
298  }
299  RespBlock *rb = new RespBlock(conn,
300  MakeUri(type, ids, filters, parents, refs, fields), cb);
301  rb->GetConnection()->HttpGet(rb->GetUri(), false, false, true, hdr_,
302  boost::bind(&VncApi::RespHandler, shared_from_this(),
303  rb, _1, _2));
304  }
305 }
306 
307 void
308 VncApi::RespHandler(RespBlock *rb, std::string &str,
309  boost::system::error_code &ec)
310 {
311 #ifdef __DEBUG__
312  hex_dump(str);
313  rb->ShowDetails();
314  std::cout << "\n" << str << "\nErr: " << ec << std::endl;
315 #endif // __DEBUG__
316  if (client_) {
317  if (str == "") {
318  if (rb->GetConnection()->Status() == 401) {
319  // retry
320  // client_->RemoveConnection(rb->GetConnection());
321  // rb->Clear(client_->CreateConnection(cfg_->api_srv_ip,
322  // cfg_->api_srv_port));
323  rb->Clear();
324  Reauthenticate(rb);
325  } else {
326  contrail_rapidjson::Document jdoc;
327  if (rb->GetConnection()->Status() == 200)
328  jdoc.Parse<0>(rb->GetBody().c_str());
329  rb->GetCallBack()(jdoc, ec,
330  rb->GetConnection()->Version(),
331  rb->GetConnection()->Status(),
332  rb->GetConnection()->Reason(),
333  rb->GetConnection()->Headers());
335  delete rb;
336  }
337  } else {
338  rb->AddBody(str);
339  }
340  } else {
341  delete rb;
342  }
343 }
HttpConnection * CreateConnection(boost::asio::ip::tcp::endpoint)
Definition: http_client.cc:454
void RemoveConnection(HttpConnection *)
Definition: http_client.cc:473
void Init()
Definition: http_client.cc:422
std::map< std::string, std::string > * Headers()
Definition: http_client.h:95
std::string Version()
Definition: http_client.h:93
void set_ca_cert(const std::string &ca_cert)
Definition: http_client.h:128
int HttpGet(const std::string &path, HttpCb)
Definition: http_client.cc:135
void set_client_cert(const std::string &client_cert)
Definition: http_client.h:119
void set_use_ssl(bool ssl_flag)
Definition: http_client.h:117
int HttpPost(const std::string &post_string, const std::string &path, HttpCb)
Definition: http_client.cc:180
std::string Reason()
Definition: http_client.h:94
void set_client_cert_type(const std::string &client_cert_type)
Definition: http_client.h:122
void set_client_key(const std::string &client_key)
Definition: http_client.h:125
void ShowDetails()
Definition: vncapi.cc:69
std::string uri_
Definition: vncapi.h:52
HttpConnection * conn_
Definition: vncapi.h:51
HttpConnection * GetConnection()
Definition: vncapi.cc:37
boost::function< void(contrail_rapidjson::Document &, boost::system::error_code &, std::string, int, std::string, std::map< std::string, std::string > *)> cb_
Definition: vncapi.h:55
RespBlock(HttpConnection *c, std::string uri, boost::function< void(contrail_rapidjson::Document &, boost::system::error_code &, std::string, int, std::string, std::map< std::string, std::string > *)> cb)
Definition: vncapi.cc:28
void Clear(HttpConnection *c=0)
Definition: vncapi.cc:49
std::string GetUri()
Definition: vncapi.cc:63
std::string GetBody()
Definition: vncapi.cc:57
boost::function< void(contrail_rapidjson::Document &, boost::system::error_code &, std::string, int, std::string, std::map< std::string, std::string > *)> GetCallBack()
Definition: vncapi.cc:77
void AddBody(std::string s)
Definition: vncapi.cc:43
std::string body_
Definition: vncapi.h:56
static void DeleteServer(TcpServer *server)
Definition: tcp_server.cc:658
bool CondTest(std::string s)
Definition: vncapi.cc:142
std::string MakeUri(std::string type, std::vector< std::string > ids, std::vector< std::string > filters, std::vector< std::string > parents, std::vector< std::string > refs, std::vector< std::string > fields)
Definition: vncapi.cc:225
void RespHandler(RespBlock *rb, std::string &str, boost::system::error_code &ec)
Definition: vncapi.cc:308
void Add2URI(std::ostringstream &uri, std::string &qadded, std::string key, std::vector< std::string > data)
Definition: vncapi.cc:209
HttpClient * client_
Definition: vncapi.h:64
void Reauthenticate(RespBlock *orb)
Definition: vncapi.cc:118
void KsRespHandler(RespBlock *rb, RespBlock *orb, std::string &str, boost::system::error_code &ec)
Definition: vncapi.cc:171
void GetConfig(std::string type, std::vector< std::string > ids, std::vector< std::string > filters, std::vector< std::string > parents, std::vector< std::string > refs, std::vector< std::string > fields, boost::function< void(contrail_rapidjson::Document &, boost::system::error_code &ec, std::string version, int status, std::string reason, std::map< std::string, std::string > *headers)> cb)
Definition: vncapi.cc:281
VncApiConfig * cfg_
Definition: vncapi.h:63
std::vector< std::string > hdr_
Definition: vncapi.h:65
VncApi(EventManager *evm, VncApiConfig *cfg)
Definition: vncapi.cc:241
void hex_dump(std::string s)
Definition: vncapi.cc:85
std::string GetToken(RespBlock *rb) const
Definition: vncapi.cc:148
std::vector< std::string > kshdr_
Definition: vncapi.h:66
void Stop()
Definition: vncapi.cc:269
static EventManager evm
uint8_t type
Definition: load_balance.h:2
#define LOG(_Level, _Msg)
Definition: logging.h:34
std::string api_srv_ip
Definition: vncapi.h:18
bool api_use_ssl
Definition: vncapi.h:20
int ks_srv_port
Definition: vncapi.h:25
std::string api_cafile
Definition: vncapi.h:23
std::string api_certfile
Definition: vncapi.h:22
std::string ks_certfile
Definition: vncapi.h:31
std::string ks_protocol
Definition: vncapi.h:26
std::string ks_srv_ip
Definition: vncapi.h:24
std::string ks_tenant
Definition: vncapi.h:29
std::string ks_keyfile
Definition: vncapi.h:30
std::string ks_user
Definition: vncapi.h:27
int api_srv_port
Definition: vncapi.h:19
std::string ks_cafile
Definition: vncapi.h:32
std::string api_keyfile
Definition: vncapi.h:21
std::string ks_password
Definition: vncapi.h:28
#define CHR_PER_LN
Definition: vncapi.cc:83