summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg Pfuetzenreuter2022-05-07 18:37:24 +0200
committerGeorg Pfuetzenreuter2022-05-07 18:37:24 +0200
commitbc6efc5c5103d61c9d13313e41e2344e8baf4b7e (patch)
treec38a4f846cbf220cd321be32a988c388b3bae785
parente37ec4083a8fff705185956bb8fa3b29f3c05ff8 (diff)
downloadpubsh-web-bc6efc5c5103d61c9d13313e41e2344e8baf4b7e.tar.gz
pubsh-web-bc6efc5c5103d61c9d13313e41e2344e8baf4b7e.tar.bz2
pubsh-web-bc6efc5c5103d61c9d13313e41e2344e8baf4b7e.zip
Checkpoint: Image deletion interface
Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
-rw-r--r--src/main/java/net/libertacasa/pubsh/web/Docker.java47
-rw-r--r--src/main/java/net/libertacasa/pubsh/web/SecurityConfig.java1
-rw-r--r--src/main/java/net/libertacasa/pubsh/web/WebApplication.java52
-rw-r--r--src/main/resources/templates/portal.html23
4 files changed, 106 insertions, 17 deletions
diff --git a/src/main/java/net/libertacasa/pubsh/web/Docker.java b/src/main/java/net/libertacasa/pubsh/web/Docker.java
index 1460bb3..6912d1b 100644
--- a/src/main/java/net/libertacasa/pubsh/web/Docker.java
+++ b/src/main/java/net/libertacasa/pubsh/web/Docker.java
@@ -1,17 +1,25 @@
package net.libertacasa.pubsh.web;
import java.io.File;
+import java.nio.file.Path;
import java.time.Duration;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
+
+import org.springframework.core.io.ClassPathResource;
+
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.BuildImageResultCallback;
+import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InspectExecResponse.Container;
import com.github.dockerjava.api.command.ListContainersCmd;
+import com.github.dockerjava.api.command.ListImagesCmd;
+import com.github.dockerjava.api.command.WaitContainerResultCallback;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientConfig;
@@ -82,8 +90,11 @@ public class Docker {
}
public static String buildImage(String targetUser, String osChoice, Integer count) {
- String dockerfile = "classpath:docker/Dockerfile-" + osChoice;
- String tag = targetUser + ":sh" + count;
+ String dockerfile = "/home/georg/tmp/docker/Dockerfile_" + osChoice;
+ String tag = targetUser + ":sh" + count;
+ if (! new File(dockerfile).exists()) {
+ System.out.printf("\nInvalid Dockerfile: %s\n", dockerfile);
+ }
Set<String> tags = new HashSet<String>();
tags.add(tag);
String imgid = dockerClient.buildImageCmd()
@@ -91,7 +102,39 @@ public class Docker {
.withPull(false).withNoCache(false).withTags(tags)
.exec(new BuildImageResultCallback()).awaitImageId();
+ System.out.printf("\nBuilt image with ID %s", imgid);
return(imgid);
}
+
+ public static void deleteImage(String username, String id) {
+ List<Image> imagequery = Docker.getImages();
+
+ if (imagequery.toString().contains(id)) {
+ System.out.printf("\nFound image ID %s, deleting ...", id);
+ dockerClient.removeImageCmd(id).withImageId(id).exec();
+ }
+ if (! imagequery.toString().contains(id)) {
+ System.out.printf("\nImage ID %s not found.", id);
+ }
+
+ }
+
+ public static String createContainer(String imgid) {
+ //String containerid = dockerClient.createContainerCmd(imgid).exec();
+ WaitContainerResultCallback resultCallback = new WaitContainerResultCallback();
+ CreateContainerResponse createContainerResponse = dockerClient.createContainerCmd(imgid).exec();
+ dockerClient.waitContainerCmd(createContainerResponse.getId()).exec(resultCallback);
+ try {
+ resultCallback.awaitCompletion();
+ } catch (InterruptedException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ String containerid = createContainerResponse.getId();
+ //System.out.println(dockerClient.infoCmd().exec());
+
+ System.out.printf("\nCreated container with ID %s from image ID %s", containerid, imgid);
+ return(containerid);
+ }
}
diff --git a/src/main/java/net/libertacasa/pubsh/web/SecurityConfig.java b/src/main/java/net/libertacasa/pubsh/web/SecurityConfig.java
index 630acf4..53f83ab 100644
--- a/src/main/java/net/libertacasa/pubsh/web/SecurityConfig.java
+++ b/src/main/java/net/libertacasa/pubsh/web/SecurityConfig.java
@@ -32,7 +32,6 @@ public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception
{
- http.csrf().disable();
super.configure(http); //.anonymous().disable()
http
.authorizeRequests()
diff --git a/src/main/java/net/libertacasa/pubsh/web/WebApplication.java b/src/main/java/net/libertacasa/pubsh/web/WebApplication.java
index e7b3cd2..bfdeb59 100644
--- a/src/main/java/net/libertacasa/pubsh/web/WebApplication.java
+++ b/src/main/java/net/libertacasa/pubsh/web/WebApplication.java
@@ -21,6 +21,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.MultiValueMap;
+import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.DeleteMapping;
//import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
@@ -36,7 +37,6 @@ import com.github.dockerjava.api.model.Container;
import com.github.dockerjava.api.model.Image;
import java.util.Random;
-//@SessionAttributes("osChoice")
@SpringBootApplication
@Controller
public class WebApplication {
@@ -87,7 +87,7 @@ public class WebApplication {
//System.out.println(images);
List<Container> containers = Docker.getContainers();
//System.out.println(containers);
-
+
model.addAttribute("docker_images", images);
model.addAttribute("docker_containers", containers);
@@ -113,30 +113,66 @@ public class WebApplication {
username = String.valueOf(customClaims.get("username"));
// [End]
- System.out.printf("Deletion triggered for ID %s by %s (%s)", id, userid, username);
+ System.out.printf("\nDeletion triggered for ID %s by %s (%s)", id, userid, username);
Docker.deleteContainer(id);
return("redirect:/portal");
}
- @PostMapping(path="/frontend/container/add",consumes=MediaType.APPLICATION_FORM_URLENCODED_VALUE)
- public static String addContainer(@RequestBody MultiValueMap<String, String> body, HttpServletRequest request) {
+ @DeleteMapping("/frontend/image/delete/{id}")
+ public static String deleteImage(@PathVariable String id, HttpServletRequest request, RedirectAttributes redirectAttributes) {
+ // [Start] This block should move to a logging method. It's only job is to print user details to the console.
KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request.getUserPrincipal();
String username= null;
String userid = principal.getName();
IDToken token = principal.getAccount().getKeycloakSecurityContext().getIdToken();
Map<String, Object> customClaims = token.getOtherClaims();
username = String.valueOf(customClaims.get("username"));
- String osChoice = (String) body.getFirst("osChoice");
+ // [End]
+
+ System.out.printf("\nImage deletion triggered for ID %s by %s (%s)", id, userid, username);
+
+ try {
+ Docker.deleteImage(username, id);
+ String returnmessage = "Success - removed image with ID " + id + "!";
+ redirectAttributes.addFlashAttribute("message", returnmessage);
+ } catch (com.github.dockerjava.api.exception.ConflictException exception) {
+ String returnmessage = "Error - Image is still being used by a container.";
+ redirectAttributes.addFlashAttribute("message", returnmessage);
+ }
+
+ return("redirect:/portal");
+ }
+
+ @PostMapping(path="/frontend/container/add",consumes=MediaType.APPLICATION_FORM_URLENCODED_VALUE)
+ public static String addContainer(@RequestBody MultiValueMap<String, String> body, HttpServletRequest request, RedirectAttributes redirectAttributes) {
+ KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request.getUserPrincipal();
+ String username = null;
+ String userid = principal.getName();
+ IDToken token = principal.getAccount().getKeycloakSecurityContext().getIdToken();
+ Map<String, Object> customClaims = token.getOtherClaims();
+ username = String.valueOf(customClaims.get("username"));
+ String os = (String) body.getFirst("osChoice");
- System.out.printf("New container with OS %s requested by %s (%s)", osChoice, userid, username);
+ System.out.printf("\nNew container with OS %s requested by %s (%s)\n", os, userid, username);
Random rand = new Random();
Integer randomInt = rand.nextInt(9999999-1111);
Integer count = randomInt;
- //Docker.buildImage(username, osChoice, count);
+ try {
+ String imageid = Docker.buildImage(username, os, count);
+ String returnmessage = "Success - built image with ID " + imageid + " and tag sh" + count + "!";
+ redirectAttributes.addFlashAttribute("message", returnmessage);
+ } catch (Exception exception) {
+ redirectAttributes.addFlashAttribute("message", "Success!");
+ String returnmessage = "Error - failed to build image :-(";
+ redirectAttributes.addFlashAttribute("message", returnmessage);
+ System.out.println(exception);
+ }
+
+ //Docker.createContainer(imageid);
return("redirect:/portal");
}
diff --git a/src/main/resources/templates/portal.html b/src/main/resources/templates/portal.html
index 836c42e..d2f1847 100644
--- a/src/main/resources/templates/portal.html
+++ b/src/main/resources/templates/portal.html
@@ -4,20 +4,32 @@
</head>
<body>
<div id="container">
+ <div th:if="${message}" th:text="${message}" th:class="${'alert ' + alertClass}"/></div>
<h1>
Hello, <span th:text="${username}"></span>.
</h1>
<div th:if="${attribute01 != null}" th:text="${attribute01}"></div>
- <h2>Available Docker Images:</h2>
+ <h2>Available images:</h2>
<table>
<tr th:each="image: ${docker_images}" th:if="${image.repoTags[0] != '<none>:<none>'}">
- <td th:text="${image.repoTags[0]}" />
- <td th:text="${image.created}" />
+ <td>
+ <table>
+ <tr th:each="tag: ${image.repoTags}">
+ <td th:text="${tag}"/>
+ <td>
+ <form id="deletion_pseudoform" action="#" th:action="@{'/frontend/image/delete/{id}'(id=${tag})}" th:method="delete" th:tag="${tag}" th:onsubmit="return confirm('Do you really want to delete the imag with tag ' + this.getAttribute('tag') + '?');">
+ <button class="btn btn-danger" id="deletion_submission" type="submit">x</button>
+ </form>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td th:text="${image.created}" />
</tr>
</table>
<h2>Generate new throw-away shell:</h2>
- <form th:object="${osChoice}" th:id="request_pseudoform" action="#" th:action="@{'/frontend/container/add'}" th:method="post" th:os="${osoption}" th:onsubmit="return confirm('You are about to generate a shell with the OS ' + this.getAttribute('os') + ' - please be patient after you confirm, as the generation may take a short while.');">
+ <form th:object="${osChoice}" th:id="request_pseudoform" action="#" th:action="@{'/frontend/container/add'}" th:method="post" th:os="${osChoice}" th:onsubmit="return confirm('You are about to generate a shell with the OS ' + this.getAttribute('osoption') + ' - please be patient after you confirm, as the generation may take a short while.');">
<select class="form-control" th:object="${osChoice}" name="osChoice">
<option value="">Select operating system ...</option>
<option
@@ -26,14 +38,13 @@
th:attr="value=${osoption}"
th:text="${osoption}"></option>
</select>
- <p><span th:text="${osChoice}"></span></p>
<button class="btn btn-primary" th:id="request_submission" th:type="submit">Generate</button>
</form>
- <h2>Existing Containers:</h2>
+ <h2>Existing containers:</h2>
<table>
<tr th:each="container: ${docker_containers}">
<td th:text="${container.names[0]}" />