registration and unregister work

This commit is contained in:
Antoine 2020-09-16 01:04:29 +02:00
parent 6e7a6055b4
commit 2ec8fb5411
Signed by: antoine
GPG Key ID: 098FB66FC0475E70
15 changed files with 318 additions and 50 deletions

View File

@ -5,6 +5,99 @@ command used to register new runner
```shell script
$ docker run -d --name gitlab-runner --restart always -v /var/run/docker.sock:/var/run/docker.sock -v gitlab-runner-config:/etc/gitlab-runner gitlab/gitlab-runner:latest
$ gitlab-runner register -non-interactive --description "manualy registered gitlab runner" --url "http://172.17.0.1
:8080/" --registration-token "registration_token" --tag-list "docker,manual"
$ gitlab-runner register -non-interactive --description "manualy registered gitlab runner" --url "http://172.17.0.1:8080/" --registration-token "3b79eb1f-32f3-4db2-ad1b-6
702e476d839" --tag-list "docker,manual" --executor shell
```
same with curl
```shell script
$ curl --request POST -H 'Content-Type: application/json' "http://localhost:8080/api/v4/runners" -d '{"description":"manualy registered gitlab runner","tag_list":"docker,manual","run_untagged":false,"locked":true,"active":true,"info":{"name":"gitlab-runner","version":"13.3.1","revision":"738bbe5a","platform":"linux","architecture":"amd64","features":{"variables":false,"image":false,"services":false,"artifacts":false,"cache":false,"shared":false,"upload_multiple_artifacts":false,"upload_raw_artifacts":false,"session":false,"terminal":false,"refspecs":false,"masking":false,"proxy":false,"raw_variables":false,"artifacts_exclude":false,"multi_build_steps":false}},"token":"registration_token"}'
```
---
```json
{
"description":"manualy registered gitlab runner",
"tag_list":"docker,manual",
"run_untagged":false,
"locked":true,
"active":true,
"info":{
"name":"gitlab-runner",
"version":"13.3.1",
"revision":"738bbe5a",
"platform":"linux",
"architecture":"amd64",
"features":{
"variables":false,
"image":false,
"services":false,
"artifacts":false,
"cache":false,
"shared":false,
"upload_multiple_artifacts":false,
"upload_raw_artifacts":false,
"session":false,
"terminal":false,
"refspecs":false,
"masking":false,
"proxy":false,
"raw_variables":false,
"artifacts_exclude":false,
"multi_build_steps":false
}
},
"token":"registration_token"
}
```
## http call use when job is run
```
[POST /api/v4/jobs/request HTTP/1.1
Host: 172.17.0.1:8080
User-Agent: gitlab-runner 13.3.1 (13-3-stable; go1.13.8; linux/amd64)
Content-Length: 510
Accept: application/json
Content-Type: application/json
Accept-Encoding: gzip
```
```json
{
"info":{
"name":"gitlab-runner",
"version":"13.3.1",
"revision":"738bbe5a",
"platform":"linux",
"architecture":"amd64",
"executor":"shell",
"shell":"bash",
"features":{
"variables":true,
"image":false,
"services":false,
"artifacts":true,
"cache":true,
"shared":true,
"upload_multiple_artifacts":true,
"upload_raw_artifacts":true,
"session":true,
"terminal":true,
"refspecs":true,
"masking":true,
"proxy":false,
"raw_variables":true,
"artifacts_exclude":true,
"multi_build_steps":true
}
},
"token":"76a79b73-b211-48c6-a3da-6b99fb8b0612"
}
```
...

View File

@ -9,6 +9,7 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0-M2</version>
<!-- <version>2.3.2.RELEASE</version>-->
<relativePath/> <!-- lookup parent from repository -->
</parent>

View File

