Fixes to make path redirect affinity work using the new nfchainagent service.
[affinity.git] / affinity / northbound / src / main / java / org / opendaylight / affinity / affinity / northbound / AffinityNorthbound.java
1 /*
2  * Copyright (c) 2013 Plexxi, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.affinity.affinity.northbound;
10
11 import java.util.ArrayList;
12 import java.util.HashSet;
13 import java.util.List;
14 import java.util.Map;
15 import java.util.Set;
16
17 import javax.ws.rs.Consumes;
18 import javax.ws.rs.DELETE;
19 import javax.ws.rs.GET;
20 import javax.ws.rs.POST;
21 import javax.ws.rs.PUT;
22 import javax.ws.rs.Path;
23 import javax.ws.rs.PathParam;
24 import javax.ws.rs.Produces;
25 import javax.ws.rs.core.Context;
26 import javax.ws.rs.core.MediaType;
27 import javax.ws.rs.core.Response;
28 import javax.ws.rs.core.SecurityContext;
29
30 import org.codehaus.enunciate.jaxrs.ResponseCode;
31 import org.codehaus.enunciate.jaxrs.StatusCodes;
32 import org.codehaus.enunciate.jaxrs.TypeHint;
33 import org.opendaylight.controller.containermanager.IContainerManager;
34 import org.opendaylight.controller.northbound.commons.RestMessages;
35 import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
36 import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
37 import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
38 import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
39 import org.opendaylight.controller.northbound.commons.exception.UnauthorizedException;
40 import org.opendaylight.controller.northbound.commons.utils.NorthboundUtils;
41 import org.opendaylight.controller.sal.authorization.Privilege;
42 import org.opendaylight.controller.sal.utils.GlobalConstants;
43 import org.opendaylight.controller.sal.utils.ServiceHelper;
44 import org.opendaylight.controller.sal.utils.Status;
45 import org.opendaylight.affinity.affinity.IAffinityManager;
46 import org.opendaylight.affinity.affinity.AffinityLink;
47 import org.opendaylight.affinity.affinity.AffinityGroup;
48
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51
52 /**
53  * The class provides Northbound REST APIs to access affinity configuration.
54  *
55  */
56
57 @Path("/")
58 public class AffinityNorthbound {
59
60     private String username;
61     private static final Logger log = LoggerFactory.getLogger(AffinityNorthbound.class);
62
63     @Context
64     public void setSecurityContext(SecurityContext context) {
65         username = context.getUserPrincipal().getName();
66     }
67
68     protected String getUserName() {
69         return username;
70     }
71
72     private IAffinityManager getIfAffinityManagerService(String containerName) {
73         log.debug("In getIfAffinityManager");
74
75         IContainerManager containerManager = (IContainerManager) ServiceHelper
76                 .getGlobalInstance(IContainerManager.class, this);
77         if (containerManager == null) {
78             throw new ServiceUnavailableException("Container "
79                     + RestMessages.SERVICEUNAVAILABLE.toString());
80         }
81
82         boolean found = false;
83         List<String> containerNames = containerManager.getContainerNames();
84         for (String cName : containerNames) {
85             if (cName.trim().equalsIgnoreCase(containerName.trim())) {
86                 found = true;
87                 break;
88             }
89         }
90
91         if (found == false) {
92             throw new ResourceNotFoundException(containerName + " "
93                     + RestMessages.SERVICEUNAVAILABLE.toString());
94         }
95
96         IAffinityManager affinityManager = (IAffinityManager) ServiceHelper
97                 .getInstance(IAffinityManager.class, containerName, this);
98
99         if (affinityManager == null) {
100             throw new ServiceUnavailableException("Affinity Manager "
101                     + RestMessages.SERVICEUNAVAILABLE.toString());
102         }
103
104         return affinityManager;
105     }
106
107     /**
108      * Add an affinity to the configuration database
109      *
110      * @param containerName
111      *            Name of the Container
112      * @param affinityGroupName
113      *            Name of the new affinity group being added
114      * @return Response as dictated by the HTTP Response Status code
115      */
116
117     @Path("/{containerName}/create/group/{affinityGroupName}")
118     @PUT
119     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
120     @TypeHint(Response.class)
121     @StatusCodes({
122             @ResponseCode(code = 200, condition = "Operation successful"),
123             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
124             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
125     public Response createAffinityGroup(
126             @PathParam("containerName") String containerName,
127             @PathParam("affinityGroupName") String affinityGroupName) {
128
129         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
130             throw new UnauthorizedException("User is not authorized to perform this operation on container "
131                                             + containerName);
132         }
133         log.info("add a new affinitygroup = {}, containerName = {}",  affinityGroupName, containerName);
134         IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
135         if (affinityManager == null) {
136             throw new ServiceUnavailableException("Affinity Manager "
137                                                   + RestMessages.SERVICEUNAVAILABLE.toString());
138         }
139
140         AffinityGroup ag1 = new AffinityGroup(affinityGroupName);
141         Status ret = affinityManager.addAffinityGroup(ag1);
142         
143         return Response.status(Response.Status.CREATED).build();
144     }
145
146     /**
147      * Returns details of an affinity group.
148      *
149      * @param containerName
150      *            Name of the Container. The Container name for the base
151      *            controller is "default".
152      * @param affinityGroupName
153      *            Name of the affinity group being retrieved.
154      * @return affinity configuration that matches the affinity name.
155      */
156     @Path("/{containerName}/group/{affinityGroupName}")
157     @GET
158     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
159     @TypeHint(AffinityGroup.class)
160     @StatusCodes({
161             @ResponseCode(code = 200, condition = "Operation successful"),
162             @ResponseCode(code = 404, condition = "The containerName is not found"),
163             @ResponseCode(code = 415, condition = "Affinity name is not found"),
164             @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
165     public AffinityGroup getAffinityGroupDetails(
166             @PathParam("containerName") String containerName,
167             @PathParam("affinityGroupName") String affinityGroupName) {
168         if (!NorthboundUtils.isAuthorized(
169                 getUserName(), containerName, Privilege.READ, this)) {
170             throw new UnauthorizedException(
171                     "User is not authorized to perform this operation on container "
172                             + containerName);
173         }
174         IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
175         if (affinityManager == null) {
176             throw new ServiceUnavailableException("Affinity "
177                                                   + RestMessages.SERVICEUNAVAILABLE.toString());
178         }
179
180         log.info("Get affinity group details" + affinityGroupName);
181         AffinityGroup ag = affinityManager.getAffinityGroup(affinityGroupName);
182         if (ag == null) {
183             throw new ResourceNotFoundException(RestMessages.SERVICEUNAVAILABLE.toString());
184         } else {
185             return ag;
186         }
187     }
188
189     /**
190      * Add an affinity link with one "from" and one "to" affinity group. 
191      *
192      * @param containerName
193      *            Name of the Container
194      * @param affinityLinkName
195      *            Name of the new affinity link being added
196      * @return Response as dictated by the HTTP Response Status code
197      */
198
199     @Path("/{containerName}/create/link/{affinityLinkName}/from/{fromAffinityGroup}/to/{toAffinityGroup}")
200     @PUT
201     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
202     @TypeHint(Response.class)
203     @StatusCodes({
204             @ResponseCode(code = 200, condition = "Operation successful"),
205             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
206             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
207     public Response createAffinityLink(
208             @PathParam("containerName") String containerName,
209             @PathParam("affinityLinkName") String affinityLinkName,
210             @PathParam("fromAffinityGroup") String fromAffinityGroup,
211             @PathParam("toAffinityGroup") String toAffinityGroup) {
212
213         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
214             throw new UnauthorizedException("User is not authorized to perform this operation on container "
215                                             + containerName);
216         }
217
218         IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
219         if (affinityManager == null) {
220             throw new ServiceUnavailableException("Affinity Manager "
221                                                   + RestMessages.SERVICEUNAVAILABLE.toString());
222         }
223
224         
225         log.info("Create affinity link" + affinityLinkName + "fromGroup" + fromAffinityGroup + "toGroup" + toAffinityGroup);
226         AffinityGroup from = affinityManager.getAffinityGroup(fromAffinityGroup);
227         AffinityGroup to = affinityManager.getAffinityGroup(toAffinityGroup);
228         AffinityLink al1 = new AffinityLink(affinityLinkName, from, to);
229
230         Status ret = affinityManager.addAffinityLink(al1);
231         if (!ret.isSuccess()) {
232             throw new InternalServerErrorException(ret.getDescription());
233         }
234         return Response.status(Response.Status.CREATED).build();
235     }
236
237
238     /**
239      * Add path redirect details to an affinity link. 
240      *
241      * @param containerName
242      *            Name of the Container
243      * @param affinityLinkName
244      *            Name of the new affinity link being added
245      * @param wayPoint
246      *            IP address string of a waypoint server or VM
247      * @return Response as dictated by the HTTP Response Status code
248      */
249
250     @Path("/{containerName}/link/{affinityLinkName}/setwaypoint/{waypointIP}")
251     @PUT
252     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
253     @TypeHint(Response.class)
254     @StatusCodes({
255             @ResponseCode(code = 200, condition = "Operation successful"),
256             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
257             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
258     public Response setLinkWaypoint(
259             @PathParam("containerName") String containerName,
260             @PathParam("affinityLinkName") String affinityLinkName,
261             @PathParam("waypointIP") String waypointIP) {
262
263         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
264             throw new UnauthorizedException("User is not authorized to perform this operation on container "
265                                             + containerName);
266         }
267
268         IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
269         if (affinityManager == null) {
270             throw new ServiceUnavailableException("Affinity Manager "
271                                                   + RestMessages.SERVICEUNAVAILABLE.toString());
272         }
273         log.info("Set waypoint address (link)" + affinityLinkName + " (waypoint ip) " + waypointIP);
274
275         AffinityLink al1 = affinityManager.getAffinityLink(affinityLinkName);
276         al1.setWaypoint(waypointIP);
277         try {
278             affinityManager.addNfchain(al1);
279             affinityManager.enableRedirect(al1);
280         } catch (Exception e) {
281             String message = "An error occurred during flow programming.";
282             log.error(message, e);
283         }
284         return Response.status(Response.Status.CREATED).build();
285     }
286
287
288     /**
289      * Add IP addresses to a group. 
290      *
291      * @param containerName
292      *            Name of the Container
293      * @param affinityGroupName
294      *            Name of the affinity group to add to. 
295      * @param ipaddress
296      *            IP address of the new affinity member. 
297      * @return Response as dictated by the HTTP Response Status code
298      */
299     @Path("/{containerName}/group/{affinityGroupName}/add/ip/{ipaddress}")
300     @PUT
301     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
302     @TypeHint(Response.class)
303     @StatusCodes({
304             @ResponseCode(code = 200, condition = "Operation successful"),
305             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
306             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
307     public Response addInetAddress(
308             @PathParam("containerName") String containerName,
309             @PathParam("affinityGroupName") String affinityGroupName,
310             @PathParam("ipaddress") String ipaddress) {
311         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
312             throw new UnauthorizedException("User is not authorized to perform this operation on container "
313                                             + containerName);
314         }
315         
316         IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
317         if (affinityManager == null) {
318             throw new ServiceUnavailableException("Affinity Manager "
319                                                   + RestMessages.SERVICEUNAVAILABLE.toString());
320         }
321         
322         log.info("add Inet address " + affinityGroupName + " (ipaddress) " + ipaddress);
323         AffinityGroup ag1 = affinityManager.getAffinityGroup(affinityGroupName);
324         ag1.add(ipaddress);
325         
326         return Response.status(Response.Status.CREATED).build();
327     }
328     
329     /**
330      * Add prefix/mask subnet as a member of the affinity group.
331      *
332      * @param containerName
333      *            Name of the Container
334      * @param affinityGroupName
335      *            Name of the affinity group to add to. 
336      * @param ipmask
337      *            a.b.c.d/mm format of a set of IP addresses to add.
338      * @return Response as dictated by the HTTP Response Status code
339      */
340     @Path("/{containerName}/group/{affinityGroupName}/addsubnet/ipprefix/{ipprefix}/mask/{mask}")
341     @PUT
342     @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
343     @TypeHint(Response.class)
344     @StatusCodes({
345             @ResponseCode(code = 200, condition = "Operation successful"),
346             @ResponseCode(code = 404, condition = "The Container Name or nodeId or configuration name is not found"),
347             @ResponseCode(code = 503, condition = "One or more of Controller services are unavailable") })
348     public Response addSubnet(
349             @PathParam("containerName") String containerName,
350             @PathParam("affinityGroupName") String affinityGroupName,
351             @PathParam("ipprefix") String ipprefix,
352             @PathParam("mask") String mask) {
353         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.WRITE, this)) {
354             throw new UnauthorizedException("User is not authorized to perform this operation on container "
355                                             + containerName);
356         }
357         
358         IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
359         if (affinityManager == null) {
360             throw new ServiceUnavailableException("Affinity Manager "
361                                                   + RestMessages.SERVICEUNAVAILABLE.toString());
362         }
363         
364         log.info("addSubnet to affinitygroup" + affinityGroupName);
365         AffinityGroup ag1 = affinityManager.getAffinityGroup(affinityGroupName);
366         String ipmask = ipprefix + "/" + mask;
367         ag1.addInetMask(ipmask);
368         
369         return Response.status(Response.Status.CREATED).build();
370     }
371
372
373     @Path("/{containerName}/affinity-groups")
374     @GET
375     @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
376     @TypeHint(AffinityGroupList.class)
377     @StatusCodes({ @ResponseCode(code = 200, condition = "Operation successful"),
378         @ResponseCode(code = 401, condition = "User not authorized to perform this operation"),
379         @ResponseCode(code = 404, condition = "The containerName is not found"),
380         @ResponseCode(code = 503, condition = "One or more of Controller Services are unavailable") })
381     public AffinityGroupList getAllAffinityGroups(@PathParam("containerName") String containerName) {
382
383         //        if (!isValidContainer(containerName)) {
384         //            throw new ResourceNotFoundException("Container " + containerName + " does not exist.");
385         //}
386
387         if (!NorthboundUtils.isAuthorized(getUserName(), containerName, Privilege.READ, this)) {
388             throw new UnauthorizedException("User is not authorized to perform this operation on container "
389                     + containerName);
390         }
391
392         IAffinityManager affinityManager = getIfAffinityManagerService(containerName);
393         if (affinityManager == null) {
394             throw new ServiceUnavailableException("Affinity Manager "
395                                                   + RestMessages.SERVICEUNAVAILABLE.toString());
396         }
397         log.info("getallgroups");
398         return new AffinityGroupList(affinityManager.getAllAffinityGroups());
399     }
400
401 }