Skip to content

Commit

Permalink
Split Host and Component management (#274)
Browse files Browse the repository at this point in the history
* Component management is on its own page now
* Components per host is still viewable on the host page
* Add ability to update host and component
* Add auth to ensure calls that require admin are protected
  • Loading branch information
chrisrohr authored Jul 24, 2023
1 parent 1d33d7b commit 5103998
Show file tree
Hide file tree
Showing 22 changed files with 662 additions and 241 deletions.
10 changes: 5 additions & 5 deletions service/src/main/java/org/kiwiproject/champagne/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

import static org.kiwiproject.dropwizard.util.job.MonitoredJobs.registerJob;

import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;
import java.util.EnumSet;

import io.dropwizard.Application;
import io.dropwizard.configuration.EnvironmentVariableSubstitutor;
import io.dropwizard.configuration.SubstitutingSourceProvider;
Expand Down Expand Up @@ -51,10 +55,6 @@
import org.kiwiproject.json.JsonHelper;
import org.kiwiproject.net.KiwiInternetAddresses;

import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.FilterRegistration;

public class App extends Application<AppConfig> {

public static void main(String[] args) throws Exception {
Expand Down Expand Up @@ -125,7 +125,7 @@ public void run(AppConfig configuration, Environment environment) {
var cleanOutAuditsJob = new CleanOutAuditsJob(auditRecordDao, configuration.getAuditRecordsMaxRetain().toMilliseconds());
registerJob(environment, "Clean Out Audits", configuration.getAuditCleanup(), cleanOutAuditsJob);

environment.jersey().register(new DeployableSystemRequestFilter(deployableSystemDao));
environment.jersey().register(new DeployableSystemRequestFilter(deployableSystemDao, userDao));
}

private static void setupJsonProcessing(Environment environment) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,16 @@ public interface ComponentDao {
@SqlQuery("select * from components where tag in (<tags>)")
List<Component> findComponentsByHostTags(@BindList("tags") List<String> tags);

@SqlQuery("select * from components where deployable_system_id = :deployableSystemId")
List<Component> findComponentsForSystem(@Bind("deployableSystemId") long deployableSystemId);

@SqlUpdate("insert into components (component_name, tag, deployable_system_id) values (:componentName, :tag, :deployableSystemId)")
@GetGeneratedKeys
long insertComponent(@BindBean Component component);

@SqlUpdate("update components set component_name = :componentName, tag = :tag where id = :id")
int updateComponent(@Bind("componentName") String componentName, @Bind("tag") String tag, @Bind("id") long id);

@SqlUpdate("delete from components where id = :id")
int deleteComponent(@Bind("id") long id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,6 @@ public interface DeployableSystemDao {
@SqlQuery("select system_admin from users_deployable_systems where user_id = :userId and deployable_system_id = :systemId")
boolean isUserAdminOfSystem(@Bind("userId") long userId, @Bind("systemId") long systemId);

@SqlQuery("select true from users_deployable_systems uds join users u on u.id = uds.user_id join deployable_systems ds on ds.id = uds.deployable_system_id where u.system_identifier = :userName and ds.id = :systemId")
Boolean isUserBySystemIdentifierInSystem(@Bind("userName") String systemIdentifier, @Bind("systemId") long systemId);

@SqlQuery("select true from users_deployable_systems where deployable_system_id = :systemId and user_id = :userId")
Boolean isUserInSystem(@Bind("userId") long userId, @Bind("systemId") long systemId);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public interface HostDao {
@GetGeneratedKeys
long insertHost(@BindBean Host host, @Bind("tagCsv") String tagCsv);

@SqlUpdate("update hosts set hostname = :hostname, tags = :tags where id = :id")
int updateHost(@Bind("hostname") String hostname, @Bind("tags") String tagCsv, @Bind("id") long id);

@SqlUpdate("delete from hosts where id = :id")
int deleteHost(@Bind("id") long id);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,28 @@

import java.util.Optional;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.experimental.UtilityClass;

@UtilityClass
public class DeployableSystemThreadLocal {

private static final ThreadLocal<Long> THREAD_LOCAL = new ThreadLocal<>();
@Getter
@AllArgsConstructor
public class DeployableSystemInfo {
Long id;
boolean admin;
}

private static final ThreadLocal<DeployableSystemInfo> THREAD_LOCAL = new ThreadLocal<>();

public static Optional<Long> getCurrentDeployableSystem() {
public static Optional<DeployableSystemInfo> getCurrentDeployableSystem() {
return Optional.ofNullable(THREAD_LOCAL.get());
}

public static void setCurrentDeployableSystem(Long id) {
THREAD_LOCAL.set(id);
public static void setCurrentDeployableSystem(Long id, boolean admin) {
THREAD_LOCAL.set(new DeployableSystemInfo(id, admin));
}

public static void clearDeployableSystem() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,9 @@
import static java.util.Objects.isNull;
import static javax.ws.rs.core.MediaType.APPLICATION_JSON;
import static org.kiwiproject.base.KiwiPreconditions.requireNotNull;
import static org.kiwiproject.champagne.util.DeployableSystems.checkUserAdminOfSystem;
import static org.kiwiproject.champagne.util.DeployableSystems.getSystemIdOrThrowBadRequest;

import com.codahale.metrics.annotation.ExceptionMetered;
import com.codahale.metrics.annotation.Timed;
import org.kiwiproject.champagne.dao.AuditRecordDao;
import org.kiwiproject.champagne.dao.DeploymentEnvironmentDao;
import org.kiwiproject.champagne.model.AuditRecord.Action;
import org.kiwiproject.champagne.model.DeploymentEnvironment;
import org.kiwiproject.champagne.service.ManualTaskService;
import org.kiwiproject.dropwizard.error.dao.ApplicationErrorDao;

import javax.annotation.security.PermitAll;
import javax.validation.Valid;
import javax.ws.rs.Consumes;
Expand All @@ -26,6 +18,15 @@
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

import com.codahale.metrics.annotation.ExceptionMetered;
import com.codahale.metrics.annotation.Timed;
import org.kiwiproject.champagne.dao.AuditRecordDao;
import org.kiwiproject.champagne.dao.DeploymentEnvironmentDao;
import org.kiwiproject.champagne.model.AuditRecord.Action;
import org.kiwiproject.champagne.model.DeploymentEnvironment;
import org.kiwiproject.champagne.service.ManualTaskService;
import org.kiwiproject.dropwizard.error.dao.ApplicationErrorDao;

@Path("/environments")
@Produces(APPLICATION_JSON)
@Consumes(APPLICATION_JSON)
Expand Down Expand Up @@ -56,6 +57,8 @@ public Response listEnvironments() {
@Timed
@ExceptionMetered
public Response createEnvironment(@Valid DeploymentEnvironment deploymentEnvironment) {
checkUserAdminOfSystem();

if (isNull(deploymentEnvironment.getDeployableSystemId())) {
var systemId = getSystemIdOrThrowBadRequest();
deploymentEnvironment = deploymentEnvironment.withDeployableSystemId(systemId);
Expand All @@ -74,6 +77,8 @@ public Response createEnvironment(@Valid DeploymentEnvironment deploymentEnviron
@Timed
@ExceptionMetered
public Response updateEnvironment(@Valid DeploymentEnvironment deploymentEnvironment) {
checkUserAdminOfSystem();

requireNotNull(deploymentEnvironment.getId(), "An id is required to update a deployment environment");

var updatedCount = deploymentEnvironmentDao.updateEnvironment(deploymentEnvironment);
Expand All @@ -90,6 +95,8 @@ public Response updateEnvironment(@Valid DeploymentEnvironment deploymentEnviron
@Timed
@ExceptionMetered
public Response hardDeleteEnvironment(@PathParam("id") Long id) {
checkUserAdminOfSystem();

var deleteCount = deploymentEnvironmentDao.hardDeleteById(id);

if (deleteCount > 0) {
Expand All @@ -104,6 +111,8 @@ public Response hardDeleteEnvironment(@PathParam("id") Long id) {
@Timed
@ExceptionMetered
public Response deactivateEnvironment(@PathParam("id") Long id) {
checkUserAdminOfSystem();

var updatedCount = deploymentEnvironmentDao.softDeleteById(id);

if (updatedCount > 0) {
Expand All @@ -118,6 +127,8 @@ public Response deactivateEnvironment(@PathParam("id") Long id) {
@Timed
@ExceptionMetered
public Response activateEnvironment(@PathParam("id") Long id) {
checkUserAdminOfSystem();

var updatedCount = deploymentEnvironmentDao.unSoftDeleteById(id);

if (updatedCount > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,34 @@

import static java.util.Objects.isNull;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.kiwiproject.champagne.util.DeployableSystems.checkUserAdminOfSystem;
import static org.kiwiproject.champagne.util.DeployableSystems.getSystemIdOrThrowBadRequest;

import com.codahale.metrics.annotation.ExceptionMetered;
import com.codahale.metrics.annotation.Timed;
import org.apache.commons.lang3.StringUtils;
import org.kiwiproject.champagne.dao.AuditRecordDao;
import org.kiwiproject.champagne.dao.ComponentDao;
import org.kiwiproject.champagne.dao.HostDao;
import org.kiwiproject.champagne.model.AuditRecord.Action;
import org.kiwiproject.champagne.model.Component;
import org.kiwiproject.champagne.model.Host;
import org.kiwiproject.dropwizard.error.dao.ApplicationErrorDao;
import org.kiwiproject.jaxrs.exception.JaxrsNotFoundException;

import java.util.List;
import javax.annotation.security.PermitAll;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
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.MediaType;
import javax.ws.rs.core.Response;
import java.util.List;

import com.codahale.metrics.annotation.ExceptionMetered;
import com.codahale.metrics.annotation.Timed;
import org.apache.commons.lang3.StringUtils;
import org.kiwiproject.champagne.dao.AuditRecordDao;
import org.kiwiproject.champagne.dao.ComponentDao;
import org.kiwiproject.champagne.dao.HostDao;
import org.kiwiproject.champagne.model.AuditRecord.Action;
import org.kiwiproject.champagne.model.Component;
import org.kiwiproject.champagne.model.Host;
import org.kiwiproject.dropwizard.error.dao.ApplicationErrorDao;
import org.kiwiproject.jaxrs.exception.JaxrsNotFoundException;

@Path("/host")
@Consumes(MediaType.APPLICATION_JSON)
Expand Down Expand Up @@ -60,6 +62,8 @@ public Response listHostsForEnvironment(@PathParam("environment") Long envId, @Q
@Timed
@ExceptionMetered
public Response createHost(Host host) {
checkUserAdminOfSystem();

if (isNull(host.getDeployableSystemId())) {
var systemId = getSystemIdOrThrowBadRequest();
host = host.withDeployableSystemId(systemId);
Expand All @@ -72,11 +76,29 @@ public Response createHost(Host host) {
return Response.accepted().build();
}

@PUT
@Path("/{id}")
@Timed
@ExceptionMetered
public Response updateHost(Host host, @PathParam("id") Long hostId) {
checkUserAdminOfSystem();

var updateCount = hostDao.updateHost(host.getHostname(), StringUtils.join(host.getTags(), ","), hostId);

if (updateCount > 0) {
auditAction(hostId, Host.class, Action.UPDATED);
}

return Response.accepted().build();
}

@DELETE
@Path("/{id}")
@Timed
@ExceptionMetered
public Response deleteHost(@PathParam("id") Long id) {
checkUserAdminOfSystem();

var deleteCount = hostDao.deleteHost(id);

if (deleteCount > 0) {
Expand All @@ -86,6 +108,17 @@ public Response deleteHost(@PathParam("id") Long id) {
return Response.accepted().build();
}

@GET
@Path("/components")
@Timed
@ExceptionMetered
public Response listComponents() {
var systemId = getSystemIdOrThrowBadRequest();
var components = componentDao.findComponentsForSystem(systemId);

return Response.ok(components).build();
}

@GET
@Path("/{hostId}/components")
@Timed
Expand All @@ -102,6 +135,8 @@ public Response listComponentsForHost(@PathParam("hostId") Long hostId) {
@Timed
@ExceptionMetered
public Response createComponent(Component component) {
checkUserAdminOfSystem();

if (isNull(component.getDeployableSystemId())) {
var systemId = getSystemIdOrThrowBadRequest();
component = component.withDeployableSystemId(systemId);
Expand All @@ -114,11 +149,29 @@ public Response createComponent(Component component) {
return Response.accepted().build();
}

@PUT
@Path("/component/{id}")
@Timed
@ExceptionMetered
public Response updateComponent(Component component, @PathParam("id") Long componentId) {
checkUserAdminOfSystem();

var updateCount = componentDao.updateComponent(component.getComponentName(), component.getTag(), componentId);

if (updateCount > 0) {
auditAction(componentId, Component.class, Action.UPDATED);
}

return Response.accepted().build();
}

@DELETE
@Path("/component/{componentId}")
@Timed
@ExceptionMetered
public Response deleteComponent(@PathParam("componentId") Long componentId) {
checkUserAdminOfSystem();

var deleteCount = componentDao.deleteComponent(componentId);

if (deleteCount > 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
package org.kiwiproject.champagne.resource.filter;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;

import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.kiwiproject.champagne.dao.DeployableSystemDao;
import org.kiwiproject.champagne.dao.UserDao;
import org.kiwiproject.champagne.model.DeployableSystemThreadLocal;

import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import org.kiwiproject.jaxrs.exception.JaxrsBadRequestException;

public class DeployableSystemRequestFilter implements ContainerRequestFilter {

private static final String DEPLOYABLE_SYSTEM_HEADER_NAME = "Champagne-Deployable-System";

private final DeployableSystemDao deployableSystemDao;
private final UserDao userDao;

public DeployableSystemRequestFilter(DeployableSystemDao deployableSystemDao) {
public DeployableSystemRequestFilter(DeployableSystemDao deployableSystemDao, UserDao userDao) {
this.deployableSystemDao = deployableSystemDao;
this.userDao = userDao;
}

@Override
Expand All @@ -24,9 +28,12 @@ public void filter(ContainerRequestContext requestContext) {

if (StringUtils.isNotBlank(system)) {
var userName = requestContext.getSecurityContext().getUserPrincipal().getName();
var user = userDao.findBySystemIdentifier(userName).orElseThrow(() -> new JaxrsBadRequestException("No user context"));
var systemId = Long.parseLong(system);

if (BooleanUtils.isTrue(deployableSystemDao.isUserBySystemIdentifierInSystem(userName, Long.parseLong(system)))) {
DeployableSystemThreadLocal.setCurrentDeployableSystem(Long.valueOf(system));
if (BooleanUtils.isTrue(deployableSystemDao.isUserInSystem(user.getId(), systemId))) {
var isAdminOfSystem = deployableSystemDao.isUserAdminOfSystem(user.getId(), systemId);
DeployableSystemThreadLocal.setCurrentDeployableSystem(systemId, isAdminOfSystem);
}
}
}
Expand Down
Loading

0 comments on commit 5103998

Please sign in to comment.