@ -1,42 +1,39 @@
package tk.antoine_roux.wiki;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import tk.antoine_roux.wiki.annotation.ApiPrefix;
import tk.antoine_roux.wiki.annotation.ApiVersion;
import tk.antoine_roux.wiki.configuration.Exception.DeleteRunnerException;
import tk.antoine_roux.wiki.model.Runner;
import tk.antoine_roux.wiki.model.request.AddRunner;
import tk.antoine_roux.wiki.model.request.DeleteRunner;
import tk.antoine_roux.wiki.model.response.RegisterResponse;
import tk.antoine_roux.wiki.utilitary.Boolean;
import java.lang.invoke.MethodHandles;
import java.util.Map;
import java.util.TreeMap;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static tk.antoine_roux.wiki.Constant.*;
@RestController
@ApiPrefix(API_PREFIX)
public class ControllerHandlers {
private RunnerRegistrar runnerRegistrar;
private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
private final RunnerRegistrar runnerRegistrar;
@Autowired
public ControllerHandlers(RunnerRegistrar runnerRegistrar) {
this.runnerRegistrar = runnerRegistrar;
}
/**
* add register new runners
*
* @param body
* @return
*/
@ResponseBody
@ApiVersion({API_VERSION})
@PostMapping(value = "/runners", produces = APPLICATION_JSON_VALUE)
public static ResponseEntity<String> addRunner(@RequestBody String body) {
System.out.println(body);
return ResponseEntity.ok(body);
}
/**
* hello test endpoint
*
@ -44,7 +41,7 @@ public class ControllerHandlers {
*/
@ResponseBody
@GetMapping("/info")
public static ResponseEntity<TreeMap<String, String>> info() {
public ResponseEntity<TreeMap<String, String>> info() {
return ResponseEntity.ok(
// sort attribute by key name
new TreeMap<>(
@ -55,4 +52,32 @@ public class ControllerHandlers {
)
);
}
/**
* add register new runners
*
* @param body
* @return
*/
@ResponseBody
@ApiVersion({API_VERSION})
@PostMapping("/runners")
public ResponseEntity<RegisterResponse> addRunner(@RequestBody AddRunner body) {
logger.debug("Receive register runner request " + body);
Runner createdRunner = this.runnerRegistrar.addRunner(body);
RegisterResponse response = createdRunner.toRegisterResponse();
logger.debug("Response register runner " + response);
return ResponseEntity.status(HttpStatus.CREATED).body(response);
}
@ApiVersion(API_VERSION)
@DeleteMapping("/runners")
public ResponseEntity<Void> deleteRunner(@RequestBody DeleteRunner body) throws Exception {
logger.debug("Receive delete runner request " + body);
Boolean.trueOrElseThrow(this.runnerRegistrar.removeRunnerByRegistrationToken(body), DeleteRunnerException::new);
logger.debug("Successfully delete runner ");
return ResponseEntity.noContent().build();
}
}

View File

@ -1,9 +1,14 @@
package tk.antoine_roux.wiki;
import org.springframework.stereotype.Service;
import tk.antoine_roux.wiki.model.Runner;
import tk.antoine_roux.wiki.model.request.AddRunner;
import tk.antoine_roux.wiki.model.request.DeleteRunner;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Class use to perist registered gitlab runner
@ -12,30 +17,24 @@ import java.util.List;
public class RunnerRegistrar {
private final List<Runner> runners = new ArrayList<>();
AtomicInteger idIncrementer = new AtomicInteger();
public List<Runner> getRunners() {
return this.runners;
}
public void addRunner(Runner r) {
public Runner addRunner(AddRunner addRunner) {
Runner r = new Runner();
r.id = this.idIncrementer.getAndIncrement();
r.authenticationToken = UUID.randomUUID();
r.registrationToken = addRunner.token;
r.tags = addRunner.tags;
r.description = addRunner.description;
this.runners.add(r);
return r;
}
/**
* in memory representation of gitlab runner
*/
public static class Runner {
private static final String TAG_SEPARATOR = ",";
public String id;
public String description;
public String[] tags;
public String registrationToken;
public Runner(String id, String description, String tags, String registrationToken) {
this.id = id;
this.description = description;
this.tags = tags.split(TAG_SEPARATOR);
this.registrationToken = registrationToken;
}
public boolean removeRunnerByRegistrationToken(DeleteRunner r) {
return this.runners.removeIf(runner -> runner.authenticationToken.equals(r.token));
}
}

View File

@ -52,8 +52,8 @@ public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandle
RequestMappingInfo requestMappingInfo = new RequestMappingInfo(
new PatternsRequestCondition(
new String[]{annotationApiPrefix.value()},
false,
this.getPathMatcher()
this.getUrlPathHelper(), this.getPathMatcher(),
false
),
new RequestMethodsRequestCondition(),
new ParamsRequestCondition(),
@ -76,7 +76,11 @@ public class ApiVersionRequestMappingHandlerMapping extends RequestMappingHandle
}
return new RequestMappingInfo(
new PatternsRequestCondition(patterns, false, this.getPathMatcher()),
new PatternsRequestCondition(
patterns, this.getUrlPathHelper(), this.getPathMatcher(),
false
// , this.useTrailingSlashMatch(), this.getFileExtensions()
),
new RequestMethodsRequestCondition(),
new ParamsRequestCondition(),
new HeadersRequestCondition(),

View File

@ -0,0 +1,39 @@
package tk.antoine_roux.wiki.configuration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import tk.antoine_roux.wiki.configuration.Exception.DeleteRunnerException;
import tk.antoine_roux.wiki.configuration.Exception.NoIdException;
import java.time.LocalDateTime;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Custom http handler for dealing with {@link Exception}
*/
@ControllerAdvice
public class ControllerExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({NoIdException.class})
public ResponseEntity<Object> handleInternalException(NoIdException ex, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", ex.getMessage());
return new ResponseEntity<>(body, HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler({DeleteRunnerException.class})
public ResponseEntity<Object> handleNotFoundException(NoIdException ex, WebRequest request) {
Map<String, Object> body = new LinkedHashMap<>();
body.put("timestamp", LocalDateTime.now());
body.put("message", ex.getMessage());
return new ResponseEntity<>(body, HttpStatus.NOT_FOUND);
}
}

View File

@ -0,0 +1,9 @@
package tk.antoine_roux.wiki.configuration.Exception;
public class DeleteRunnerException extends RuntimeException {
private static final long serialVersionUID = 559919382888691526L;
public DeleteRunnerException() {
super("Fail to delete runner");
}
}

View File

@ -0,0 +1,9 @@
package tk.antoine_roux.wiki.configuration.Exception;
public class NoIdException extends RuntimeException {
private static final long serialVersionUID = 1470945508482780554L;
public NoIdException() {
super("Invalid id value");
}
}

View File

@ -1,25 +1,20 @@
package tk.antoine_roux.wiki.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.resource.ResourceUrlProvider;
import tk.antoine_roux.wiki.Constant;
/**
* spring web configuration
*
* @see org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations
*/
@Configuration(proxyBeanMethods = false)
public class WebConfiguration extends WebMvcConfigurationSupport {
public class WebConfiguration implements WebMvcRegistrations {
@Bean
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(ContentNegotiationManager contentNegotiationManager,
FormattingConversionService conversionService,
ResourceUrlProvider resourceUrlProvider) {
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new ApiVersionRequestMappingHandlerMapping(Constant.VERSION_PREFIX);
}
}

View File

@ -0,0 +1,21 @@
package tk.antoine_roux.wiki.model;
import tk.antoine_roux.wiki.model.response.RegisterResponse;
import java.util.List;
import java.util.UUID;
/**
* in memory representation of gitlab runner
*/
public class Runner {
public String description;
public List<String> tags;
public UUID registrationToken;
public UUID authenticationToken;
public Integer id;
public RegisterResponse toRegisterResponse() {
return new RegisterResponse(String.valueOf(this.id), this.authenticationToken.toString());
}
}

View File

@ -0,0 +1,23 @@
package tk.antoine_roux.wiki.model.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
/**
* Model use to add runner instance
*/
public class AddRunner {
private static final String TAG_SEPARATOR = ",";
public String description;
public List<String> tags;
public UUID token;
@JsonProperty("tag_list")
public void setTags(String tags) {
this.tags = Arrays.asList(tags.split(TAG_SEPARATOR).clone());
}
}

View File

@ -0,0 +1,10 @@
package tk.antoine_roux.wiki.model.request;
import java.util.UUID;
/**
* Model use to remove runner instance
*/
public class DeleteRunner {
public UUID token;
}

View File

@ -0,0 +1,18 @@
package tk.antoine_roux.wiki.model.response;
import com.fasterxml.jackson.annotation.JsonProperty;
/**
* Json response object for register endpoint
*/
public class RegisterResponse {
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
String id;
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
String token;
public RegisterResponse(String id, String token) {
this.id = id;
this.token = token;
}
}

View File

@ -0,0 +1,19 @@
package tk.antoine_roux.wiki.utilitary;
import java.util.function.Supplier;
public final class Boolean {
/**
* utility method throw ex if in is false, else follow in value
*
* @param in
* @param ex
* @throws Exception exception thrown when in param is false
*/
public static <T extends Exception> void trueOrElseThrow(boolean in, Supplier<T> ex) throws Exception {
if (!in) {
throw ex.get();
}
}
}

View File

@ -8,6 +8,9 @@ server.port=^application.port^
logging.level.root=INFO
# this log print request content
logging.level.org.apache.coyote.http11.Http11InputBuffer=DEBUG
# spring boot actuator
management.server.port=8080
info.name=gitlab-runner-gateway