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