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