diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java index cf0a83a..2c85a60 100644 --- hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/RMWebServices.java @@ -92,6 +92,11 @@ import org.apache.hadoop.yarn.api.records.NodeState; import org.apache.hadoop.yarn.api.records.Priority; import org.apache.hadoop.yarn.api.records.QueueACL; +import org.apache.hadoop.yarn.api.records.ReservationDefinition; +import org.apache.hadoop.yarn.api.records.ReservationId; +import org.apache.hadoop.yarn.api.records.ReservationRequest; +import org.apache.hadoop.yarn.api.records.ReservationRequestInterpreter; +import org.apache.hadoop.yarn.api.records.ReservationRequests; import org.apache.hadoop.yarn.api.records.Resource; import org.apache.hadoop.yarn.api.records.YarnApplicationState; import org.apache.hadoop.yarn.conf.YarnConfiguration; @@ -130,6 +135,20 @@ import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.LocalResourceInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodeInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.NodesInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDefinitionInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteResponseInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationRequestInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationRequestsInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionResponseInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateResponseInfo; +import org.apache.hadoop.yarn.api.protocolrecords.ReservationDeleteRequest; +import org.apache.hadoop.yarn.api.protocolrecords.ReservationDeleteResponse; +import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionRequest; +import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionResponse; +import org.apache.hadoop.yarn.api.protocolrecords.ReservationUpdateRequest; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ResourceInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerInfo; import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.SchedulerTypeInfo; @@ -1495,4 +1514,254 @@ public CancelDelegationTokenResponse run() throws IOException, } return token; } + + + /** + * Function to submit a Reservation to the RM + * + * @param newReservation + * structure containing information to construct the + * ReservationSubmissionReques + * @param hsr + * the servlet request + * @return Response containing the status code + * @throws AuthorizationException + * @throws IOException + * @throws InterruptedException + */ + @POST + @Path("/reservation/submit") + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response submitReservation( + ReservationSubmissionRequestInfo resContext, + @Context HttpServletRequest hsr) throws AuthorizationException, + IOException, InterruptedException { + + init(); + UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); + if (callerUGI == null) { + throw new AuthorizationException("Unable to obtain user name, " + + "user not authenticated"); + } + if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) { + String msg = "The default static user cannot carry out this operation."; + return Response.status(Status.FORBIDDEN).entity(msg).build(); + } + + final ReservationSubmissionRequest reservation = createReservationSubmissionRequest(resContext); + + ReservationSubmissionResponseInfo resRespInfo; + try { + resRespInfo = callerUGI + .doAs(new PrivilegedExceptionAction() { + @Override + public ReservationSubmissionResponseInfo run() throws IOException, + YarnException { + ReservationSubmissionResponse tempRes = rm.getClientRMService() + .submitReservation(reservation); + return new ReservationSubmissionResponseInfo(tempRes); + } + }); + } catch (UndeclaredThrowableException ue) { + if (ue.getCause() instanceof YarnException) { + throw new BadRequestException(ue.getCause().getMessage()); + } + LOG.info("Submit reservation request failed", ue); + throw ue; + } + + return Response.status(Status.OK).entity(resRespInfo).build(); + } + + private ReservationSubmissionRequest createReservationSubmissionRequest( + ReservationSubmissionRequestInfo resContext) { + + ReservationDefinitionInfo resInfo = resContext.getReservationDefinition(); + ReservationRequestsInfo resReqsInfo = resInfo.getReservationRequests(); + ReservationRequestInterpreter[] values = ReservationRequestInterpreter + .values(); + ReservationRequestInterpreter resInt = values[resReqsInfo + .getReservationRequestsInterpreter()]; + List list = new ArrayList(); + + for (ReservationRequestInfo resReqInfo : resReqsInfo + .getReservationRequeust()) { + ResourceInfo rInfo = resReqInfo.getCapability(); + Resource capability = Resource.newInstance(rInfo.getMemory(), + rInfo.getvCores()); + int numContainers = resReqInfo.getNumContainers(); + int minConcurrency = resReqInfo.getMinConcurrency(); + long duration = resReqInfo.getDuration(); + ReservationRequest rr = ReservationRequest.newInstance(capability, + numContainers, minConcurrency, duration); + list.add(rr); + } + ReservationRequests reqs = ReservationRequests.newInstance(list, resInt); + ReservationDefinition rDef = ReservationDefinition.newInstance( + resInfo.getArrival(), resInfo.getDeadline(), reqs, + resInfo.getReservationName()); + ReservationSubmissionRequest request = ReservationSubmissionRequest + .newInstance(rDef, resContext.getQueue()); + + return request; + } + + /** + * Function to update a Reservation to the RM + * + * @param updatedReservation + * structure containing information to construct the + * ReservationUpdateRequest + * @param hsr + * the servlet request + * @return Response containing the status code + * @throws AuthorizationException + * @throws IOException + * @throws InterruptedException + */ + @POST + @Path("/reservation/update") + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response updateReservation(ReservationUpdateRequestInfo resContext, + @Context HttpServletRequest hsr) throws AuthorizationException, + IOException, InterruptedException { + + init(); + UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); + if (callerUGI == null) { + throw new AuthorizationException("Unable to obtain user name, " + + "user not authenticated"); + } + if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) { + String msg = "The default static user cannot carry out this operation."; + return Response.status(Status.FORBIDDEN).entity(msg).build(); + } + + final ReservationUpdateRequest reservation = createReservationUpdateRequest(resContext); + + ReservationUpdateResponseInfo resRespInfo; + try { + resRespInfo = callerUGI + .doAs(new PrivilegedExceptionAction() { + @Override + public ReservationUpdateResponseInfo run() throws IOException, + YarnException { + rm.getClientRMService().updateReservation(reservation); + return new ReservationUpdateResponseInfo(); + } + }); + } catch (UndeclaredThrowableException ue) { + if (ue.getCause() instanceof YarnException) { + throw new BadRequestException(ue.getCause().getMessage()); + } + LOG.info("Update reservation request failed", ue); + throw ue; + } + + return Response.status(Status.OK).entity(resRespInfo).build(); + } + + private ReservationUpdateRequest createReservationUpdateRequest( + ReservationUpdateRequestInfo resContext) throws IOException { + + ReservationDefinitionInfo resInfo = resContext.getReservationDefinition(); + ReservationRequestsInfo resReqsInfo = resInfo.getReservationRequests(); + ReservationRequestInterpreter[] values = ReservationRequestInterpreter + .values(); + ReservationRequestInterpreter resInt = values[resReqsInfo + .getReservationRequestsInterpreter()]; + List list = new ArrayList(); + + for (ReservationRequestInfo resReqInfo : resReqsInfo + .getReservationRequeust()) { + ResourceInfo rInfo = resReqInfo.getCapability(); + Resource capability = Resource.newInstance(rInfo.getMemory(), + rInfo.getvCores()); + int numContainers = resReqInfo.getNumContainers(); + int minConcurrency = resReqInfo.getMinConcurrency(); + long duration = resReqInfo.getDuration(); + ReservationRequest rr = ReservationRequest.newInstance(capability, + numContainers, minConcurrency, duration); + list.add(rr); + } + ReservationRequests reqs = ReservationRequests.newInstance(list, resInt); + ReservationDefinition rDef = ReservationDefinition.newInstance( + resInfo.getArrival(), resInfo.getDeadline(), reqs, + resInfo.getReservationName()); + ReservationUpdateRequest request = ReservationUpdateRequest.newInstance( + rDef, ReservationId.parseReservationId(resContext.getReservationId() + .getReservationId())); + + return request; + } + + /** + * Function to delete a Reservation to the RM + * + * @param deleteReservation + * structure containing the iinformation to construct the + * ReservationDeleteRequest + * @param hsr + * the servlet request + * @return Response containing the status code + * @throws AuthorizationException + * @throws IOException + * @throws InterruptedException + */ + @POST + @Path("/reservation/delete") + @Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + @Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) + public Response deleteReservation(ReservationDeleteRequestInfo resContext, + @Context HttpServletRequest hsr) throws AuthorizationException, + IOException, InterruptedException { + + init(); + UserGroupInformation callerUGI = getCallerUserGroupInformation(hsr, true); + if (callerUGI == null) { + throw new AuthorizationException("Unable to obtain user name, " + + "user not authenticated"); + } + if (UserGroupInformation.isSecurityEnabled() && isStaticUser(callerUGI)) { + String msg = "The default static user cannot carry out this operation."; + return Response.status(Status.FORBIDDEN).entity(msg).build(); + } + + final ReservationDeleteRequest reservation = createReservationDeleteRequest(resContext); + + ReservationDeleteResponseInfo resRespInfo; + try { + resRespInfo = callerUGI + .doAs(new PrivilegedExceptionAction() { + @Override + public ReservationDeleteResponseInfo run() throws IOException, + YarnException { + ReservationDeleteResponse tempRes = rm.getClientRMService() + .deleteReservation(reservation); + return new ReservationDeleteResponseInfo(); + } + }); + } catch (UndeclaredThrowableException ue) { + if (ue.getCause() instanceof YarnException) { + throw new BadRequestException(ue.getCause().getMessage()); + } + LOG.info("Update reservation request failed", ue); + throw ue; + } + + return Response.status(Status.OK).entity(resRespInfo).build(); + } + + private ReservationDeleteRequest createReservationDeleteRequest( + ReservationDeleteRequestInfo resContext) throws IOException { + + ReservationDeleteRequest request = ReservationDeleteRequest + .newInstance(ReservationId.parseReservationId(resContext + .getReservationId().getReservationId())); + + return request; + } + } diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDefinitionInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDefinitionInfo.java new file mode 100644 index 0000000..3c2363c --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDefinitionInfo.java @@ -0,0 +1,78 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Simple class that represent a reservation definition + * + */ +@XmlRootElement(name = "reservation-definition") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationDefinitionInfo { + + long arrival; + long deadline; + @XmlElement(name = "reservation-requests") + ReservationRequestsInfo reservationRequests; + + @XmlElement(name = "reservation-name") + String reservationName; + + public ReservationDefinitionInfo() { + + } + + public long getArrival() { + return arrival; + } + + public void setArrival(long arrival) { + this.arrival = arrival; + } + + public long getDeadline() { + return deadline; + } + + public void setDeadline(long deadline) { + this.deadline = deadline; + } + + public ReservationRequestsInfo getReservationRequests() { + return reservationRequests; + } + + public void setReservationRequests(ReservationRequestsInfo reservationRequests) { + this.reservationRequests = reservationRequests; + } + + public String getReservationName() { + return reservationName; + } + + public void setReservationName(String reservationName) { + this.reservationName = reservationName; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDeleteRequestInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDeleteRequestInfo.java new file mode 100644 index 0000000..7d7a24f --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDeleteRequestInfo.java @@ -0,0 +1,52 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import java.io.IOException; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Simple class to allow users to send information required to create an + * ReservationSubmissionContext which can then be used to submit a reservation + * + */ +@XmlRootElement(name = "reservation-delete-context") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationDeleteRequestInfo { + + @XmlElement(name = "reservation-id") + ReservationIdInfo reservationId; + + public ReservationDeleteRequestInfo() { + reservationId = null; + } + + public ReservationIdInfo getReservationId() { + return reservationId; + } + + public void setReservationId(ReservationIdInfo reservationId) { + this.reservationId = reservationId; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDeleteResponseInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDeleteResponseInfo.java new file mode 100644 index 0000000..4fbad13 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationDeleteResponseInfo.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Simple class that represent a reservation definition + * + */ +@XmlRootElement(name = "reservation-delete-response") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationDeleteResponseInfo { + + public ReservationDeleteResponseInfo() { + + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationIdInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationIdInfo.java new file mode 100644 index 0000000..efe6ef1 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationIdInfo.java @@ -0,0 +1,57 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.hadoop.yarn.api.records.ReservationId; + +/** + * Simple class to allow users to send information required to create an + * ReservationSubmissionContext which can then be used to submit a reservation + * + */ +@XmlRootElement(name = "reservation-id") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationIdInfo { + + @XmlElement(name = "reservation-id") + String reservationId; + + + public ReservationIdInfo() { + reservationId = null; + } + public ReservationIdInfo(ReservationId rid) { + reservationId = rid.toString(); + } + + public String getReservationId() { + return reservationId; + } + + public void setReservationId(String reservationId) { + this.reservationId = reservationId; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationRequestInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationRequestInfo.java new file mode 100644 index 0000000..01a9f4e --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationRequestInfo.java @@ -0,0 +1,57 @@ +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "reservation-definition") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationRequestInfo { + + @XmlElement(name = "capability") + ResourceInfo capability; + @XmlElement(name = "min-concurrency") + int minConcurrency; + @XmlElement(name = "num-containers") + int numContainers; + @XmlElement(name = "duration") + long duration; + + public ReservationRequestInfo() { + + } + + public ResourceInfo getCapability() { + return capability; + } + + public void setCapability(ResourceInfo capability) { + this.capability = capability; + } + + public int getMinConcurrency() { + return minConcurrency; + } + + public void setMinConcurrency(int minConcurrency) { + this.minConcurrency = minConcurrency; + } + + public int getNumContainers() { + return numContainers; + } + + public void setNumContainers(int numContainers) { + this.numContainers = numContainers; + } + + public long getDuration() { + return duration; + } + + public void setDuration(long duration) { + this.duration = duration; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationRequestsInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationRequestsInfo.java new file mode 100644 index 0000000..c8e5389 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationRequestsInfo.java @@ -0,0 +1,40 @@ +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import java.util.ArrayList; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "reservation-definition") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationRequestsInfo { + + @XmlElement(name = "reservation-request-interpreter") + int reservationRequestsInterpreter; + @XmlElement(name = "reservation-request") + ArrayList reservationRequeust; + + public ReservationRequestsInfo() { + + } + + public int getReservationRequestsInterpreter() { + return reservationRequestsInterpreter; + } + + public void setReservationRequestsInterpreter( + int reservationRequestsInterpreter) { + this.reservationRequestsInterpreter = reservationRequestsInterpreter; + } + + public ArrayList getReservationRequeust() { + return reservationRequeust; + } + + public void setReservationRequeust(ArrayList reservationRequeust) { + this.reservationRequeust = reservationRequeust; + } + +} \ No newline at end of file diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationSubmissionRequestInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationSubmissionRequestInfo.java new file mode 100644 index 0000000..b2ce1c1 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationSubmissionRequestInfo.java @@ -0,0 +1,62 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Simple class to allow users to send information required to create an + * ReservationSubmissionContext which can then be used to submit a reservation + * + */ +@XmlRootElement(name = "reservation-submission-context") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationSubmissionRequestInfo { + + String queue; + + @XmlElement(name = "reservation-definition") + ReservationDefinitionInfo reservationDefinition; + + public ReservationSubmissionRequestInfo() { + queue = null; + reservationDefinition = null; + } + + public String getQueue() { + return queue; + } + + public void setQueue(String queue) { + this.queue = queue; + } + + public ReservationDefinitionInfo getReservationDefinition() { + return reservationDefinition; + } + + public void setReservationDefinition( + ReservationDefinitionInfo reservationDefinition) { + this.reservationDefinition = reservationDefinition; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationSubmissionResponseInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationSubmissionResponseInfo.java new file mode 100644 index 0000000..3135c60 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationSubmissionResponseInfo.java @@ -0,0 +1,51 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.hadoop.yarn.api.protocolrecords.ReservationSubmissionResponse; + +/** + * Simple class that represent a reservation definition + * + */ +@XmlRootElement(name = "reservation-submission-response") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationSubmissionResponseInfo { + + @XmlElement(name = "reservation-id") + String reservationId; + + public ReservationSubmissionResponseInfo() { + + } + + public ReservationSubmissionResponseInfo(ReservationSubmissionResponse response) { + this.reservationId = response.getReservationId().toString(); + } + + public String getReservationId() { + return reservationId; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationUpdateRequestInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationUpdateRequestInfo.java new file mode 100644 index 0000000..85d222b --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationUpdateRequestInfo.java @@ -0,0 +1,65 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import java.io.IOException; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Simple class to allow users to send information required to create an + * ReservationSubmissionContext which can then be used to submit a reservation + * + */ +@XmlRootElement(name = "reservation-update-context") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationUpdateRequestInfo { + + @XmlElement(name = "reservation-id") + ReservationIdInfo reservationId; + + @XmlElement(name = "reservation-definition") + ReservationDefinitionInfo reservationDefinition; + + public ReservationUpdateRequestInfo() { + reservationId = null; + reservationDefinition = null; + } + + public ReservationIdInfo getReservationId() { + return reservationId; + } + + public void setReservationId(ReservationIdInfo reservationId) { + this.reservationId = reservationId; + } + + public ReservationDefinitionInfo getReservationDefinition() { + return reservationDefinition; + } + + public void setReservationDefinition( + ReservationDefinitionInfo reservationDefinition) { + this.reservationDefinition = reservationDefinition; + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationUpdateResponseInfo.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationUpdateResponseInfo.java new file mode 100644 index 0000000..9e616f8 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/main/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/dao/ReservationUpdateResponseInfo.java @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp.dao; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlRootElement; + +/** + * Simple class that represent a reservation definition + * + */ +@XmlRootElement(name = "reservation-update-response") +@XmlAccessorType(XmlAccessType.FIELD) +public class ReservationUpdateResponseInfo { + + public ReservationUpdateResponseInfo() { + + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesReservation.java hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesReservation.java new file mode 100644 index 0000000..ed30b95 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/java/org/apache/hadoop/yarn/server/resourcemanager/webapp/TestRMWebServicesReservation.java @@ -0,0 +1,509 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.yarn.server.resourcemanager.webapp; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringReader; +import java.util.Arrays; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Properties; + +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.ws.rs.core.MediaType; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.io.FileUtils; +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.security.authentication.server.AuthenticationFilter; +import org.apache.hadoop.security.authentication.server.PseudoAuthenticationHandler; +import org.apache.hadoop.yarn.api.records.ReservationId; +import org.apache.hadoop.yarn.conf.YarnConfiguration; +import org.apache.hadoop.yarn.server.resourcemanager.MockNM; +import org.apache.hadoop.yarn.server.resourcemanager.MockRM; +import org.apache.hadoop.yarn.server.resourcemanager.ResourceManager; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacitySchedulerConfiguration; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairScheduler; +import org.apache.hadoop.yarn.server.resourcemanager.scheduler.fair.FairSchedulerConfiguration; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationDeleteRequestInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationIdInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationSubmissionRequestInfo; +import org.apache.hadoop.yarn.server.resourcemanager.webapp.dao.ReservationUpdateRequestInfo; +import org.apache.hadoop.yarn.webapp.GenericExceptionHandler; +import org.apache.hadoop.yarn.webapp.JerseyTestBase; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import com.google.inject.Singleton; +import com.google.inject.servlet.GuiceServletContextListener; +import com.google.inject.servlet.ServletModule; +import com.sun.jersey.api.client.ClientResponse; +import com.sun.jersey.api.client.ClientResponse.Status; +import com.sun.jersey.api.client.WebResource; +import com.sun.jersey.api.client.config.DefaultClientConfig; +import com.sun.jersey.api.json.JSONConfiguration; +import com.sun.jersey.api.json.JSONJAXBContext; +import com.sun.jersey.api.json.JSONUnmarshaller; +import com.sun.jersey.guice.spi.container.servlet.GuiceContainer; +import com.sun.jersey.test.framework.WebAppDescriptor; + +@RunWith(Parameterized.class) +public class TestRMWebServicesReservation extends JerseyTestBase { + private static MockRM rm; + + private static Injector injector; + private String webserviceUserName = "testuser"; + + private boolean setAuthFilter = false; + + private static final String TEST_DIR = new File(System.getProperty( + "test.build.data", "/tmp")).getAbsolutePath(); + private static final String FS_ALLOC_FILE = new File(TEST_DIR, + "test-fs-queues.xml").getAbsolutePath(); + + public static class GuiceServletConfig extends GuiceServletContextListener { + + @Override + protected Injector getInjector() { + return injector; + } + } + + /* + * Helper class to allow testing of RM web services which require + * authorization Add this class as a filter in the Guice injector for the + * MockRM + */ + + @Singleton + public static class TestRMCustomAuthFilter extends AuthenticationFilter { + + @Override + protected Properties getConfiguration(String configPrefix, + FilterConfig filterConfig) throws ServletException { + Properties props = new Properties(); + Enumeration names = filterConfig.getInitParameterNames(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + if (name.startsWith(configPrefix)) { + String value = filterConfig.getInitParameter(name); + props.put(name.substring(configPrefix.length()), value); + } + } + props.put(AuthenticationFilter.AUTH_TYPE, "simple"); + props.put(PseudoAuthenticationHandler.ANONYMOUS_ALLOWED, "false"); + return props; + } + + } + + private abstract class TestServletModule extends ServletModule { + public Configuration conf = new Configuration(); + + public abstract void configureScheduler(); + + @Override + protected void configureServlets() { + configureScheduler(); + bind(JAXBContextResolver.class); + bind(RMWebServices.class); + bind(GenericExceptionHandler.class); + conf.setInt(YarnConfiguration.RM_AM_MAX_ATTEMPTS, + YarnConfiguration.DEFAULT_RM_AM_MAX_ATTEMPTS); + Configuration conf = new Configuration(); + conf.setBoolean(YarnConfiguration.RM_RESERVATION_SYSTEM_ENABLE, + true); + conf.setInt(YarnConfiguration.RM_AM_MAX_ATTEMPTS, + YarnConfiguration.DEFAULT_RM_AM_MAX_ATTEMPTS); + conf.setClass(YarnConfiguration.RM_SCHEDULER, + CapacityScheduler.class, ResourceScheduler.class); + CapacitySchedulerConfiguration csconf = new CapacitySchedulerConfiguration( + conf); + String[] queues = { "default", "dedicated" }; + csconf.setQueues("root", queues); + csconf.setCapacity("root.default", 50.0f); + csconf.setCapacity("root.dedicated", 50.0f); + csconf.setReservable("root.dedicated", true); + + rm = new MockRM(csconf); + bind(ResourceManager.class).toInstance(rm); + if (setAuthFilter) { + filter("/*").through(TestRMCustomAuthFilter.class); + } + serve("/*").with(GuiceContainer.class); + } + } + + private class CapTestServletModule extends TestServletModule { + @Override + public void configureScheduler() { + conf.set("yarn.resourcemanager.scheduler.class", + CapacityScheduler.class.getName()); + } + } + + private class FairTestServletModule extends TestServletModule { + @Override + public void configureScheduler() { + try { + PrintWriter out = new PrintWriter(new FileWriter(FS_ALLOC_FILE)); + out.println(""); + out.println(""); + out.println(""); + out.println(" someuser "); + out.println(" "); + out.println(" someuser "); + out.println(" "); + out.println(" "); + out.println(" someuser "); + out.println(" "); + out.println(""); + out.println(""); + out.close(); + } catch (IOException e) { + } + conf.set(FairSchedulerConfiguration.ALLOCATION_FILE, FS_ALLOC_FILE); + conf.set("yarn.resourcemanager.scheduler.class", + FairScheduler.class.getName()); + } + } + + private Injector getNoAuthInjectorCap() { + return Guice.createInjector(new CapTestServletModule() { + @Override + protected void configureServlets() { + setAuthFilter = false; + super.configureServlets(); + } + }); + } + + private Injector getSimpleAuthInjectorCap() { + return Guice.createInjector(new CapTestServletModule() { + @Override + protected void configureServlets() { + setAuthFilter = true; + conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true); + // set the admin acls otherwise all users are considered admins + // and we can't test authorization + conf.setStrings(YarnConfiguration.YARN_ADMIN_ACL, "testuser1"); + super.configureServlets(); + } + }); + } + + private Injector getNoAuthInjectorFair() { + return Guice.createInjector(new FairTestServletModule() { + @Override + protected void configureServlets() { + setAuthFilter = false; + super.configureServlets(); + } + }); + } + + private Injector getSimpleAuthInjectorFair() { + return Guice.createInjector(new FairTestServletModule() { + @Override + protected void configureServlets() { + setAuthFilter = true; + conf.setBoolean(YarnConfiguration.YARN_ACL_ENABLE, true); + // set the admin acls otherwise all users are considered admins + // and we can't test authorization + conf.setStrings(YarnConfiguration.YARN_ADMIN_ACL, "testuser1"); + super.configureServlets(); + } + }); + } + + @Parameters + public static Collection guiceConfigs() { + return Arrays.asList(new Object[][] { { 0 }, { 1 }, { 2 }, { 3 } }); + } + + @Before + @Override + public void setUp() throws Exception { + super.setUp(); + } + + public TestRMWebServicesReservation(int run) { + super(new WebAppDescriptor.Builder( + "org.apache.hadoop.yarn.server.resourcemanager.webapp") + .contextListenerClass(GuiceServletConfig.class) + .filterClass(com.google.inject.servlet.GuiceFilter.class) + .clientConfig( + new DefaultClientConfig(JAXBContextResolver.class)) + .contextPath("jersey-guice-filter").servletPath("/").build()); + switch (run) { + case 0: + default: + // No Auth Capacity Scheduler + injector = getNoAuthInjectorCap(); + break; + case 1: + // Simple Auth Capacity Scheduler + injector = getSimpleAuthInjectorCap(); + break; + case 2: + // No Auth Fair Scheduler + injector = getNoAuthInjectorFair(); + break; + case 3: + // Simple Auth Fair Scheduler + injector = getSimpleAuthInjectorFair(); + break; + } + } + + private boolean isAuthenticationEnabled() { + return setAuthFilter; + } + + private WebResource constructWebResource(WebResource r, String... paths) { + WebResource rt = r; + for (String path : paths) { + rt = rt.path(path); + } + if (isAuthenticationEnabled()) { + rt = rt.queryParam("user.name", webserviceUserName); + } + return rt; + } + + private WebResource constructWebResource(String... paths) { + WebResource r = resource(); + WebResource ws = r.path("ws").path("v1").path("cluster"); + return this.constructWebResource(ws, paths); + } + + @After + @Override + public void tearDown() throws Exception { + if (rm != null) { + rm.stop(); + } + super.tearDown(); + } + + + @Test + public void testSubmitReservation() throws JSONException, Exception { + rm.start(); + for (int i = 0; i < 100; i++) { + MockNM amNodeManager = rm.registerNode("127.0.0." + i + ":1234", + 100 * 1024); + amNodeManager.nodeHeartbeat(true); + } + ReservationId rid = testSubmissionReservationHelper( + "reservation/submit", MediaType.APPLICATION_JSON); + if (this.isAuthenticationEnabled()) { + assertNotNull(rid); + } + rm.stop(); + } + + @Test + public void testFailedSubmitReservation() throws JSONException, Exception { + rm.start(); + // setup a cluster too small to accept the reservation + for (int i = 0; i < 1; i++) { + MockNM amNodeManager = rm.registerNode("127.0.0." + i + ":1234", + 100 * 1024); + amNodeManager.nodeHeartbeat(true); + } + ReservationId rid = testSubmissionReservationHelper( + "reservation/submit", MediaType.APPLICATION_JSON); + assertNull(rid); + rm.stop(); + } + + @Test + public void testUpdateReservation() throws JSONException, Exception { + rm.start(); + for (int i = 0; i < 100; i++) { + MockNM amNodeManager = rm.registerNode("127.0.0." + i + ":1234", + 100 * 1024); + amNodeManager.nodeHeartbeat(true); + } + ReservationId rid = testSubmissionReservationHelper( + "reservation/submit", MediaType.APPLICATION_JSON); + if (this.isAuthenticationEnabled()) { + assertNotNull(rid); + } + testUpdateReservationHelper("reservation/update", rid, + MediaType.APPLICATION_JSON); + + rm.stop(); + } + + @Test + public void testDeleteReservation() throws JSONException, Exception { + rm.start(); + for (int i = 0; i < 100; i++) { + MockNM amNodeManager = rm.registerNode("127.0.0." + i + ":1234", + 100 * 1024); + amNodeManager.nodeHeartbeat(true); + } + ReservationId rid = testSubmissionReservationHelper( + "reservation/submit", MediaType.APPLICATION_JSON); + if (this.isAuthenticationEnabled()) { + assertNotNull(rid); + } + testDeleteReservationHelper("reservation/delete", rid, + MediaType.APPLICATION_JSON); + + rm.stop(); + } + + private ReservationId testSubmissionReservationHelper(String path, + String media) throws JSONException, Exception { + + String reservationJson = FileUtils.readFileToString(new File( + "src/test/resources/submit-reservation.json")); + + JSONJAXBContext jc = new JSONJAXBContext(JSONConfiguration.mapped() + .rootUnwrapping(false).build(), + ReservationSubmissionRequestInfo.class); + JSONUnmarshaller unmarshaller = jc.createJSONUnmarshaller(); + ReservationSubmissionRequestInfo rsci = unmarshaller.unmarshalFromJSON( + new StringReader(reservationJson), + ReservationSubmissionRequestInfo.class); + + Thread.sleep(1000); + ClientResponse response = constructWebResource(path) + .entity(rsci, MediaType.APPLICATION_JSON).accept(media) + .post(ClientResponse.class); + + if (!this.isAuthenticationEnabled()) { + assertEquals(Status.UNAUTHORIZED, + response.getClientResponseStatus()); + return null; + } + + System.out.println("RESPONSE:" + response); + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); + JSONObject json = response.getEntity(JSONObject.class); + + assertEquals("incorrect number of elements", 1, json.length()); + ReservationId rid = null; + try { + rid = ReservationId.parseReservationId(json + .getString("reservation-id")); + assertEquals("incorrect return value", rid.getId(), 1); + } catch (JSONException j) { + // failure is possible and is checked outside + } + return rid; + } + + private void testUpdateReservationHelper(String path, + ReservationId reservationId, String media) throws JSONException, + Exception { + + String reservationJson = FileUtils.readFileToString(new File( + "src/test/resources/update-reservation.json")); + + JSONJAXBContext jc = new JSONJAXBContext(JSONConfiguration.mapped() + .rootUnwrapping(false).build(), + ReservationUpdateRequestInfo.class); + JSONUnmarshaller unmarshaller = jc.createJSONUnmarshaller(); + ReservationUpdateRequestInfo rsci = unmarshaller.unmarshalFromJSON( + new StringReader(reservationJson), + ReservationUpdateRequestInfo.class); + if (this.isAuthenticationEnabled()) { + // only works when previous submit worked + rsci.setReservationId(new ReservationIdInfo(reservationId)); + } + + Thread.sleep(1000); + ClientResponse response = constructWebResource(path) + .entity(rsci, MediaType.APPLICATION_JSON).accept(media) + .post(ClientResponse.class); + + if (!this.isAuthenticationEnabled()) { + assertEquals(Status.UNAUTHORIZED, + response.getClientResponseStatus()); + return; + } + + System.out.println("RESPONSE:" + response); + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); + assertEquals(Status.OK, response.getClientResponseStatus()); + + } + + private void testDeleteReservationHelper(String path, + ReservationId reservationId, String media) throws JSONException, + Exception { + + String reservationJson = FileUtils.readFileToString(new File( + "src/test/resources/delete-reservation.json")); + + JSONJAXBContext jc = new JSONJAXBContext(JSONConfiguration.mapped() + .rootUnwrapping(false).build(), + ReservationDeleteRequestInfo.class); + JSONUnmarshaller unmarshaller = jc.createJSONUnmarshaller(); + ReservationDeleteRequestInfo rsci = unmarshaller.unmarshalFromJSON( + new StringReader(reservationJson), + ReservationDeleteRequestInfo.class); + if (this.isAuthenticationEnabled()) { + // only works when previous submit worked + rsci.setReservationId(new ReservationIdInfo(reservationId)); + } + + Thread.sleep(1000); + ClientResponse response = constructWebResource(path) + .entity(rsci, MediaType.APPLICATION_JSON).accept(media) + .post(ClientResponse.class); + + if (!this.isAuthenticationEnabled()) { + assertEquals(Status.UNAUTHORIZED, + response.getClientResponseStatus()); + return; + } + + System.out.println("RESPONSE:" + response); + assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getType()); + assertEquals(Status.OK, response.getClientResponseStatus()); + + } + +} diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/delete-reservation.json hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/delete-reservation.json new file mode 100644 index 0000000..972fff8 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/delete-reservation.json @@ -0,0 +1,5 @@ +{ + "reservation-delete-context" : { + "reservation-id" : "reservation_12341234_1" + } +} \ No newline at end of file diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/submit-reservation.json hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/submit-reservation.json new file mode 100644 index 0000000..3c22090 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/submit-reservation.json @@ -0,0 +1,33 @@ +{ + "reservation-submission-context" : { + "queue" : "dedicated", + "reservation-definition" : { + "arrival" : 1765541532000, + "deadline" : 1765542252000, + "reservation-name" : "res_1", + "reservation-requests" : { + "reservation-request-interpreter" : 0, + "reservation-request" : [ + { + "duration" : 60, + "num-containers" : 220, + "min-concurrency" : 220, + "capability" : { + "memory" : 1024, + "vCores" : 1 + } + }, + { + "duration" : 120, + "num-containers" : 110, + "min-concurrency" : 110, + "capability" : { + "memory" : 1024, + "vCores" : 1 + } + } + ] + } + } + } +} \ No newline at end of file diff --git hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/update-reservation.json hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/update-reservation.json new file mode 100644 index 0000000..a8f2aa6 --- /dev/null +++ hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-resourcemanager/src/test/resources/update-reservation.json @@ -0,0 +1,33 @@ +{ + "reservation-update-context" : { + "reservation-id" : "reservation_12341234_1", + "reservation-definition" : { + "arrival" : 1765541532000, + "deadline" : 1765542252000, + "reservation-name" : "res_1", + "reservation-requests" : { + "reservation-request-interpreter" : 0, + "reservation-request" : [ + { + "duration" : 60, + "num-containers" : 100, + "min-concurrency" : 1, + "capability" : { + "memory" : 1024, + "vCores" : 1 + } + }, + { + "duration" : 120, + "num-containers" : 40, + "min-concurrency" : 1, + "capability" : { + "memory" : 1024, + "vCores" : 1 + } + } + ] + } + } + } +} \ No newline at end of file