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;
23 import org.codehaus.enunciate.jaxrs.ResponseCode;
24 import org.codehaus.enunciate.jaxrs.StatusCodes;
25 import org.codehaus.enunciate.jaxrs.TypeHint;
26 import org.opendaylight.controller.containermanager.IContainerManager;
27 import org.opendaylight.controller.samples.loadbalancer.entities.Pool;
28 import org.opendaylight.controller.samples.loadbalancer.entities.PoolMember;
29 import org.opendaylight.controller.samples.loadbalancer.entities.VIP;
30 import org.opendaylight.controller.northbound.commons.RestMessages;
31 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
32 import org.opendaylight.controller.northbound.commons.exception.MethodNotAllowedException;
33 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
34 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
35 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
36 import org.opendaylight.controller.northbound.commons.exception.UnsupportedMediaTypeException;
37 import org.opendaylight.controller.sal.utils.ServiceHelper;
38 import org.opendaylight.controller.samples.loadbalancer.IConfigManager;
41 * This class exposes North bound REST APIs for the Load Balancer Service.
42 * Following APIs are exposed by the Load Balancer Service:
44 * Data retrieval REST APIs::
45 * 1. Get details of all existing pools
47 * URI : /one/nb/v2/lb/{container-name}/
48 * NOTE: Current implementation of the opendaylight usage 'default' as a container-name
49 * e.g : http://localhost:8080/one/nb/v2/lb/default will give you list of all the pools
51 * 2. Get details of all the existing VIPs
53 * URI: /one/nb/v2/lb/{container-name}/vips
55 * Pool related REST APIs::
58 * URI : /one/nb/v2/lb/{container-name}/create/pool
64 * Currently, two load balancing policies are allowed {"roundrobin" and "random" }
68 * URI : /one/nb/v2/lb/{container-name}/delete/pool/{pool-name}
70 * VIP related REST APIs::
73 * URI : /one/nb/v2/lb/{container-name}/create/vip
77 * "ip":"ip in (xxx.xxx.xxx.xxx) format",
78 * "protocol":"TCP/UDP",
79 * "port":"any valid port number",
80 * "poolname":"" (optional)
82 * The pool name is optional and can be set up at a later stage (using the REST API given below).
84 * 2. Update VIP: Update pool name of the VIP
86 * URI : /one/nb/v2/lb/{container-name}/update/vip
92 * Currently, we only allow update of the VIP pool name (if a VIP does not have an attached pool)
93 * and not of the VIP name itself.
94 * The specified pool name must already exist. If the specified VIP is already attached to a pool, the update
99 * URI : /one/nb/v2/lb/{container-name}/delete/vip/{vip-name}
101 * Pool member related REST APIs::
102 * 1. Create pool member:
104 * URI : /one/nb/v2/lb/default/create/poolmember
108 * "ip":"ip in (xxx.xxx.xxx.xxx) format",
109 * "poolname":"existing pool name"
112 * 2. Delete pool member:
114 * URI : /one/nb/v2/lb/{container-name}/delete/poolmember/{pool-member-name}/{pool-name}
116 * NOTE: Property "name" of each individual entity must be unique.
117 * All the above REST APIs throw appropriate response codes in case of error/success.
118 * Please consult the respective methods to get details of various response codes.
122 public class LoadBalancerNorthbound {
125 * Method returns the Load balancer service instance running within
126 * 'default' container.
128 private IConfigManager getConfigManagerService(String containerName) {
129 IContainerManager containerManager = (IContainerManager) ServiceHelper
130 .getGlobalInstance(IContainerManager.class, this);
131 if (containerManager == null) {
132 throw new ServiceUnavailableException("Container "
133 + RestMessages.SERVICEUNAVAILABLE.toString());
136 boolean found = false;
137 List<String> containerNames = containerManager.getContainerNames();
138 for (String cName : containerNames) {
139 if (cName.trim().equalsIgnoreCase(containerName.trim())) {
144 if (found == false) {
145 throw new ResourceNotFoundException(containerName + " "
146 + RestMessages.NOCONTAINER.toString());
149 IConfigManager configManager = (IConfigManager) ServiceHelper.getInstance(
150 IConfigManager.class, containerName, this);
152 if (configManager == null) {
153 throw new ServiceUnavailableException("Load Balancer"
154 + RestMessages.SERVICEUNAVAILABLE.toString());
157 return configManager;
160 @Path("/{containerName}")
162 @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
163 @TypeHint(Pools.class)
165 @ResponseCode(code = 200, condition = "Operation successful"),
166 @ResponseCode(code = 404, condition = "The containerName is not found"),
167 @ResponseCode(code = 503, condition = "Load balancer service is unavailable") })
168 public Pools getAllPools(
169 @PathParam("containerName") String containerName) {
171 IConfigManager configManager = getConfigManagerService(containerName);
172 if (configManager == null) {
173 throw new ServiceUnavailableException("Load Balancer "
174 + RestMessages.SERVICEUNAVAILABLE.toString());
177 return new Pools(configManager.getAllPools());
180 @Path("/{containerName}/vips")
182 @Produces( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
183 @TypeHint(VIPs.class)
185 @ResponseCode(code = 200, condition = "Operation successful"),
186 @ResponseCode(code = 404, condition = "The containerName is not found"),
187 @ResponseCode(code = 503, condition = "Load balancer service is unavailable") })
188 public VIPs getAllVIPs(
189 @PathParam("containerName") String containerName) {
191 IConfigManager configManager = getConfigManagerService(containerName);
192 if (configManager == null) {
193 throw new ServiceUnavailableException("Load Balancer "
194 + RestMessages.SERVICEUNAVAILABLE.toString());
197 return new VIPs(configManager.getAllVIPs());
200 @Path("/{containerName}/create/vip")
202 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
204 @ResponseCode(code = 201, condition = "VIP created successfully"),
205 @ResponseCode(code = 404, condition = "The Container Name not found"),
206 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
207 @ResponseCode(code = 409, condition = "VIP already exist"),
208 @ResponseCode(code = 415, condition = "Invalid input data")})
209 public Response addVIP(@PathParam("containerName") String containerName,
210 @TypeHint(VIP.class) VIP inVIP){
212 VIP vipInput = inVIP;
213 String name = vipInput.getName();
214 String ip = vipInput.getIp();
215 String protocol = vipInput.getProtocol();
216 short protocolPort = vipInput.getPort();
217 String poolName = vipInput.getPoolName();
222 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
225 IConfigManager configManager = getConfigManagerService(containerName);
227 if (configManager == null) {
228 throw new ServiceUnavailableException("Load Balancer "
229 + RestMessages.SERVICEUNAVAILABLE.toString());
232 if(!configManager.vipExists(name, ip, protocol, protocolPort, poolName)){
234 VIP vip = configManager.createVIP(name, ip, protocol, protocolPort, poolName);
236 return Response.status(Response.Status.CREATED).build();
239 throw new ResourceConflictException(NBConst.RES_VIP_ALREADY_EXIST);
241 throw new InternalServerErrorException(NBConst.RES_VIP_CREATION_FAILED);
244 @Path("/{containerName}/update/vip")
246 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
248 @ResponseCode(code = 201, condition = "VIP updated successfully"),
249 @ResponseCode(code = 404, condition = "The containerName not found"),
250 @ResponseCode(code = 503, condition = "VIP not found"),
251 @ResponseCode(code = 404, condition = "Pool not found"),
252 @ResponseCode(code = 405, condition = "Pool already attached to the VIP"),
253 @ResponseCode(code = 415, condition = "Invalid input name")})
254 public Response updateVIP(@PathParam("containerName") String containerName,
255 @TypeHint(VIP.class) VIP inVIP) {
257 VIP vipInput = inVIP;
258 String name = vipInput.getName();
259 String poolName = vipInput.getPoolName();
262 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
265 IConfigManager configManager = getConfigManagerService(containerName);
266 if (configManager == null) {
267 throw new ServiceUnavailableException("Load Balancer "
268 + RestMessages.SERVICEUNAVAILABLE.toString());
271 if(!configManager.poolExists(poolName))
272 throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
274 if(configManager.getVIPAttachedPool(name)!=null)
275 throw new MethodNotAllowedException(NBConst.RES_VIP_POOL_EXIST);
277 if(configManager.updateVIP(name, poolName)!= null)
278 return Response.status(Response.Status.ACCEPTED).build();
280 throw new InternalServerErrorException(NBConst.RES_VIP_UPDATE_FAILED);
283 @Path("/{containerName}/delete/vip/{vipName}")
285 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
287 @ResponseCode(code = 200, condition = "VIP deleted successfully"),
288 @ResponseCode(code = 404, condition = "The containerName not found"),
289 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
290 @ResponseCode(code = 404, condition = "VIP not found"),
291 @ResponseCode(code = 500, condition = "Failed to delete VIP")})
292 public Response deleteVIP(
293 @PathParam(value = "containerName") String containerName,
294 @PathParam(value = "vipName") String vipName) {
296 if(vipName.isEmpty())
297 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
299 IConfigManager configManager = getConfigManagerService(containerName);
300 if (configManager == null) {
301 throw new ServiceUnavailableException("Load Balancer"
302 + RestMessages.SERVICEUNAVAILABLE.toString());
305 if(!configManager.vipExists(vipName))
306 throw new ResourceNotFoundException(NBConst.RES_VIP_NOT_FOUND);
308 for(VIP vip : configManager.getAllVIPs()){
309 if(vip.getName().equals(vipName)){
310 configManager.deleteVIP(vipName);
311 return Response.ok().build();
314 throw new InternalServerErrorException(NBConst.RES_VIP_DELETION_FAILED);
317 @Path("/{containerName}/create/pool")
319 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
321 @ResponseCode(code = 201, condition = "Pool created successfully"),
322 @ResponseCode(code = 404, condition = "The containerName not found"),
323 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
324 @ResponseCode(code = 409, condition = "Pool already exist"),
325 @ResponseCode(code = 415, condition = "Invalid input data")})
326 public Response addPool(@PathParam("containerName") String containerName,
327 @TypeHint(Pool.class) Pool inPool) {
329 Pool poolInput = inPool;
330 String name = poolInput.getName();
331 String lbMethod =poolInput.getLbMethod();
334 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
337 IConfigManager configManager = getConfigManagerService(containerName);
338 if (configManager == null) {
339 throw new ServiceUnavailableException("Load Balancer "
340 + RestMessages.SERVICEUNAVAILABLE.toString());
343 if(!configManager.poolExists(name)){
345 Pool pool = configManager.createPool(name, lbMethod);
347 return Response.status(Response.Status.CREATED).build();
350 throw new ResourceConflictException(NBConst.RES_POOL_ALREADY_EXIST);
352 throw new InternalServerErrorException(NBConst.RES_POOL_CREATION_FAILED);
355 @Path("/{containerName}/delete/pool/{poolName}")
357 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
359 @ResponseCode(code = 200, condition = "Pool deleted successfully"),
360 @ResponseCode(code = 404, condition = "The containerName not found"),
361 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
362 @ResponseCode(code = 404, condition = "Pool not found"),
363 @ResponseCode(code = 500, condition = "Failed to delete Pool")})
364 public Response deletePool(
365 @PathParam(value = "containerName") String containerName,
366 @PathParam(value = "poolName") String poolName) {
368 if(poolName.isEmpty())
369 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
371 IConfigManager configManager = getConfigManagerService(containerName);
372 if (configManager == null) {
373 throw new ServiceUnavailableException("Load Balancer"
374 + RestMessages.SERVICEUNAVAILABLE.toString());
377 if(!configManager.poolExists(poolName))
378 throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
380 for(Pool pool:configManager.getAllPools()){
381 if(pool.getName().equals(poolName)){
382 configManager.deletePool(poolName);
383 return Response.ok().build();
386 throw new InternalServerErrorException(NBConst.RES_POOL_DELETION_FAILED);
389 @Path("/{containerName}/create/poolmember")
391 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
393 @ResponseCode(code = 201, condition = "Pool member created successfully"),
394 @ResponseCode(code = 404, condition = "The containerName not found"),
395 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
396 @ResponseCode(code = 404, condition = "Pool not found"),
397 @ResponseCode(code = 409, condition = "Pool member already exist"),
398 @ResponseCode(code = 415, condition = "Invalid input data")})
399 public Response addPoolMember(@PathParam("containerName") String containerName,
400 @TypeHint(PoolMember.class) PoolMember inPoolMember){
402 PoolMember pmInput = inPoolMember;
403 String name = pmInput.getName();
404 String memberIP = pmInput.getIp();
405 String poolName = pmInput.getPoolName();
410 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
413 IConfigManager configManager = getConfigManagerService(containerName);
414 if (configManager == null) {
415 throw new ServiceUnavailableException("Load Balancer "
416 + RestMessages.SERVICEUNAVAILABLE.toString());
419 if(!configManager.poolExists(poolName))
420 throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
422 if(!configManager.memberExists(name, memberIP, poolName)){
424 PoolMember poolMember = configManager.addPoolMember(name, memberIP, poolName);
425 if ( poolMember != null){
426 return Response.status(Response.Status.CREATED).build();
429 throw new ResourceConflictException(NBConst.RES_POOLMEMBER_ALREADY_EXIST);
431 throw new InternalServerErrorException(NBConst.RES_POOLMEMBER_CREATION_FAILED);
434 @Path("/{containerName}/delete/poolmember/{poolMemberName}/{poolName}")
436 @Consumes( { MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
438 @ResponseCode(code = 200, condition = "Pool member deleted successfully"),
439 @ResponseCode(code = 404, condition = "The containerName not found"),
440 @ResponseCode(code = 503, condition = "Load balancer service is unavailable"),
441 @ResponseCode(code = 404, condition = "Pool member not found"),
442 @ResponseCode(code = 404, condition = "Pool not found")})
443 public Response deletePoolMember(
444 @PathParam(value = "containerName") String containerName,
445 @PathParam(value = "poolMemberName") String poolMemberName,
446 @PathParam(value = "poolName") String poolName) {
448 if(poolMemberName.isEmpty()||
450 throw new UnsupportedMediaTypeException(RestMessages.INVALIDDATA.toString());
452 IConfigManager configManager = getConfigManagerService(containerName);
454 if (configManager == null) {
455 throw new ServiceUnavailableException("Load Balancer"
456 + RestMessages.SERVICEUNAVAILABLE.toString());
459 if(!configManager.poolExists(poolName))
460 throw new ResourceNotFoundException(NBConst.RES_POOL_NOT_FOUND);
462 if(configManager.memberExists(poolMemberName, poolName)){
464 configManager.removePoolMember(poolMemberName, poolName);
466 return Response.ok().build();
468 throw new ResourceNotFoundException(NBConst.RES_POOLMEMBER_NOT_FOUND);