Merge "Python based rapp manager"
diff --git a/rapp-manager/src/main/java/org/oransc/rappmanager/controller/AppController.java b/rapp-manager/src/main/java/org/oransc/rappmanager/controller/AppController.java
index ca1994b..04f0f05 100644
--- a/rapp-manager/src/main/java/org/oransc/rappmanager/controller/AppController.java
+++ b/rapp-manager/src/main/java/org/oransc/rappmanager/controller/AppController.java
@@ -56,13 +56,12 @@
@Autowired
private AppService appService;
- @Autowired
private static Gson gson = new GsonBuilder().create();
@GetMapping(path = "/apps", produces = MediaType.APPLICATION_JSON_VALUE)
@ApiOperation(value = "Return all Apps")
@ApiResponses(value = {@ApiResponse(code = 200, message = "rApp List")})
- public ResponseEntity<AppList> getAllApps() throws ServiceException {
+ public ResponseEntity<AppList> getAllApps() {
Collection<AppInfo> apps = new ArrayList<>();
appService.getAllApps().forEach(app -> apps.add(toAppInfo(app)));
AppList list = AppList.builder().apps(apps).build();
diff --git a/rapp-manager/src/main/java/org/oransc/rappmanager/helm/HelmClient.java b/rapp-manager/src/main/java/org/oransc/rappmanager/helm/HelmClient.java
index 05a8e00..bfdb439 100644
--- a/rapp-manager/src/main/java/org/oransc/rappmanager/helm/HelmClient.java
+++ b/rapp-manager/src/main/java/org/oransc/rappmanager/helm/HelmClient.java
@@ -40,13 +40,17 @@
}
public void installApp(App app) throws ServiceException {
- ProcessBuilder builder = prepareInstallCommand(app);
+ ProcessBuilder builder = prepareCreateNamespaceCommand(app.getNamespace());
+ executeCommand(builder);
+ builder = prepareInstallCommand(app);
executeCommand(builder);
}
public void uninstallApp(App app) throws ServiceException {
ProcessBuilder builder = prepareUnInstallCommand(app);
executeCommand(builder);
+ builder = prepareDeleteNamespaceCommand(app.getNamespace());
+ executeCommand(builder);
}
protected String getOverrideFileName(App app) {
@@ -66,14 +70,15 @@
Process process = builder.start();
process.waitFor();
int exitValue = process.exitValue();
+ String commandStr = toString(builder);
if (exitValue != 0) {
String error = IOUtils.toString(process.getErrorStream(), StandardCharsets.UTF_8);
- logger.error("Executing helm command {} failed, exitValue: {} {}", toString(builder), exitValue, error);
- throw new ServiceException("Command execution failed: " + builder + " " + error);
+ logger.error("Executing helm command <{}> failed, exitValue: {} {}", commandStr, exitValue, error);
+ throw new ServiceException("Command execution failed: " + commandStr + " " + error);
}
String output = IOUtils.toString(process.getInputStream(), StandardCharsets.UTF_8);
- logger.debug("Command execution, output:{}", output);
+ logger.debug("Command <{}> execution, output:{}", commandStr, output);
return output;
} catch (Exception e) {
throw new ServiceException("Failed to execute the Command", e);
@@ -84,8 +89,8 @@
List<String> helmArguments = Arrays.asList(//
"helm", //
- "install", getChartFileName(app), //
- "--name", releaseName(app), //
+ "install", app.getName(), getChartFileName(app), //
+ "--version", app.getVersion(), //
"--namespace", app.getNamespace(), //
"--values", getOverrideFileName(app));
@@ -95,7 +100,19 @@
}
public ProcessBuilder prepareUnInstallCommand(App app) {
- return new ProcessBuilder("helm", "delete", releaseName(app), "--purge");
+ return new ProcessBuilder("helm", "delete", app.getName(), "--namespace", app.getNamespace());
+ }
+
+ // Assuming to have a separate namespace for each App,
+ // modifications needed if multiple Apps could share the same namespace
+ public ProcessBuilder prepareCreateNamespaceCommand(String namespace) {
+ return new ProcessBuilder(Arrays.asList(//
+ "kubectl", "create", "namespace", namespace));
+ }
+
+ public ProcessBuilder prepareDeleteNamespaceCommand(String namespace) {
+ return new ProcessBuilder(Arrays.asList(//
+ "kubectl", "delete", "namespace", namespace, "--wait=false"));
}
private void addKubeApiInfo(List<String> helmArguments) {
diff --git a/rapp-manager/src/main/java/org/oransc/rappmanager/service/App.java b/rapp-manager/src/main/java/org/oransc/rappmanager/service/App.java
index 11b4529..939ac43 100644
--- a/rapp-manager/src/main/java/org/oransc/rappmanager/service/App.java
+++ b/rapp-manager/src/main/java/org/oransc/rappmanager/service/App.java
@@ -20,10 +20,8 @@
import lombok.Builder;
import lombok.Getter;
-import lombok.Setter;
@Getter
-@Setter
@Builder
public class App {
diff --git a/rapp-manager/src/main/java/org/oransc/rappmanager/service/AppStore.java b/rapp-manager/src/main/java/org/oransc/rappmanager/service/AppStore.java
index 39b503f..4c49dce 100644
--- a/rapp-manager/src/main/java/org/oransc/rappmanager/service/AppStore.java
+++ b/rapp-manager/src/main/java/org/oransc/rappmanager/service/AppStore.java
@@ -18,11 +18,17 @@
package org.oransc.rappmanager.service;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.PrintStream;
import java.lang.invoke.MethodHandles;
import java.nio.file.Files;
import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -42,13 +48,19 @@
public class AppStore {
private final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+ private static Gson gson = new GsonBuilder().create();
+
/**
* The appStore map contains app name as key & App as value
*/
private Map<String, App> appMap = new HashMap<>();
- @Autowired
- ApplicationConfig appConfig;
+ private final ApplicationConfig appConfig;
+
+ public AppStore(@Autowired ApplicationConfig appConfig) {
+ this.appConfig = appConfig;
+ this.restoreFromDatabase();
+ }
public File getOverrideFile(App app) {
Path appPath = getAppPath(app.getName(), app.getVersion());
@@ -78,6 +90,7 @@
overrideFile.transferTo(getOverrideFile(app));
appMap.put(key(app), app);
+ storeAppInFile(app);
return app;
}
@@ -104,9 +117,45 @@
appMap.remove(key(app));
}
+ private void storeAppInFile(App app) {
+ try (PrintStream out = new PrintStream(new FileOutputStream(getFile(app)))) {
+ out.print(gson.toJson(app));
+ } catch (Exception e) {
+ logger.warn("Could not store app: {} {}", app.getName(), e.getMessage());
+ }
+ }
+
+ private File getFile(App app) {
+ String appPath = getAppPath(app.getName(), app.getVersion()).toString();
+ return Path.of(appPath, APP_FILE_NAME).toFile();
+ }
+
+ private static final String APP_FILE_NAME = "App.json";
+
+ public synchronized void restoreFromDatabase() {
+ try {
+ Files.createDirectories(Paths.get(getDatabaseDirectory()));
+ restoreFromDatabase(new File(getDatabaseDirectory()));
+ } catch (IOException e) {
+ logger.warn("Could not restore apps from database: {}", e.getMessage());
+ }
+ }
+
+ public synchronized void restoreFromDatabase(File file) throws IOException {
+ if (file.isDirectory()) {
+ for (File dirElement : file.listFiles()) {
+ restoreFromDatabase(dirElement);
+ }
+ } else if (file.getName().equals(APP_FILE_NAME)) {
+ String json = Files.readString(file.toPath());
+ App app = gson.fromJson(json, App.class);
+ appMap.put(key(app), app);
+ }
+ }
+
public synchronized void reset() {
try {
- FileSystemUtils.deleteRecursively(Path.of(this.appConfig.getVardataDirectory()));
+ FileSystemUtils.deleteRecursively(Path.of(getDatabaseDirectory()));
} catch (IOException e) {
logger.warn("Could not delete database : {}", e.getMessage());
}
diff --git a/rapp-manager/src/test/java/org/oransc/rappmanager/controller/KubernetesTest.java b/rapp-manager/src/test/java/org/oransc/rappmanager/controller/KubernetesTest.java
index 547c4d3..d47461a 100644
--- a/rapp-manager/src/test/java/org/oransc/rappmanager/controller/KubernetesTest.java
+++ b/rapp-manager/src/test/java/org/oransc/rappmanager/controller/KubernetesTest.java
@@ -11,9 +11,8 @@
import java.util.Arrays;
import java.util.List;
-import org.junit.Test;
import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.runner.RunWith;
import org.oransc.rappmanager.BeanFactory;
@@ -29,7 +28,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.context.TestConfiguration;
@@ -48,7 +46,6 @@
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.BodyInserters.MultipartInserter;
-@AutoConfigureMockMvc
@RunWith(SpringRunner.class)
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
@@ -87,8 +84,20 @@
@Override
public ProcessBuilder prepareUnInstallCommand(App app) {
- String unistall = toString(super.prepareUnInstallCommand(app));
- return executeInVagrant(unistall);
+ String uninstallCommand = toString(super.prepareUnInstallCommand(app));
+ return executeInVagrant(uninstallCommand);
+ }
+
+ @Override
+ public ProcessBuilder prepareCreateNamespaceCommand(String namespace) {
+ String createCommand = toString(super.prepareCreateNamespaceCommand(namespace));
+ return executeInVagrant(createCommand);
+ }
+
+ @Override
+ public ProcessBuilder prepareDeleteNamespaceCommand(String namespace) {
+ String deleteCommand = toString(super.prepareDeleteNamespaceCommand(namespace));
+ return executeInVagrant(deleteCommand);
}
private ProcessBuilder executeInVagrant(String command) {
@@ -152,7 +161,6 @@
}
}
- @BeforeEach
@AfterEach
void reset() {
appStore.reset();
@@ -172,6 +180,15 @@
deleteApp();
}
+ @Test
+ public void testStoreApp() throws ServiceException {
+ appStore.reset();
+ onboardApp();
+ AppStore tmpAppStore = new AppStore(this.applicationConfig);
+ App app = tmpAppStore.getApp(APP_NAME, VERSION);
+ assertThat(app.getNamespace()).isEqualTo(NAMESPACE);
+ }
+
private void onboardApp() {
String url = "/rms/apps";
AppInfo appInfo = AppInfo.builder().name(APP_NAME).version(VERSION).namespace(NAMESPACE).build();