Skip to content

Commit

Permalink
Merge pull request #129 from CodeKaio/72-mandatory-variables
Browse files Browse the repository at this point in the history
🚸 : mandatory variables
  • Loading branch information
cdubuisson committed Aug 30, 2019
2 parents c9dc432 + c30568e commit 408efe8
Show file tree
Hide file tree
Showing 23 changed files with 886 additions and 172 deletions.
23 changes: 23 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,31 @@
<groupId>io.codeka</groupId>
<artifactId>gaia</artifactId>
<version>1.2.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>gaia</name>
<description>gaia runs yours terraform modules</description>
<url>https://github.com/CodeKaio/gaia</url>
<inceptionYear>2019</inceptionYear>

<licenses>
<license>
<name>Mozilla Public License Version 2.0</name>
<url>http://mozilla.org/MPL/2.0/</url>
</license>
</licenses>

<scm>
<url>https://github.com/CodeKaio/gaia</url>
</scm>
<issueManagement>
<system>github</system>
<url>https://github.com/CodeKaio/gaia/issues</url>
</issueManagement>
<ciManagement>
<system>travis-ci</system>
<url>https://travis-ci.org/CodeKaio/gaia</url>
</ciManagement>

<properties>
<java.version>11</java.version>
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/io/codeka/gaia/modules/bo/TerraformModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import io.codeka.gaia.teams.bo.User;
import org.springframework.data.mongodb.core.mapping.DBRef;

