Line data Source code
1 : /*
2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved.
3 : */
4 :
5 : #include <vector>
6 : #include <string>
7 :
8 : #include <boost/bind/bind.hpp>
9 : #include <boost/assign.hpp>
10 : #include <boost/foreach.hpp>
11 :
12 : #include "base/regex.h"
13 : #include "http/http_server.h"
14 : #include "http/http_request.h"
15 : #include "http/http_session.h"
16 : #include "base/contrail_ports.h"
17 : #include "port_ipc/port_ipc_handler.h"
18 : #include "cmn/agent.h"
19 : #include "rest_server.h"
20 : #include "rest_common.h"
21 : #include "init/agent_param.h"
22 :
23 : using namespace boost::placeholders;
24 :
25 : using contrail::regex;
26 : using contrail::regex_match;
27 : using contrail::regex_search;
28 :
29 : class RestServerGetVmCfgTask : public Task {
30 : public:
31 0 : RestServerGetVmCfgTask(PortIpcHandler *pih,
32 0 : const struct RestServer::RESTData& data):
33 : Task((TaskScheduler::GetInstance()->GetTaskId("Agent::RestApi")), 0),
34 0 : pih_(pih),
35 0 : vm_name_((*data.match)[1]),
36 0 : data_(data),
37 0 : context_(data_.session->get_context()) {
38 0 : }
39 0 : virtual ~RestServerGetVmCfgTask() { }
40 0 : virtual bool Run() {
41 0 : std::string info;
42 0 : const std::string client_ctx = data_.session->get_client_context(context_);
43 : // check session is not deleted
44 0 : if ((!data_.session->set_client_context(context_, client_ctx)) ||
45 0 : (context_.empty()))
46 0 : return true;
47 0 : if (pih_->GetVmVnCfgPort(vm_name_, info)) {
48 0 : REST::SendResponse(data_.session, info, 200, context_);
49 : } else {
50 0 : REST::SendErrorResponse(data_.session, "{ Not Found }", 404, context_);
51 : }
52 0 : return true;
53 0 : }
54 0 : std::string Description() const { return "RestServerGetVmCfgTask"; }
55 : private:
56 : const PortIpcHandler *pih_;
57 : std::string vm_name_;
58 : const struct RestServer::RESTData& data_;
59 : const std::string context_;
60 : DISALLOW_COPY_AND_ASSIGN(RestServerGetVmCfgTask);
61 : };
62 :
63 0 : void RestServer::VmPortPostHandler(const struct RESTData& data) {
64 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
65 0 : if (pih) {
66 0 : std::string err_msg;
67 0 : if (pih->AddPortFromJson(data.request->Body(), false, err_msg, true)) {
68 0 : REST::SendResponse(data.session, "{}");
69 : } else {
70 0 : REST::SendErrorResponse(data.session, "{ " + err_msg + " }");
71 : }
72 0 : } else {
73 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
74 : }
75 0 : }
76 :
77 0 : void RestServer::VmPortSyncHandler(const struct RESTData& data) {
78 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
79 0 : if (pih) {
80 0 : pih->SyncHandler();
81 0 : REST::SendResponse(data.session, "{}");
82 : } else {
83 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
84 : }
85 0 : }
86 :
87 0 : void RestServer::VmPortDeleteHandler(const struct RESTData& data) {
88 0 : std::string error;
89 0 : const std::string& port_id = (*data.match)[1];
90 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
91 0 : if (pih) {
92 0 : if (pih->DeletePort(port_id, error)) {
93 0 : REST::SendResponse(data.session, "{}");
94 : } else {
95 0 : REST::SendErrorResponse(data.session, "{" + error + "}");
96 : }
97 : } else {
98 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
99 : }
100 0 : }
101 :
102 0 : void RestServer::VmPortGetHandler(const struct RESTData& data) {
103 0 : const std::string& port_id = (*data.match)[1];
104 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
105 0 : if (pih) {
106 0 : std::string info;
107 0 : if (pih->GetPortInfo(port_id, info)) {
108 0 : REST::SendResponse(data.session, info);
109 : } else {
110 0 : REST::SendErrorResponse(data.session, "{ Not Found }", 404);
111 : }
112 0 : } else {
113 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
114 : }
115 0 : }
116 :
117 0 : void RestServer::GatewayPostHandler(const struct RESTData& data) {
118 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
119 0 : if (pih) {
120 0 : std::string err_msg;
121 0 : if (pih->AddVgwFromJson(data.request->Body(), err_msg)) {
122 0 : REST::SendResponse(data.session, "{}");
123 : } else {
124 0 : REST::SendErrorResponse(data.session, "{ " + err_msg + " }");
125 : }
126 0 : } else {
127 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
128 : }
129 0 : }
130 :
131 0 : void RestServer::GatewayDeleteHandler(const struct RESTData& data) {
132 0 : std::string error;
133 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
134 0 : if (pih) {
135 0 : std::string err_msg;
136 0 : if (pih->DelVgwFromJson(data.request->Body(), err_msg)) {
137 0 : REST::SendResponse(data.session, "{}");
138 : } else {
139 0 : REST::SendErrorResponse(data.session, "{" + error + "}");
140 : }
141 0 : } else {
142 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
143 : }
144 0 : }
145 :
146 0 : void RestServer::VmVnPortPostHandler(const struct RESTData& data) {
147 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
148 0 : if (pih) {
149 0 : std::string err_msg;
150 0 : if (pih->AddVmVnPort(data.request->Body(), false, err_msg, true)) {
151 0 : REST::SendResponse(data.session, "{}");
152 : } else {
153 0 : REST::SendErrorResponse(data.session, "{ " + err_msg + " }");
154 : }
155 0 : } else {
156 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
157 : }
158 0 : }
159 :
160 0 : void RestServer::VmVnPortDeleteHandler(const struct RESTData& data) {
161 0 : std::string error;
162 0 : const std::string &vm_uuid = (*data.match)[1];
163 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
164 0 : if (pih) {
165 0 : if (pih->DeleteVmVnPort(data.request->Body(), vm_uuid, error)) {
166 0 : REST::SendResponse(data.session, "{}");
167 : } else {
168 0 : REST::SendErrorResponse(data.session, "{" + error + "}");
169 : }
170 : } else {
171 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
172 : }
173 0 : }
174 :
175 0 : void RestServer::VmVnPortGetHandler(const struct RESTData& data) {
176 0 : std::string url = (*data.match)[0];
177 0 : bool vmi_uuid_presence = false;
178 0 : std::size_t pos = 4; // skip "/vm/"
179 0 : std::size_t vmi_uuid_pos = url.find("/", pos);
180 0 : if (vmi_uuid_pos != std::string::npos) {
181 0 : vmi_uuid_presence = true;
182 : }
183 0 : std::string vm_uuid = url.substr(pos, vmi_uuid_pos);
184 0 : std::string vmi_uuid = "";
185 0 : if (vmi_uuid_presence) {
186 0 : vmi_uuid = url.substr(vmi_uuid_pos+1, std::string::npos);
187 : }
188 :
189 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
190 0 : if (pih) {
191 0 : std::string info;
192 0 : if (pih->GetVmVnPort(vm_uuid, vmi_uuid, info)) {
193 0 : REST::SendResponse(data.session, info);
194 : } else {
195 0 : REST::SendErrorResponse(data.session, "{ Not Found }", 404);
196 : }
197 0 : } else {
198 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
199 : }
200 0 : }
201 :
202 0 : void RestServer::VmVnPortCfgGetHandler(const struct RESTData& data) {
203 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
204 0 : if (pih) {
205 : RestServerGetVmCfgTask *t =
206 0 : new RestServerGetVmCfgTask(pih, data);
207 0 : TaskScheduler *scheduler = TaskScheduler::GetInstance();
208 0 : scheduler->Enqueue(t);
209 : } else {
210 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
211 : }
212 0 : }
213 :
214 0 : void RestServer::VmPortEnableHandler(const struct RESTData& data) {
215 0 : std::string error;
216 0 : const std::string& port_id = (*data.match)[1];
217 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
218 0 : if (pih) {
219 0 : if (pih->EnablePort(port_id, error)) {
220 0 : REST::SendResponse(data.session, "{}");
221 : } else {
222 0 : REST::SendErrorResponse(data.session, "{" + error + "}");
223 : }
224 : } else {
225 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
226 : }
227 0 : }
228 :
229 0 : void RestServer::VmPortDisableHandler(const struct RESTData& data) {
230 0 : std::string error;
231 0 : const std::string& port_id = (*data.match)[1];
232 0 : PortIpcHandler *pih = agent_->port_ipc_handler();
233 0 : if (pih) {
234 0 : if (pih->DisablePort(port_id, error)) {
235 0 : REST::SendResponse(data.session, "{}");
236 : } else {
237 0 : REST::SendErrorResponse(data.session, "{" + error + "}");
238 : }
239 : } else {
240 0 : REST::SendErrorResponse(data.session, "{ Operation Not Supported }");
241 : }
242 0 : }
243 :
244 : const std::vector<RestServer::HandlerSpecifier> RestServer::RESTHandlers_ =
245 : boost::assign::list_of
246 : (HandlerSpecifier(
247 : regex("/port"),
248 : HTTP_POST,
249 : &RestServer::VmPortPostHandler))
250 : (HandlerSpecifier(
251 : regex("/syncports"),
252 : HTTP_POST,
253 : &RestServer::VmPortSyncHandler))
254 : (HandlerSpecifier(
255 : regex("/port/"
256 : "([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"),
257 : HTTP_DELETE,
258 : &RestServer::VmPortDeleteHandler))
259 : (HandlerSpecifier(
260 : regex("/port/"
261 : "([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"),
262 : HTTP_GET,
263 : &RestServer::VmPortGetHandler))
264 : (HandlerSpecifier(
265 : regex("/gateway"),
266 : HTTP_POST,
267 : &RestServer::GatewayPostHandler))
268 : (HandlerSpecifier(
269 : regex("/gateway"),
270 : HTTP_DELETE,
271 : &RestServer::GatewayDeleteHandler))
272 : (HandlerSpecifier(
273 : regex("/vm"),
274 : HTTP_POST,
275 : &RestServer::VmVnPortPostHandler))
276 : (HandlerSpecifier(
277 : regex("/vm/"
278 : "([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"),
279 : HTTP_DELETE,
280 : &RestServer::VmVnPortDeleteHandler))
281 : (HandlerSpecifier(
282 : regex("/vm/"
283 : "([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"),
284 : HTTP_GET,
285 : &RestServer::VmVnPortGetHandler))
286 : (HandlerSpecifier(
287 : regex("/vm/"
288 : "([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/"
289 : "([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"),
290 : HTTP_GET,
291 : &RestServer::VmVnPortGetHandler))
292 : (HandlerSpecifier(
293 : regex("/vm-cfg/(.*)"),
294 : HTTP_GET,
295 : &RestServer::VmVnPortCfgGetHandler))
296 : (HandlerSpecifier(
297 : regex("/enable-port/"
298 : "([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"),
299 : HTTP_PUT,
300 : &RestServer::VmPortEnableHandler))
301 : (HandlerSpecifier(
302 : regex("/disable-port/"
303 : "([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})"),
304 : HTTP_PUT,
305 : &RestServer::VmPortDisableHandler));
306 :
307 0 : RestServer::RestServer(Agent *agent)
308 0 : : agent_(agent), http_server_(new HttpServer(agent->event_manager())) {
309 0 : http_server_->RegisterHandler(HTTP_WILDCARD_ENTRY,
310 : boost::bind(&RestServer::HandleRequest, this, _1, _2));
311 0 : }
312 :
313 0 : void RestServer::InitDone() {
314 0 : if (agent_ && agent_->params() && agent_->params()->cat_is_agent_mocked())
315 : //only if RestServer is used via mocked agent
316 0 : http_server_->Initialize(agent_->params()->rest_port());
317 : else //otherwise , use the hardcoded value
318 0 : http_server_->Initialize(ContrailPorts::PortIpcVrouterAgentPort());
319 0 : }
320 :
321 0 : void RestServer::HandleRequest(HttpSession* session,
322 : const HttpRequest* request) {
323 0 : std::string path = request->UrlPath();
324 0 : BOOST_FOREACH(const RestServer::HandlerSpecifier& hs, RESTHandlers_) {
325 0 : boost::smatch match;
326 0 : if (regex_match(path, match, hs.request_regex) &&
327 0 : request->GetMethod() == hs.method) {
328 : struct RESTData data = {
329 : &match,
330 0 : request->GetMethod(),
331 : session,
332 : request
333 0 : };
334 0 : (this->*hs.handler_func)(data);
335 : // Though IMHO it contradicts most programmers' intuition,
336 : // currently handlers are responsible for freeing handled
337 : // requests.
338 0 : delete request;
339 0 : return;
340 : }
341 0 : }
342 0 : REST::SendErrorResponse(session, "Unknown Request", 404);
343 0 : }
344 :
345 0 : void RestServer::Shutdown() {
346 0 : if (http_server_) {
347 0 : http_server_->Shutdown();
348 0 : TcpServerManager::DeleteServer(http_server_);
349 0 : http_server_ = NULL;
350 : }
351 0 : }
352 :
353 0 : RestServer::~RestServer() {
354 0 : }
|