2 * Copyright IBM Corporation, 2013. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.controller.samples.loadbalancer.northbound;
10 import java.util.List;
12 import javax.ws.rs.Consumes;
13 import javax.ws.rs.DELETE;
14 import javax.ws.rs.GET;
15 import javax.ws.rs.POST;
16 import javax.ws.rs.PUT;
17 import javax.ws.rs.Path;
18 import javax.ws.rs.PathParam;
19 import javax.ws.rs.Produces;
20 import javax.ws.rs.core.MediaType;
21 import javax.ws.rs.core.Response;
22 import javax.xml.bind.JAXBElement;
24 import org.codehaus.enunciate.jaxrs.ResponseCode;
25 import org.codehaus.enunciate.jaxrs.StatusCodes;
26 import org.codehaus.enunciate.jaxrs.TypeHint;
27 import org.opendaylight.controller.containermanager.IContainerManager;
28 import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
29 import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
30 import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
31 import org.opendaylight.controller.northbound.commons.RestMessages;
32 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
33 import org.opendaylight.controller.northbound.commons.exception.MethodNotAllowedException;
34 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
35 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
36 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
37 import org.opendaylight.controller.northbound.commons.exception.UnsupportedMediaTypeException;
38 import org.opendaylight.controller.sal.utils.ServiceHelper;
39 import org.opendaylight.controller.samples.loadbalancer.IConfigManager;
42 * This class exposes North bound REST APIs for the Load Balancer Service.
43 * Following APIs are exposed by the Load Balancer Service:
45 * Data retrieval REST APIs::
46 * 1. Get details of all existing pools
48 * URI : /one/nb/v2/lb/{container-name}/
49 * NOTE: Current implementation of the opendaylight usage 'default' as a container-name
50 * e.g : http://localhost:8080/one/nb/v2/lb/default will give you list of all the pools
52 * 2. Get details of all the existing VIPs
54 * URI: /one/nb/v2/lb/{container-name}/vips
56 * Pool related REST APIs::
59 * URI : /one/nb/v2/lb/{container-name}/create/pool
65 * Currently, two load balancing policies are allowed {"roundrobin" and "random" }
69 * URI : /one/nb/v2/lb/{container-name}/delete/pool/{pool-name}
71 * VIP related REST APIs::
74 * URI : /one/nb/v2/lb/{container-name}/create/vip
78 * "ip":"ip in (xxx.xxx.xxx.xxx) format",
79 * "protocol":"TCP/UDP",
80 * "port":"any valid port number",
81 * "poolname":"" (optional)
83 * The pool name is optional and can be set up at a later stage (using the REST API given below).
85 * 2. Update VIP: Update pool name of the VIP
87 * URI : /one/nb/v2/lb/{container-name}/update/vip
93 * Currently, we only allow update of the VIP pool name (if a VIP does not have an attached pool)
94 * and not of the VIP name itself.
95 * The specified pool name must already exist. If the specified VIP is already attached to a pool, the update
100 * URI : /one/nb/v2/lb/{container-name}/delete/vip/{vip-name}
102 * Pool member related REST APIs::
103 * 1. Create pool member:
105 * URI : /one/nb/v2/lb/default/create/poolmember
109 * "ip":"ip in (xxx.xxx.xxx.xxx) format",
110 * "poolname":"existing pool name"
113 * 2. Delete pool member:
115 * URI : /one/nb/v2/lb/{container-name}/delete/poolmember/{pool-member-name}/{pool-name}
117 * NOTE: Property "name" of each individual entity must be unique.
118 * All the above REST APIs throw appropriate response codes in case of error/success.
119 * Please consult the respective methods to get details of various response codes.
123 public class LoadBalancerNorthbound {
126 * Method returns the Load balancer service instance running within
127 * 'default' container.
129 private IConfigManager getConfigManagerService(String containerName) {
130 IContainerManager containerManager = (IContainerManager) ServiceHelper
131 .getGlobalInstance(IContainerManager.class, this);
132 if (containerManager == null) {
133 throw new ServiceUnavailableException("Container "
134 + RestMessages.SERVICEUNAVAILABLE.toString());
137 boolean found = false;
138 List<String> containerNames = containerManager.getContainerNames();
139 for (String cName : containerNames) {
140 if (cName.trim().equalsIgnoreCase(containerName.trim())) {
145 if (found == false) {
146 throw new ResourceNotFoundException(containerName + " "
147 + RestMessages.NOCONTAINER.toString());
150 IConfigManager configManager = (IConfigManager) ServiceHelper.getInstance(
151 IConfigManager.class, containerName, this);
153 if (configManager == null) {
154 throw new ServiceUnavailableException("Load Balancer"
155 + RestMessages.SERVICEUNAVAILABLE.toString());
158 return configManager;
161 @Path("/{containerName}")
163 @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
164 @TypeHint(Pools.class)
166 @ResponseCode(code = 200, condition = "Operation successful"),
167 @ResponseCode(code = 404, condition = "The containerName is not found"),
168 @ResponseCode(code = 503, condition = "Load balancer service is unavailable") })
169 public Pools getAllPools(
170 @PathParam("containerName") String containerName) {
172 IConfigManager configManager = getConfigManagerService(containerName);
173 if (configManager == null) {
174 throw new ServiceUnavailableException("Load Balancer "
175 + RestMessages.SERVICEUNAVAILABLE.toString());
178 return new Pools(configManager.getAllPools());
181 @Path("/{containerName}/vips")
183 @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
184 @TypeHint(VIPs.class)
186 @ResponseCode(code = 200, condition = "Operation successful"),
187 @ResponseCode(code = 404, condition = "The containerName is not found"),
188 @ResponseCode(code = 503, condition = "Load balancer service is unavailable") })
189 public VIPs getAllVIPs(
190 @PathParam("containerName") String containerName) {
192 IConfigManager configManager = getConfigManagerService(containerName);
193 if (configManager == null) {
194 throw new ServiceUnavailableException("Load Balancer "
195 + RestMessages.SERVICEUNAVAILABLE.toString());
198 return new VIPs(configManager.getAllVIPs());
201 @Path("/{containerName}/create/vip")
203 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
205 @ResponseCode(code = 201, condition = "VIP created successfully"),
206 @ResponseCode(code = 404, condition = "The Container Name not found"),
207 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
208 @ResponseCode(code = 409, condition = "VIP already exist"),
209 @ResponseCode(code = 415, condition = "Invalid input data")})
210 public Response addVIP(@PathParam("containerName") String containerName,
211 @TypeHint(VIP.class) VIP inVIP){
213 VIP vipInput = inVIP;
214 String name = vipInput.getName();
215 String ip = vipInput.getIp();
216 String protocol = vipInput.getProtocol();
217 short protocolPort = vipInput.getPort();
218 String poolName = vipInput.getPoolName();
223 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
226 IConfigManager configManager = getConfigManagerService(containerName);
228 if (configManager == null) {
229 throw new ServiceUnavailableException("Load Balancer "
230 + RestMessages.SERVICEUNAVAILABLE.toString());
233 if(!configManager.vipExists(name, ip, protocol, protocolPort, poolName)){
235 VIP vip = configManager.createVIP(name, ip, protocol, protocolPort, poolName);
237 return Response.status(Response.Status.CREATED).build();
240 throw new ResourceConflictException(NBConst.RES_VIP_ALREADY_EXIST);
242 throw new InternalServerErrorException(NBConst.RES_VIP_CREATION_FAILED);
245 @Path("/{containerName}/update/vip")
247 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
249 @ResponseCode(code = 201, condition = "VIP updated successfully"),
250 @ResponseCode(code = 404, condition = "The containerName not found"),
251 @ResponseCode(code = 503, condition = "VIP not found"),
252 @ResponseCode(code = 404, condition = "Pool not found"),
253 @ResponseCode(code = 405, condition = "Pool already attached to the VIP"),
254 @ResponseCode(code = 415, condition = "Invalid input name")})
255 public Response updateVIP(@PathParam("containerName") String containerName,
256 @TypeHint(VIP.class) VIP inVIP) {
258 VIP vipInput = inVIP;
259 String name = vipInput.getName();
260 String poolName = vipInput.getPoolName();
263 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
266 IConfigManager configManager = getConfigManagerService(containerName);
267 if (configManager == null) {
268 throw new ServiceUnavailableException("Load Balancer "
269 + RestMessages.SERVICEUNAVAILABLE.toString());
272 if(!configManager.poolExists(poolName))
273 throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
275 if(configManager.getVIPAttachedPool(name)!=null)
276 throw new MethodNotAllowedException(NBConst.RES_VIP_POOL_EXIST);
278 if(configManager.updateVIP(name, poolName)!= null)
279 return Response.status(Response.Status.ACCEPTED).build();
281 throw new InternalServerErrorException(NBConst.RES_VIP_UPDATE_FAILED);
284 @Path("/{containerName}/delete/vip/{vipName}")
286 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
288 @ResponseCode(code = 200, condition = "VIP deleted successfully"),
289 @ResponseCode(code = 404, condition = "The containerName not found"),
290 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
291 @ResponseCode(code = 404, condition = "VIP not found"),
292 @ResponseCode(code = 500, condition = "Failed to delete VIP")})
293 public Response deleteVIP(
294 @PathParam(value = "containerName") String containerName,
295 @PathParam(value = "vipName") String vipName) {
297 if(vipName.isEmpty())
298 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
300 IConfigManager configManager = getConfigManagerService(containerName);
301 if (configManager == null) {
302 throw new ServiceUnavailableException("Load Balancer"
303 + RestMessages.SERVICEUNAVAILABLE.toString());
306 if(!configManager.vipExists(vipName))
307 throw new ResourceNotFoundException(NBConst.RES_VIP_NOT_FOUND);
309 for(VIP vip : configManager.getAllVIPs()){
310 if(vip.getName().equals(vipName)){
311 configManager.deleteVIP(vipName);
312 return Response.ok().build();
315 throw new InternalServerErrorException(NBConst.RES_VIP_DELETION_FAILED);
318 @Path("/{containerName}/create/pool")
320 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
322 @ResponseCode(code = 201, condition = "Pool created successfully"),
323 @ResponseCode(code = 404, condition = "The containerName not found"),
324 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
325 @ResponseCode(code = 409, condition = "Pool already exist"),
326 @ResponseCode(code = 415, condition = "Invalid input data")})
327 public Response addPool(@PathParam("containerName") String containerName,
328 @TypeHint(Pool.class) Pool inPool) {
330 Pool poolInput = inPool;
331 String name = poolInput.getName();
332 String lbMethod =poolInput.getLbMethod();
335 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
338 IConfigManager configManager = getConfigManagerService(containerName);
339 if (configManager == null) {
340 throw new ServiceUnavailableException("Load Balancer "
341 + RestMessages.SERVICEUNAVAILABLE.toString());
344 if(!configManager.poolExists(name)){
346 Pool pool = configManager.createPool(name, lbMethod);
348 return Response.status(Response.Status.CREATED).build();
351 throw new ResourceConflictException(NBConst.RES_POOL_ALREADY_EXIST);
353 throw new InternalServerErrorException(NBConst.RES_POOL_CREATION_FAILED);
356 @Path("/{containerName}/delete/pool/{poolName}")
358 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
360 @ResponseCode(code = 200, condition = "Pool deleted successfully"),
361 @ResponseCode(code = 404, condition = "The containerName not found"),
362 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
363 @ResponseCode(code = 404, condition = "Pool not found"),
364 @ResponseCode(code = 500, condition = "Failed to delete Pool")})
365 public Response deletePool(
366 @PathParam(value = "containerName") String containerName,
367 @PathParam(value = "poolName") String poolName) {
369 if(poolName.isEmpty())
370 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
372 IConfigManager configManager = getConfigManagerService(containerName);
373 if (configManager == null) {
374 throw new ServiceUnavailableException("Load Balancer"
375 + RestMessages.SERVICEUNAVAILABLE.toString());
378 if(!configManager.poolExists(poolName))
379 throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
381 for(Pool pool:configManager.getAllPools()){
382 if(pool.getName().equals(poolName)){
383 configManager.deletePool(poolName);
384 return Response.ok().build();
387 throw new InternalServerErrorException(NBConst.RES_POOL_DELETION_FAILED);
390 @Path("/{containerName}/create/poolmember")
392 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
394 @ResponseCode(code = 201, condition = "Pool member created successfully"),
395 @ResponseCode(code = 404, condition = "The containerName not found"),
396 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
397 @ResponseCode(code = 404, condition = "Pool not found"),
398 @ResponseCode(code = 409, condition = "Pool member already exist"),
399 @ResponseCode(code = 415, condition = "Invalid input data")})
400 public Response addPoolMember(@PathParam("containerName") String containerName,
401 @TypeHint(PoolMember.class) PoolMember inPoolMember){
403 PoolMember pmInput = inPoolMember;
404 String name = pmInput.getName();
405 String memberIP = pmInput.getIp();
406 String poolName = pmInput.getPoolName();
411 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
414 IConfigManager configManager = getConfigManagerService(containerName);
415 if (configManager == null) {
416 throw new ServiceUnavailableException("Load Balancer "
417 + RestMessages.SERVICEUNAVAILABLE.toString());
420 if(!configManager.poolExists(poolName))
421 throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
423 if(!configManager.memberExists(name, memberIP, poolName)){
425 PoolMember poolMember = configManager.addPoolMember(name, memberIP, poolName);
426 if ( poolMember != null){
427 return Response.status(Response.Status.CREATED).build();
430 throw new ResourceConflictException(NBConst.RES_POOLMEMBER_ALREADY_EXIST);
432 throw new InternalServerErrorException(NBConst.RES_POOLMEMBER_CREATION_FAILED);
435 @Path("/{containerName}/delete/poolmember/{poolMemberName}/{poolName}")
437 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
439 @ResponseCode(code = 200, condition = "Pool member deleted successfully"),
440 @ResponseCode(code = 404, condition = "The containerName not found"),
441 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
442 @ResponseCode(code = 404, condition = "Pool member not found"),
443 @ResponseCode(code = 404, condition = "Pool not found")})
444 public Response deletePoolMember(
445 @PathParam(value = "containerName") String containerName,
446 @PathParam(value = "poolMemberName") String poolMemberName,
447 @PathParam(value = "poolName") String poolName) {
449 if(poolMemberName.isEmpty()||
451 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
453 IConfigManager configManager = getConfigManagerService(containerName);
455 if (configManager == null) {
456 throw new ServiceUnavailableException("Load Balancer"
457 + RestMessages.SERVICEUNAVAILABLE.toString());
460 if(!configManager.poolExists(poolName))
461 throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
463 if(configManager.memberExists(poolMemberName, poolName)){
465 configManager.removePoolMember(poolMemberName, poolName);
467 return Response.ok().build();
469 throw new ResourceNotFoundException(NBConst.RES_POOLMEMBER_NOT_FOUND);