Skip to content

Commit

Permalink
Merge pull request #1938 from HubSpot/slave_cache_fix
Browse files Browse the repository at this point in the history
Make Slave/Rack Resource use proxy to leader
  • Loading branch information
ssalinas authored May 20, 2019
2 parents 0cf15b9 + c029f90 commit 0453ce5
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response.Status;

import org.apache.curator.framework.recipes.leader.LeaderLatch;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.hubspot.singularity.MachineState;
import com.hubspot.singularity.SingularityAction;
Expand All @@ -20,15 +23,17 @@
import com.hubspot.singularity.data.AbstractMachineManager.StateChangeResult;
import com.hubspot.singularity.data.SingularityValidator;
import com.hubspot.singularity.expiring.SingularityExpiringMachineState;
import com.ning.http.client.AsyncHttpClient;

public abstract class AbstractMachineResource<T extends SingularityMachineAbstraction<T>> {
public abstract class AbstractMachineResource<T extends SingularityMachineAbstraction<T>> extends AbstractLeaderAwareResource {

protected final AbstractMachineManager<T> manager;

protected final SingularityAuthorizationHelper authorizationHelper;
private final SingularityValidator validator;

public AbstractMachineResource(AbstractMachineManager<T> manager, SingularityAuthorizationHelper authorizationHelper, SingularityValidator validator) {
public AbstractMachineResource(AsyncHttpClient httpClient, LeaderLatch leaderLatch, ObjectMapper objectMapper, AbstractMachineManager<T> manager, SingularityAuthorizationHelper authorizationHelper, SingularityValidator validator) {
super(httpClient, leaderLatch, objectMapper);
this.manager = manager;
this.authorizationHelper = authorizationHelper;
this.validator = validator;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.curator.framework.recipes.leader.LeaderLatch;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.google.inject.Inject;
import com.hubspot.singularity.MachineState;
Expand All @@ -24,6 +30,7 @@
import com.hubspot.singularity.data.RackManager;
import com.hubspot.singularity.data.SingularityValidator;
import com.hubspot.singularity.expiring.SingularityExpiringMachineState;
import com.ning.http.client.AsyncHttpClient;

import io.dropwizard.auth.Auth;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -40,8 +47,13 @@
public class RackResource extends AbstractMachineResource<SingularityRack> {

@Inject
public RackResource(RackManager rackManager, SingularityAuthorizationHelper authorizationHelper, SingularityValidator validator) {
super(rackManager, authorizationHelper, validator);
public RackResource(AsyncHttpClient httpClient,
LeaderLatch leaderLatch,
ObjectMapper objectMapper,
RackManager rackManager,
SingularityAuthorizationHelper authorizationHelper,
SingularityValidator validator) {
super(httpClient, leaderLatch, objectMapper, rackManager, authorizationHelper, validator);
}

@Override
Expand Down Expand Up @@ -72,52 +84,73 @@ public List<SingularityMachineStateHistoryUpdate> getRackHistory(
@DELETE
@Path("/rack/{rackId}")
@Operation(summary = "Remove a known rack, erasing history. This operation will cancel decommissioning of racks")
public void removeRack(
public Response removeRack(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Rack ID") @PathParam("rackId") String rackId) {
super.remove(rackId, user);
return maybeProxyToLeader(requestContext, Response.class, null, () -> {
super.remove(rackId, user);
return Response.ok().build();
});
}

@POST
@Path("/rack/{rackId}/decommission")
@Operation(summary = "Begin decommissioning a specific active rack")
public void decommissionRack(
public Response decommissionRack(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Rack ID") @PathParam("rackId") String rackId,
@RequestBody(description = "Settings related to changing the state of a rack") SingularityMachineChangeRequest changeRequest) {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.decommission(rackId, maybeChangeRequest, user, SingularityAction.DECOMMISSION_RACK);
return maybeProxyToLeader(requestContext, Response.class, changeRequest, () -> {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.decommission(rackId, maybeChangeRequest, user, SingularityAction.DECOMMISSION_RACK);
return Response.ok().build();
});

}

@POST
@Path("/rack/{rackId}/freeze")
@Operation(summary = "Freeze a specific rack")
public void freezeRack(
public Response freezeRack(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Rack ID") @PathParam("rackId") String rackId,
@RequestBody(description = "Settings related to changing the state of a slave") SingularityMachineChangeRequest changeRequest) {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.freeze(rackId, maybeChangeRequest, user, SingularityAction.FREEZE_RACK);
return maybeProxyToLeader(requestContext, Response.class, changeRequest, () -> {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.freeze(rackId, maybeChangeRequest, user, SingularityAction.FREEZE_RACK);
return Response.ok().build();
});
}

@POST
@Path("/rack/{rackId}/activate")
@Operation(summary = "Activate a decomissioning rack, canceling decomission without erasing history")
public void activateRack(
public Response activateRack(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Rack ID") @PathParam("rackId") String rackId,
@RequestBody(description = "Settings related to changing the state of a slave") SingularityMachineChangeRequest changeRequest) {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.activate(rackId, maybeChangeRequest, user, SingularityAction.ACTIVATE_RACK);
return maybeProxyToLeader(requestContext, Response.class, changeRequest, () -> {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.activate(rackId, maybeChangeRequest, user, SingularityAction.ACTIVATE_RACK);
return Response.ok().build();
});
}

@DELETE
@Path("/rack/{rackId}/expiring")
@Operation(summary = "Delete any expiring machine state changes for this rack")
public void deleteExpiringStateChange(
public Response deleteExpiringStateChange(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Rack ID") @PathParam("rackId") String rackId) {
super.cancelExpiring(rackId, user);
return maybeProxyToLeader(requestContext, Response.class, null, () -> {
super.cancelExpiring(rackId, user);
return Response.ok().build();
});
}

@GET
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
Expand All @@ -10,8 +11,13 @@
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;

import org.apache.curator.framework.recipes.leader.LeaderLatch;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Optional;
import com.google.inject.Inject;
import com.hubspot.singularity.MachineState;
Expand All @@ -25,6 +31,7 @@
import com.hubspot.singularity.data.SingularityValidator;
import com.hubspot.singularity.data.SlaveManager;
import com.hubspot.singularity.expiring.SingularityExpiringMachineState;
import com.ning.http.client.AsyncHttpClient;

import io.dropwizard.auth.Auth;
import io.swagger.v3.oas.annotations.Operation;
Expand All @@ -40,8 +47,13 @@
@Tags({@Tag(name = "Slaves")})
public class SlaveResource extends AbstractMachineResource<SingularitySlave> {
@Inject
public SlaveResource(SlaveManager slaveManager, SingularityAuthorizationHelper authorizationHelper, SingularityValidator validator) {
super(slaveManager, authorizationHelper, validator);
public SlaveResource(AsyncHttpClient httpClient,
LeaderLatch leaderLatch,
ObjectMapper objectMapper,
SlaveManager slaveManager,
SingularityAuthorizationHelper authorizationHelper,
SingularityValidator validator) {
super(httpClient, leaderLatch, objectMapper, slaveManager, authorizationHelper, validator);
}

@Override
Expand Down Expand Up @@ -82,20 +94,32 @@ public Optional<SingularitySlave> getSlave(
@DELETE
@Path("/slave/{slaveId}")
@Operation(summary = "Remove a known slave, erasing history. This operation will cancel decomissioning of the slave")
public void removeSlave(
public Response removeSlave(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Active SlaveId") @PathParam("slaveId") String slaveId) {
super.remove(slaveId, user);
return maybeProxyToLeader(requestContext, Response.class, null, () -> {
super.remove(slaveId, user);
return Response.ok().build();
});
}

@POST
@Path("/slave/{slaveId}/decommission")
@Operation(summary = "Begin decommissioning a specific active slave")
@Consumes({ MediaType.APPLICATION_JSON })
public void decommissionSlave(
public Response decommissionSlave(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Active slaveId") @PathParam("slaveId") String slaveId,
@RequestBody(description = "Settings related to changing the state of a slave") SingularityMachineChangeRequest changeRequest) {
return maybeProxyToLeader(requestContext, Response.class, changeRequest, () -> {
decommissionSlave(user, slaveId, changeRequest);
return Response.ok().build();
});
}

public void decommissionSlave(SingularityUser user, String slaveId, SingularityMachineChangeRequest changeRequest) {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.decommission(slaveId, maybeChangeRequest, user, SingularityAction.DECOMMISSION_SLAVE);
}
Expand All @@ -104,10 +128,18 @@ public void decommissionSlave(
@Path("/slave/{slaveId}/freeze")
@Operation(summary = "Freeze tasks on a specific slave")
@Consumes({ MediaType.APPLICATION_JSON })
public void freezeSlave(
public Response freezeSlave(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Slave ID") @PathParam("slaveId") String slaveId,
@RequestBody(description = "Settings related to changing the state of a slave") SingularityMachineChangeRequest changeRequest) {
return maybeProxyToLeader(requestContext, Response.class, changeRequest, () -> {
freezeSlave(user, slaveId, changeRequest);
return Response.ok().build();
});
}

public void freezeSlave(SingularityUser user, String slaveId, SingularityMachineChangeRequest changeRequest) {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.freeze(slaveId, maybeChangeRequest, user, SingularityAction.FREEZE_SLAVE);
}
Expand All @@ -116,21 +148,33 @@ public void freezeSlave(
@Path("/slave/{slaveId}/activate")
@Operation(summary = "Activate a decomissioning slave, canceling decomission without erasing history")
@Consumes({ MediaType.APPLICATION_JSON })
public void activateSlave(
public Response activateSlave(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Active slaveId") @PathParam("slaveId") String slaveId,
@RequestBody(description = "Settings related to changing the state of a slave") SingularityMachineChangeRequest changeRequest) {
return maybeProxyToLeader(requestContext, Response.class, changeRequest, () -> {
activateSlave(user, slaveId, changeRequest);
return Response.ok().build();
});
}

public void activateSlave(SingularityUser user, String slaveId, SingularityMachineChangeRequest changeRequest) {
final Optional<SingularityMachineChangeRequest> maybeChangeRequest = Optional.fromNullable(changeRequest);
super.activate(slaveId, maybeChangeRequest, user, SingularityAction.ACTIVATE_SLAVE);
}

@DELETE
@Path("/slave/{slaveId}/expiring")
@Operation(summary = "Delete any expiring machine state changes for this slave")
public void deleteExpiringStateChange(
public Response deleteExpiringStateChange(
@Context HttpServletRequest requestContext,
@Parameter(hidden = true) @Auth SingularityUser user,
@Parameter(required = true, description = "Active slaveId") @PathParam("slaveId") String slaveId) {
super.cancelExpiring(slaveId, user);
return maybeProxyToLeader(requestContext, Response.class, null, () -> {
super.cancelExpiring(slaveId, user);
return Response.ok().build();
});
}

@GET
Expand All @@ -142,8 +186,11 @@ public List<SingularityExpiringMachineState> getExpiringStateChanges(@Parameter(

@DELETE
@Path("/dead")
public void clearAllDeadSlaves(@Auth SingularityUser user) {
authorizationHelper.checkAdminAuthorization(user);
manager.getObjectsFiltered(MachineState.DEAD).forEach((s) -> manager.deleteObject(s.getId()));
public Response clearAllDeadSlaves(@Context HttpServletRequest requestContext, @Auth SingularityUser user) {
return maybeProxyToLeader(requestContext, Response.class, null, () -> {
authorizationHelper.checkAdminAuthorization(user);
manager.getObjectsFiltered(MachineState.DEAD).forEach((s) -> manager.deleteObject(s.getId()));
return Response.ok().build();
});
}
}

0 comments on commit 0453ce5

Please sign in to comment.