import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
Expand All @@ -12,18 +14,22 @@ public class TerraformModule {

private String id;

@NotBlank
private String gitRepositoryUrl;

private String gitBranch;

private String directory;

@Valid
private List<TerraformVariable> variables = new ArrayList<>();

@NotBlank
private String name;

private String description;

@NotBlank
private String cliVersion;

@DBRef
Expand Down
23 changes: 23 additions & 0 deletions src/main/java/io/codeka/gaia/modules/bo/TerraformVariable.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package io.codeka.gaia.modules.bo;

import javax.validation.constraints.NotBlank;

/**
* Represents a module variable
*/
public class TerraformVariable {

@NotBlank
private String name;

private String description;
Expand All @@ -13,6 +16,10 @@ public class TerraformVariable {

private boolean editable;

private boolean mandatory;

private String validationRegex;

public String getName() {
return name;
}
Expand Down Expand Up @@ -44,4 +51,20 @@ public boolean isEditable() {
public void setEditable(boolean editable) {
this.editable = editable;
}

public boolean isMandatory() {
return mandatory;
}

public void setMandatory(boolean mandatory) {
this.mandatory = mandatory;
}

public String getValidationRegex() {
return validationRegex;
}

public void setValidationRegex(String validationRegex) {
this.validationRegex = validationRegex;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.List;

/**
Expand All @@ -23,7 +24,7 @@ public ModuleRestController(TerraformModuleRepository moduleRepository) {
this.moduleRepository = moduleRepository;
}

@GetMapping("")
@GetMapping
public List<TerraformModule> findAllModules(User user){
if(user.isAdmin()){
return moduleRepository.findAll();
Expand All @@ -41,7 +42,7 @@ public TerraformModule findModule(@PathVariable String id, User user){

@Secured("ROLE_ADMIN")
@PutMapping("/{id}")
public TerraformModule saveModule(@PathVariable String id, @RequestBody TerraformModule module){
public TerraformModule saveModule(@PathVariable String id, @RequestBody @Valid TerraformModule module){
return moduleRepository.save(module);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.codeka.gaia.stacks.bo;

import io.codeka.gaia.stacks.service.MandatoryStackVariablesValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = MandatoryStackVariablesValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MandatoryStackVariablesValidation {

String message() default "mandatory variables should not be blank";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.codeka.gaia.stacks.bo;

import io.codeka.gaia.stacks.service.RegexStackVariablesValidator;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Constraint(validatedBy = RegexStackVariablesValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface RegexStackVariablesValidation {

String message() default "variables should match the regex";

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};
}
5 changes: 5 additions & 0 deletions src/main/java/io/codeka/gaia/stacks/bo/Stack.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import io.codeka.gaia.teams.bo.User;
import org.springframework.data.mongodb.core.mapping.DBRef;

import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
Expand All @@ -15,6 +16,8 @@
* It references the module it is based on, with all the values of its variables.
* It also has a backend configuration, and a provider configuration (in terraform terms).
*/
@MandatoryStackVariablesValidation
@RegexStackVariablesValidation
public class Stack {

/**
Expand All @@ -25,6 +28,7 @@ public class Stack {
/**
* The id of the referenced module
*/
@NotBlank
private String moduleId;

/**
Expand All @@ -35,6 +39,7 @@ public class Stack {
/**
* The name of the stack
*/
@NotBlank
private String name;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -48,8 +49,8 @@ public Stack getStack(@PathVariable String id, User user){
return stack;
}

@PostMapping()
public Stack save(@RequestBody Stack stack, Team userTeam, User user){
@PostMapping
public Stack save(@RequestBody @Valid Stack stack, Team userTeam, User user){
stack.setOwnerTeam(userTeam);
stack.setId(UUID.randomUUID().toString());
stack.setCreatedBy(user);
Expand All @@ -58,7 +59,7 @@ public Stack save(@RequestBody Stack stack, Team userTeam, User user){
}

@PutMapping("/{id}")
public Stack update(@PathVariable String id, @RequestBody Stack stack, User user){
public Stack update(@PathVariable String id, @RequestBody @Valid Stack stack, User user){
stack.setUpdatedBy(user);
stack.setUpdatedAt(LocalDateTime.now());
return stackRepository.save(stack);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package io.codeka.gaia.stacks.controller;

import org.springframework.http.HttpStatus;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import java.util.Map;
import java.util.stream.Collectors;

@ControllerAdvice
public class StackValidationExceptionHandler {

@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
var message = ex.getBindingResult().getAllErrors().stream()
.map(this::getMessage)
.collect(Collectors.joining("\n"));

return Map.of("message", message);
}

private String getMessage(ObjectError error){
if(error instanceof FieldError){
var fieldError = ((FieldError)error);
return fieldError.getField() + " " + fieldError.getDefaultMessage();
}
return error.getDefaultMessage();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package io.codeka.gaia.stacks.service;

import io.codeka.gaia.modules.bo.TerraformVariable;
import io.codeka.gaia.modules.repository.TerraformModuleRepository;
import io.codeka.gaia.stacks.bo.Stack;
import io.codeka.gaia.stacks.bo.MandatoryStackVariablesValidation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

@Service
public class MandatoryStackVariablesValidator implements ConstraintValidator<MandatoryStackVariablesValidation, Stack> {

@Autowired
private TerraformModuleRepository moduleRepository;

@Override
public void initialize(MandatoryStackVariablesValidation constraintAnnotation) {
// nothing to do here
}

@Override
public boolean isValid(Stack stack, ConstraintValidatorContext constraintValidatorContext) {
if(stack.getModuleId() == null || stack.getModuleId().isBlank()){
// no module defined, so variables are valid !
return true;
}
// getting the module
var module = this.moduleRepository.findById(stack.getModuleId()).orElseThrow();

return module.getVariables().stream()
.filter(TerraformVariable::isMandatory)
.allMatch(variable -> {
var variableValue = stack.getVariableValues().get(variable.getName());
return variableValue != null && !variableValue.isBlank();
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package io.codeka.gaia.stacks.service;

import io.codeka.gaia.modules.repository.TerraformModuleRepository;
import io.codeka.gaia.stacks.bo.RegexStackVariablesValidation;
import io.codeka.gaia.stacks.bo.Stack;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;

@Service
public class RegexStackVariablesValidator implements ConstraintValidator<RegexStackVariablesValidation, Stack> {

@Autowired
private TerraformModuleRepository moduleRepository;

@Override
public void initialize(RegexStackVariablesValidation constraintAnnotation) {
// nothing to do here
}

@Override
public boolean isValid(Stack stack, ConstraintValidatorContext constraintValidatorContext) {
if(stack.getModuleId() == null || stack.getModuleId().isBlank()){
// no module defined, so variables are valid !
return true;
}
// getting the module
var module = this.moduleRepository.findById(stack.getModuleId()).orElseThrow();

return module.getVariables().stream()
// not checking non regex values
.filter(terraformVariable -> terraformVariable.getValidationRegex() != null)
// not checking blank values (doing it first because Pair want non-null values)
.filter(terraformVariable -> {
var value = stack.getVariableValues().get(terraformVariable.getName());
return value != null && ! value.isBlank();
})
// associating each variable with its value
.map(terraformVariable -> Pair.of(terraformVariable, stack.getVariableValues().get(terraformVariable.getName())))
.allMatch(pair -> {
var pattern = Pattern.compile(pair.getFirst().getValidationRegex());
return pattern.matcher(pair.getSecond()).matches();
});
}
}
4 changes: 2 additions & 2 deletions src/main/resources/static/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,8 @@ a.btn {
color: #000;
}

button i {
color: #fff;
#sidebarCollapse i {
color: #FFF;
}

.lead {
Expand Down
4 changes: 2 additions & 2 deletions src/main/resources/templates/layout/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ <h4>Menu</h4>
</div>
</div>
<div class="sidebar-footer">
<span><i class="fas fa-tag"></i> <span th:text="${info.build.version}"></span></span>
<span th:if="${info[build] != null}"><i class="fas fa-tag"></i> <span th:text="${info.build.version}"></span></span>

<span><i class="fab fa-github"></i> <span th:text="${info.git.commit.id}"></span></span>
<span th:if="${info[git] != null}"><i class="fab fa-github"></i> <span th:text="${info.git.commit.id}"></span></span>
</div>
</nav>
<!-- end sidebar -->
Expand Down

0 comments on commit 408efe8

Please sign in to comment.