From a20602f67191a5cbd540015e555572ed2e0fba4f Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Jun 2024 11:54:23 +0200 Subject: [PATCH 01/20] Plain tags for development branches. --- .../src/org.jdrupes.vmoperator.versioning-conventions.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle index 114db51..8623857 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle @@ -21,7 +21,8 @@ scmVersion { } var p = shortened.replace('.', '-') + "-" if (grgit.branch.current.name != "main" - && !grgit.branch.current.name.startsWith("release")) { + && !grgit.branch.current.name.startsWith("release") + && !grgit.branch.current.name.startsWith("develop")) { p = p + grgit.branch.current.name.replace('/', '-') + "-" } prefix = p From 837ee043aaf9f813057946a0fb4ecea2027c5cbd Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Jun 2024 12:28:28 +0200 Subject: [PATCH 02/20] Checkout triggering version (is default). --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e6b3c9..3c59936 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,6 @@ jobs: - uses: actions/checkout@v3 with: fetch-depth: 0 - ref: main - name: Install graphviz run: sudo apt-get install graphviz - name: Install podman From 2cb8c90357b6a52218e5e4e6fce5fe7c3989406c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Jun 2024 13:26:47 +0200 Subject: [PATCH 03/20] Try to fix version issue when building release. --- .../org.jdrupes.vmoperator.java-common-conventions.gradle | 8 +++++--- .../org.jdrupes.vmoperator.versioning-conventions.gradle | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle index e09814c..5185041 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle @@ -5,6 +5,11 @@ */ plugins { + // Apply the common versioning conventions. + // Put this at the start, because accessing project.version before + // this is applied makes things fail. + id 'org.jdrupes.vmoperator.versioning-conventions' + // Apply the java Plugin to add support for Java. id 'java' @@ -13,9 +18,6 @@ plugins { // Access to git information id 'org.ajoberstar.grgit' - - // Apply the common versioning conventions. - id 'org.jdrupes.vmoperator.versioning-conventions' } repositories { diff --git a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle index 8623857..8993929 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle @@ -28,5 +28,5 @@ scmVersion { prefix = p } } -version = scmVersion.version +project.version = scmVersion.version ext.isSnapshot = version.endsWith('-SNAPSHOT') From c66e304de444970f390841d2731760d72903bf8c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Jun 2024 13:44:53 +0200 Subject: [PATCH 04/20] Fetch all tags to make axion release plugin work properly. --- .github/workflows/release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3c59936..19f5323 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,9 +18,10 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 + fetch-tags: true - name: Install graphviz run: sudo apt-get install graphviz - name: Install podman From 2403f5db645e9a63f4852fb149145edb78f9922c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Jun 2024 13:57:21 +0200 Subject: [PATCH 05/20] Undo previous commit (is implied by fetch-depth: 0). --- .github/workflows/release.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 19f5323..e99ee03 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,6 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 - fetch-tags: true - name: Install graphviz run: sudo apt-get install graphviz - name: Install podman From 6c250d46561537be61c5a4e243e84e19525b833b Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Jun 2024 14:28:57 +0200 Subject: [PATCH 06/20] Fix release versions. --- .../src/org.jdrupes.vmoperator.versioning-conventions.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle index 8993929..40ced48 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle @@ -21,6 +21,7 @@ scmVersion { } var p = shortened.replace('.', '-') + "-" if (grgit.branch.current.name != "main" + && grgit.branch.current.name != "HEAD" && !grgit.branch.current.name.startsWith("release") && !grgit.branch.current.name.startsWith("develop")) { p = p + grgit.branch.current.name.replace('/', '-') + "-" From 4617d8d3ba6ac5f4145f87ad7f73457ee4768885 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Jun 2024 14:59:08 +0200 Subject: [PATCH 07/20] Make byte[] to String conversion null-safe. --- .../org/jdrupes/vmoperator/manager/DisplaySecretMonitor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/DisplaySecretMonitor.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/DisplaySecretMonitor.java index 8bc1db0..1ea766c 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/DisplaySecretMonitor.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/DisplaySecretMonitor.java @@ -33,6 +33,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Scanner; import java.util.logging.Level; import static org.jdrupes.vmoperator.common.Constants.APP_NAME; @@ -180,7 +181,8 @@ public class DisplaySecretMonitor // Check validity var model = stub.model().get(); @SuppressWarnings("PMD.StringInstantiation") - var expiry = new String(model.getData().get(DATA_PASSWORD_EXPIRY)); + var expiry = Optional.ofNullable(model.getData() + .get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null); if (model.getData().get(DATA_DISPLAY_PASSWORD) != null && stillValid(expiry)) { event.setResult( From a4bd129252a49397946d2603962edb1e74890a83 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 3 Jun 2024 23:10:35 +0200 Subject: [PATCH 08/20] Minor updates. --- misc/stylesheet.css | 54 ++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 32 deletions(-) diff --git a/misc/stylesheet.css b/misc/stylesheet.css index e21b9b2..2debce1 100644 --- a/misc/stylesheet.css +++ b/misc/stylesheet.css @@ -71,37 +71,31 @@ a[name] { color:#353833; } pre { - font-family: "DejaVu Sans Mono", monospace; + font-family:'DejaVu Sans Mono', monospace; } h1 { - font-family: "DejaVu Sans", sans; font-size:20px; } h2 { - font-family: "DejaVu Sans", sans; font-size:18px; } h3 { - font-family: "DejaVu Sans", sans; font-size:16px; } h4 { - font-family: "DejaVu Sans", sans; font-size:15px; } h5 { - font-family: "DejaVu Sans", sans; font-size:14px; } h6 { - font-family: "DejaVu Sans", sans; font-size:13px; } ul { list-style-type:disc; } code, tt { - font-family: "DejaVu Sans Mono", monospace; + font-family:'DejaVu Sans Mono', monospace; } :not(h1, h2, h3, h4, h5, h6) > code, :not(h1, h2, h3, h4, h5, h6) > tt { @@ -111,12 +105,12 @@ code, tt { line-height:1.4em; } dt code { - font-family: "DejaVu Sans Mono", monospace; + font-family:'DejaVu Sans Mono', monospace; font-size:14px; padding-top:4px; } .summary-table dt code { - font-family: "DejaVu Sans Mono", monospace; + font-family:'DejaVu Sans Mono', monospace; font-size:14px; vertical-align:top; padding-top:4px; @@ -124,7 +118,9 @@ dt code { sup { font-size:8px; } - +button { + font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif; +} /* * Styles for HTML generated by javadoc. * @@ -185,7 +181,6 @@ sup { min-height:2.8em; padding-top:10px; overflow:hidden; - font-family: "DejaVu Sans", sans; font-size:80%; } .sub-nav { @@ -193,7 +188,6 @@ sup { float:left; width:100%; overflow:hidden; - font-family: "DejaVu Sans", sans; font-size:80%; } .sub-nav div { @@ -311,13 +305,16 @@ main { position:relative; } dl.notes > dt { - font-family: "DejaVu Sans", sans; + font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif; + /* font-size:12px; */ font-weight:bold; margin:10px 0 0 0; color:#4E4E4E; } dl.notes > dd { - margin:5px 10px 10px 0; + margin:5px 10px 0 0; + /* font-size:14px; */ + font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; } dl.name-value > dt { margin-left:1px; @@ -389,6 +386,11 @@ ul.see-list-long li:not(:last-child):after { border-bottom:1px solid #EEE; padding:0; } + +.summary-table .col-first { + font-family: "DejaVu Sans Mono", monospace; +} + .caption { position:relative; text-align:left; @@ -402,7 +404,6 @@ ul.see-list-long li:not(:last-child):after { padding-left:1px; margin:0; white-space:pre; - font-family: 'DejaVu Sans'; } .caption a:link, .caption a:visited { color:#1f389c; @@ -450,9 +451,6 @@ div.table-tabs > button.table-tab { display: grid; grid-template-columns: minmax(10%, max-content) minmax(15%, max-content) minmax(15%, auto); } -#method-summary-table .three-column-summary { - grid-template-columns: minmax(10%, 20%) minmax(15%, max-content) minmax(15%, auto); -} .four-column-summary { display: grid; grid-template-columns: minmax(10%, max-content) minmax(10%, max-content) minmax(10%, max-content) minmax(10%, auto); @@ -490,7 +488,6 @@ div.table-tabs > button.table-tab { } .table-header { background:#dee3e9; - font-family: 'DejaVu Sans'; font-weight: bold; } /* @@ -508,7 +505,6 @@ div.table-tabs > button.table-tab { .col-last { white-space:normal; } -/* .col-first a:link, .col-first a:visited, .col-second a:link, .col-second a:visited, .col-first a:link, .col-first a:visited, @@ -520,7 +516,6 @@ div.table-tabs > button.table-tab { .all-packages-container a:link, .all-packages-container a:visited { font-weight:bold; } -*/ .table-sub-heading-color { background-color:#EEEEFF; } @@ -537,12 +532,9 @@ div.table-tabs > button.table-tab { margin:0; padding:10px 0; } -/* div.block { - font-size:14px; font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; } -*/ .col-last div { padding-top:0; } @@ -553,8 +545,7 @@ div.block { .package-signature, .type-signature, .member-signature { - font-family: "DejaVu Sans Mono", monospace; - /* font-size:14px; */ + font-family:'DejaVu Sans Mono', monospace; margin:14px 0; white-space: pre-wrap; } @@ -593,13 +584,8 @@ h1.hidden { .deprecated-label, .descfrm-type-label, .implementation-label, .member-name-label, .member-name-link, .module-label-in-package, .module-label-in-type, .override-specify-label, .package-label-in-type, .package-hierarchy-label, .type-name-label, .type-name-link, .search-tag-link, .preview-label { - font-family: "DejaVu Sans", sans; font-weight:bold; } -.sub-title, .inheritance, .all-packages-table-tab1.col-first, - .summary-table .col-first { - font-family: "DejaVu Sans", sans; -} .deprecation-comment, .help-footnote, .preview-comment { font-style:italic; } @@ -658,6 +644,7 @@ main, nav, header, footer, section { ul.ui-autocomplete { position:fixed; z-index:999999; + background-color: #FFFFFF; } ul.ui-autocomplete li { float:left; @@ -667,6 +654,9 @@ ul.ui-autocomplete li { .result-highlight { font-weight:bold; } +.ui-autocomplete .result-item { + font-size: inherit; +} #search-input { background-image:url('resources/glass.png'); background-size:13px; From fefd2737f35a37186d087ba130be47728b919b2a Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 3 Jun 2024 23:12:22 +0200 Subject: [PATCH 09/20] Widen selection box. --- .../jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss index 83e92a5..8ef8b66 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss +++ b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss @@ -43,3 +43,8 @@ white-space: nowrap; } +.jdrupes-vmoperator-vmviewer-edit { + select { + width: 15em; + } +} \ No newline at end of file From ebead171933c870b6b8e8f96e19e7e12e66c97ae Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 4 Jun 2024 09:43:27 +0200 Subject: [PATCH 10/20] Minor update. --- misc/stylesheet.css | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/misc/stylesheet.css b/misc/stylesheet.css index 2debce1..625b5ae 100644 --- a/misc/stylesheet.css +++ b/misc/stylesheet.css @@ -45,7 +45,7 @@ body { background-color:#ffffff; color:#353833; - font: normal 16px/1.5 "DejaVu Serif", serif; + font: normal 16px/1.5 "DejaVu Sans", Arial, Helvetica, sans-serif; margin:0; padding:0; height:100%; @@ -80,10 +80,12 @@ h2 { font-size:18px; } h3 { - font-size:16px; + font-size:17px; } h4 { - font-size:15px; + font-size:16px; + margin-top: 1rem; + margin-bottom: 1rem; } h5 { font-size:14px; From 85d9278e2e5d6159fdb81cc0f41a90b09753053f Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 4 Jun 2024 11:20:12 +0200 Subject: [PATCH 11/20] Update diagrams. --- .../vmoperator/manager/package-info.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java index 54d4efe..cfec873 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java @@ -119,6 +119,7 @@ * [WebConsole] *-- [RoleConfigurator] * [WebConsole] *-- [RoleConletFilter] * [WebConsole] *-left- [LoginConlet] + * [WebConsole] *-right- [OidcClient] * * Component "ComponentCollector\nfor page resources" as cpr <> * [WebConsole] *-- [cpr] @@ -153,15 +154,26 @@ * () "guiHttp" as http * http .up. [GuiHttpServer] * - * [PreferencesStore] .right. http + * [PreferencesStore] .. http + * [OidcClient] .up. http + * [LanguageSelector] .left. http * [InMemorySessionManager] .up. http - * [LanguageSelector] .up. http * * package "Conceptual WebConsole" { - * [ConsoleWeblet] .left. http + * [ConsoleWeblet] .right. http * [ConsoleWeblet] *-down- [WebConsole] * } * + * [Controller] .down[hidden]. [ConsoleWeblet] + * + * () "console" as console + * console .. WebConsole + * + * [OidcClient] .. console + * [LoginConlet] .right. console + * + * note right of console: More conlets connect here + * * @enduml */ package org.jdrupes.vmoperator.manager; From bab0db48d1741e849a652dbb2f5bc69b253e5788 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 4 Jun 2024 11:25:21 +0200 Subject: [PATCH 12/20] Fix typo. --- .../src/org/jdrupes/vmoperator/manager/package-info.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java index cfec873..54e9cd1 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java @@ -57,7 +57,7 @@ * ``` * * Developers may also be interested in the usage of channels - * by the application's component: + * by the application's components: * * ![Main channels](app-channels.svg) * From 08f4a818da2d3b2789bad1460f9f3db2b1628bae Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 4 Jun 2024 21:57:15 +0200 Subject: [PATCH 13/20] Add HTTPConnector to diagrams. --- .../src/org/jdrupes/vmoperator/manager/package-info.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java index 54e9cd1..fc75b24 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java @@ -74,6 +74,8 @@ * * Component NioDispatcher as NioDispatcher <> * [Manager] *-up- [NioDispatcher] + * Component HttpConnector as HttpConnector <> + * [Manager] *-up- [HttpConnector] * Component FileSystemWatcher as FileSystemWatcher <> * [Manager] *-up- [FileSystemWatcher] * Component YamlConfigurationStore as YamlConfigurationStore <> @@ -148,11 +150,13 @@ * () "guiTransport" as hT * hT .up. [GuiSocketServer:8080] * hT .down. [GuiHttpServer] + * hT .right[hidden]. [HttpConnector] * * [YamlConfigurationStore] -right[hidden]- hT * * () "guiHttp" as http * http .up. [GuiHttpServer] + * http .up. [HttpConnector] * * [PreferencesStore] .. http * [OidcClient] .up. http From 9180323618cb65e657689bf7dd98cb7a0d5a1aeb Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 4 Jun 2024 22:09:54 +0200 Subject: [PATCH 14/20] Update. --- .../src/org/jdrupes/vmoperator/manager/package-info.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java index fc75b24..337b5e3 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java @@ -157,6 +157,7 @@ * () "guiHttp" as http * http .up. [GuiHttpServer] * http .up. [HttpConnector] + * note top of [HttpConnector]: transport layer com-\nponents omitted * * [PreferencesStore] .. http * [OidcClient] .up. http @@ -176,7 +177,7 @@ * [OidcClient] .. console * [LoginConlet] .right. console * - * note right of console: More conlets connect here + * note right of console: More conlets\nconnect here * * @enduml */ From d6a0cc622000fe4194124c2b9043108e296f2760 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 5 Jun 2024 21:10:05 +0200 Subject: [PATCH 15/20] Improve state feedback. --- .../org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html | 6 ++++-- .../vmoperator/vmviewer/browser/VmViewer-functions.ts | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html index 913f45d..708a1a3 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html +++ b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html @@ -52,12 +52,14 @@ v-html="controller.breakBeforeDots(entry[key])"> - - - - From b0b6d6723ed13b8c724cc0c84f764ca7b4a4853f Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 6 Jun 2024 12:03:00 +0200 Subject: [PATCH 16/20] Fix typo. --- .../src/org/jdrupes/vmoperator/vmviewer/VmViewer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java index c06cc1a..ab7238a 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java +++ b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java @@ -90,7 +90,7 @@ import org.jgrapes.webconsole.base.events.UpdateConletType; import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet; /** - * The Class VmConlet. + * The Class VmViewer. */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports", "PMD.CouplingBetweenObjects", "PMD.GodClass" }) From f20e61d57c969192e2ddd387b351afe27c2be364 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 6 Jun 2024 12:36:29 +0200 Subject: [PATCH 17/20] Default to generating secrets. --- .../org/jdrupes/vmoperator/manager/DisplaySecretReconciler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/DisplaySecretReconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/DisplaySecretReconciler.java index 14b8890..17456aa 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/DisplaySecretReconciler.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/DisplaySecretReconciler.java @@ -64,7 +64,7 @@ import org.jose4j.base64url.Base64; var display = GsonPtr.to(event.vmDefinition().data()).to("spec", "vm", "display"); if (!display.get(JsonPrimitive.class, "spice", "generateSecret") - .map(JsonPrimitive::getAsBoolean).orElse(false)) { + .map(JsonPrimitive::getAsBoolean).orElse(true)) { return; } From 92c9c6df9ca06f3cc01827ff2ecfdcc50565660a Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 6 Jun 2024 15:45:02 +0200 Subject: [PATCH 18/20] Implement reset. --- .../config-sample.yaml | 6 +++ .../vmoperator/runner/qemu/Configuration.java | 3 ++ .../vmoperator/runner/qemu/Runner.java | 21 ++++++++- .../runner/qemu/commands/QmpReset.java | 43 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpReset.java diff --git a/org.jdrupes.vmoperator.runner.qemu/config-sample.yaml b/org.jdrupes.vmoperator.runner.qemu/config-sample.yaml index c365a12..e23a2ec 100644 --- a/org.jdrupes.vmoperator.runner.qemu/config-sample.yaml +++ b/org.jdrupes.vmoperator.runner.qemu/config-sample.yaml @@ -45,6 +45,12 @@ # property in the CRD. # "guestShutdownStops": # false + + # When incremented, the VM is reset. The value has no default value, + # i.e. if you start the VM without a value for this property, and + # decide to trigger a reset later, you have to first set the value + # and then inrement it. + # "resetCounter": 1 # Define the VM (required) "vm": diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Configuration.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Configuration.java index d6d5219..4e89944 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Configuration.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Configuration.java @@ -82,6 +82,9 @@ public class Configuration implements Dto { /** If guest shutdown changes CRD .vm.state to "Stopped". */ public boolean guestShutdownStops; + /** Increments of the reset counter trigger a reset of the VM. */ + public Integer resetCounter; + /** The vm. */ @SuppressWarnings("PMD.ShortVariable") public Vm vm; diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java index e0baa4f..4d9f479 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Runner.java @@ -55,6 +55,7 @@ import org.apache.commons.cli.Option; import org.apache.commons.cli.Options; import static org.jdrupes.vmoperator.common.Constants.APP_NAME; import org.jdrupes.vmoperator.runner.qemu.commands.QmpCont; +import org.jdrupes.vmoperator.runner.qemu.commands.QmpReset; import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu; import org.jdrupes.vmoperator.runner.qemu.events.Exit; import org.jdrupes.vmoperator.runner.qemu.events.MonitorCommand; @@ -215,6 +216,7 @@ public class Runner extends Component { private CommandDefinition cloudInitImgDefinition; private CommandDefinition qemuDefinition; private final QemuMonitor qemuMonitor; + private Integer resetCounter; private State state = State.INITIALIZING; /** Preparatory actions for QEMU start */ @@ -615,7 +617,7 @@ public class Runner extends Component { * @param event the event */ @Handler(priority = -1000) - public void onConfigureQemu(ConfigureQemu event) { + public void onConfigureQemuFinal(ConfigureQemu event) { if (state == State.STARTING) { fire(new MonitorCommand(new QmpCont())); state = State.RUNNING; @@ -624,6 +626,23 @@ public class Runner extends Component { } } + /** + * On configure qemu. + * + * @param event the event + */ + @Handler + public void onConfigureQemu(ConfigureQemu event) { + if (state == State.RUNNING) { + if (resetCounter != null + && event.configuration().resetCounter != null + && event.configuration().resetCounter > resetCounter) { + fire(new MonitorCommand(new QmpReset())); + } + resetCounter = event.configuration().resetCounter; + } + } + /** * On process exited. * diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpReset.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpReset.java new file mode 100644 index 0000000..0bcffc4 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpReset.java @@ -0,0 +1,43 @@ +/* + * VM-Operator + * Copyright (C) 2023 Michael N. Lipp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.jdrupes.vmoperator.runner.qemu.commands; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * A {@link QmpCommand} that send a system_reset to the VM. + */ +public class QmpReset extends QmpCommand { + + @SuppressWarnings({ "PMD.FieldNamingConventions", + "PMD.VariableNamingConventions" }) + private static final JsonNode jsonTemplate + = parseJson("{ \"execute\": \"system_reset\" }"); + + @Override + public JsonNode toJson() { + return jsonTemplate.deepCopy(); + } + + @Override + public String toString() { + return "QmpReset()"; + } + +} From 0a1f89a27048bf8220c0e6c3d704b4493b634fa5 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 6 Jun 2024 15:58:22 +0200 Subject: [PATCH 19/20] Fix avoiding unnecessary password changes. --- .../org/jdrupes/vmoperator/runner/qemu/DisplayController.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/DisplayController.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/DisplayController.java index 304ea04..dc73cb2 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/DisplayController.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/DisplayController.java @@ -116,8 +116,9 @@ public class DisplayController extends Component { } if (Objects.equals(this.currentPassword, password)) { - return false; + return true; } + this.currentPassword = password; logger.fine(() -> "Updating display password"); fire(new MonitorCommand(new QmpSetDisplayPassword(protocol, password))); return true; From 6a3f6c5e3ea4d17559bcf9010a53e10409522d0c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 9 Jun 2024 12:48:20 +0200 Subject: [PATCH 20/20] Add reset support. --- .../vmoperator/common/VmDefinitionModel.java | 3 +- .../vmoperator/manager/events/ResetVm.java | 48 ++++++++++++++++++ org.jdrupes.vmoperator.manager/build.gradle | 4 +- .../vmoperator/manager/runnerConfig.ftl.yaml | 6 +++ .../manager/ConfigMapReconciler.java | 6 +-- .../vmoperator/manager/Controller.java | 9 ++-- .../vmoperator/manager/Reconciler.java | 25 +++++++++- .../jdrupes/vmoperator/manager/VmMonitor.java | 14 ++++-- .../org/jdrupes/vmoperator/util/GsonPtr.java | 12 +++++ org.jdrupes.vmoperator.vmviewer/build.gradle | 2 +- .../vmviewer/VmViewer-confirmReset.ftl.html | 13 +++++ .../vmviewer/VmViewer-edit.ftl.html | 9 ++-- .../vmviewer/VmViewer-preview.ftl.html | 3 +- .../vmoperator/vmviewer/l10n.properties | 4 ++ .../vmoperator/vmviewer/l10n_de.properties | 5 ++ .../vmoperator/vmviewer/reset-icon.svg | 42 ++++++++++++++++ .../jdrupes/vmoperator/vmviewer/VmViewer.java | 32 ++++++++++-- .../vmviewer/browser/VmViewer-functions.ts | 24 +++++++-- .../vmviewer/browser/VmViewer-style.scss | 50 ++++++++++++++++--- 19 files changed, 275 insertions(+), 36 deletions(-) create mode 100644 org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ResetVm.java create mode 100644 org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-confirmReset.ftl.html create mode 100644 org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/reset-icon.svg diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModel.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModel.java index fa59c82..5e1ebb0 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModel.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModel.java @@ -41,7 +41,8 @@ public class VmDefinitionModel extends K8sDynamicModel { * Permissions for accessing and manipulating the VM. */ public enum Permission { - START("start"), STOP("stop"), ACCESS_CONSOLE("accessConsole"); + START("start"), STOP("stop"), RESET("reset"), + ACCESS_CONSOLE("accessConsole"); @SuppressWarnings("PMD.UseConcurrentHashMap") private static Map reprs = new HashMap<>(); diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ResetVm.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ResetVm.java new file mode 100644 index 0000000..f3320c8 --- /dev/null +++ b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ResetVm.java @@ -0,0 +1,48 @@ +/* + * VM-Operator + * Copyright (C) 2024 Michael N. Lipp + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package org.jdrupes.vmoperator.manager.events; + +import org.jgrapes.core.Event; + +/** + * Triggers a reset of the VM. + */ +@SuppressWarnings("PMD.DataClass") +public class ResetVm extends Event { + + private final String vmName; + + /** + * Instantiates a new event. + * + * @param vmName the vm name + */ + public ResetVm(String vmName) { + this.vmName = vmName; + } + + /** + * Gets the vm name. + * + * @return the vm name + */ + public String vmName() { + return vmName; + } +} diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index a8b67a0..1887108 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -18,10 +18,10 @@ dependencies { implementation 'org.jgrapes:org.jgrapes.http:[3.1.0,4)' implementation 'org.jgrapes:org.jgrapes.util:[1.34.0,2)' - implementation 'org.jgrapes:org.jgrapes.webconsole.base:[1.5.0,2)' + implementation 'org.jgrapes:org.jgrapes.webconsole.base:[1.7.0,2)' implementation 'org.jgrapes:org.jgrapes.webconsole.vuejs:[1.5.0,2)' implementation 'org.jgrapes:org.jgrapes.webconsole.rbac:[1.3.0,2)' - implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.3.0,2)' + implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.4.0,2)' implementation 'org.jgrapes:org.jgrapes.webconlet.markdowndisplay:[1.2.0,2)' runtimeOnly 'org.jgrapes:org.jgrapes.webconlet.sysinfo:[1.4.0,2)' diff --git a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerConfig.ftl.yaml b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerConfig.ftl.yaml index 7679a68..253f9b7 100644 --- a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerConfig.ftl.yaml +++ b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerConfig.ftl.yaml @@ -48,6 +48,12 @@ data: # Whether a shutdown initiated by the guest stops the pod deployment guestShutdownStops: ${ cr.spec.guestShutdownStops!false?c } + # When incremented, the VM is reset. The value has no default value, + # i.e. if you start the VM without a value for this property, and + # decide to trigger a reset later, you have to first set the value + # and then inrement it. + resetCounter: ${ cr.resetCount } + # Forward the cloud-init data if provided <#if cr.spec.cloudInit??> cloudInit: diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/ConfigMapReconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/ConfigMapReconciler.java index a882a79..4219e53 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/ConfigMapReconciler.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/ConfigMapReconciler.java @@ -36,7 +36,6 @@ import org.jdrupes.vmoperator.common.K8s; import static org.jdrupes.vmoperator.manager.Constants.APP_NAME; import static org.jdrupes.vmoperator.manager.Constants.VM_OP_NAME; import org.jdrupes.vmoperator.manager.events.VmChannel; -import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; @@ -62,7 +61,6 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; /** * Reconcile. * - * @param event the event * @param model the model * @param channel the channel * @return the dynamic kubernetes object @@ -70,8 +68,8 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; * @throws TemplateException the template exception * @throws ApiException the api exception */ - public DynamicKubernetesObject reconcile(VmDefChanged event, - Map model, VmChannel channel) + public DynamicKubernetesObject reconcile(Map model, + VmChannel channel) throws IOException, TemplateException, ApiException { // Get API DynamicKubernetesApi cmApi = new DynamicKubernetesApi("", "v1", diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Controller.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Controller.java index 66c11a7..86e3751 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Controller.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Controller.java @@ -181,13 +181,12 @@ public class Controller extends Component { @Handler public void onModifyVm(ModifyVm event, VmChannel channel) throws ApiException, IOException { - patchVmSpec(channel.client(), event.name(), event.path(), + patchVmDef(channel.client(), event.name(), "spec/vm/" + event.path(), event.value()); } - private void patchVmSpec(K8sClient client, String name, String path, - Object value) - throws ApiException, IOException { + private void patchVmDef(K8sClient client, String name, String path, + Object value) throws ApiException, IOException { var vmStub = K8sDynamicStub.get(client, new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), namespace, name); @@ -197,7 +196,7 @@ public class Controller extends Component { ? "\"" + value + "\"" : value.toString(); var res = vmStub.patch(V1Patch.PATCH_FORMAT_JSON_PATCH, - new V1Patch("[{\"op\": \"replace\", \"path\": \"/spec/vm/" + new V1Patch("[{\"op\": \"replace\", \"path\": \"/" + path + "\", \"value\": " + valueAsText + "}]"), client.defaultPatchOptions()); if (!res.isPresent()) { diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java index 5bbfe38..437790b 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Reconciler.java @@ -51,6 +51,7 @@ import org.jdrupes.vmoperator.common.K8sDynamicModel; import org.jdrupes.vmoperator.common.K8sObserver; import org.jdrupes.vmoperator.common.K8sV1SecretStub; import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET; +import org.jdrupes.vmoperator.manager.events.ResetVm; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.util.ExtendedObjectWrapper; @@ -209,13 +210,35 @@ public class Reconciler extends Component { // Reconcile, use "augmented" vm definition for model Map model = prepareModel(channel.client(), patchCr(event.vmDefinition())); - var configMap = cmReconciler.reconcile(event, model, channel); + var configMap = cmReconciler.reconcile(model, channel); model.put("cm", configMap.getRaw()); dsReconciler.reconcile(event, model, channel); stsReconciler.reconcile(event, model, channel); lbReconciler.reconcile(event, model, channel); } + /** + * Reset the VM by incrementing the reset count and doing a + * partial reconcile (configmap only). + * + * @param event the event + * @param channel the channel + * @throws IOException + * @throws ApiException + * @throws TemplateException + */ + @Handler + public void onResetVm(ResetVm event, VmChannel channel) + throws ApiException, IOException, TemplateException { + var defRoot + = GsonPtr.to(channel.vmDefinition().data()).get(JsonObject.class); + defRoot.addProperty("resetCount", + defRoot.get("resetCount").getAsLong() + 1); + Map model + = prepareModel(channel.client(), patchCr(channel.vmDefinition())); + cmReconciler.reconcile(model, channel); + } + private DynamicKubernetesObject patchCr(K8sDynamicModel vmDef) { var json = vmDef.data().deepCopy(); // Adjust cdromImage path diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmMonitor.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmMonitor.java index 41f08ce..e049b17 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmMonitor.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/VmMonitor.java @@ -25,13 +25,13 @@ import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.util.Watch; import io.kubernetes.client.util.generic.options.ListOptions; import java.io.IOException; +import java.util.Optional; import java.util.Set; import java.util.logging.Level; import java.util.stream.Collectors; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; import org.jdrupes.vmoperator.common.K8s; import org.jdrupes.vmoperator.common.K8sClient; -import org.jdrupes.vmoperator.common.K8sDynamicModel; import org.jdrupes.vmoperator.common.K8sDynamicStub; import org.jdrupes.vmoperator.common.K8sObserver.ResponseType; import org.jdrupes.vmoperator.common.K8sV1ConfigMapStub; @@ -121,7 +121,7 @@ public class VmMonitor extends } if (vmDef.data() != null) { // New data, augment and save - addDynamicData(channel.client(), vmDef); + addDynamicData(channel.client(), vmDef, channel.vmDefinition()); channel.setVmDefinition(vmDef); } else { // Reuse cached @@ -151,8 +151,16 @@ public class VmMonitor extends } } - private void addDynamicData(K8sClient client, K8sDynamicModel vmState) { + private void addDynamicData(K8sClient client, VmDefinitionModel vmState, + VmDefinitionModel prevState) { var rootNode = GsonPtr.to(vmState.data()).get(JsonObject.class); + + // Maintain (or initialize) the resetCount + rootNode.addProperty("resetCount", Optional.ofNullable(prevState) + .map(ps -> GsonPtr.to(ps.data())) + .flatMap(d -> d.getAsLong("resetCount")).orElse(0L)); + + // Add defaults in case the VM is not running rootNode.addProperty("nodeName", ""); rootNode.addProperty("nodeAddress", ""); diff --git a/org.jdrupes.vmoperator.util/src/org/jdrupes/vmoperator/util/GsonPtr.java b/org.jdrupes.vmoperator.util/src/org/jdrupes/vmoperator/util/GsonPtr.java index e3d9fcd..8b84ed3 100644 --- a/org.jdrupes.vmoperator.util/src/org/jdrupes/vmoperator/util/GsonPtr.java +++ b/org.jdrupes.vmoperator.util/src/org/jdrupes/vmoperator/util/GsonPtr.java @@ -265,6 +265,18 @@ public class GsonPtr { return set(selector, new JsonPrimitive(value)); } + /** + * Short for `set(selector, new JsonPrimitive(value))`. + * + * @param selector the selector + * @param value the value + * @return the gson ptr + * @see #set(Object, JsonElement) + */ + public GsonPtr set(Object selector, Long value) { + return set(selector, new JsonPrimitive(value)); + } + /** * Short for `set(selector, new JsonPrimitive(value))`. * diff --git a/org.jdrupes.vmoperator.vmviewer/build.gradle b/org.jdrupes.vmoperator.vmviewer/build.gradle index ab667f5..aca015b 100644 --- a/org.jdrupes.vmoperator.vmviewer/build.gradle +++ b/org.jdrupes.vmoperator.vmviewer/build.gradle @@ -5,7 +5,7 @@ plugins { dependencies { implementation project(':org.jdrupes.vmoperator.manager.events') - implementation 'org.jgrapes:org.jgrapes.webconsole.base:[1.3.0,2)' + implementation 'org.jgrapes:org.jgrapes.webconsole.base:[1.7.0,2)' implementation 'org.jgrapes:org.jgrapes.webconsole.provider.vue:[1,2)' implementation 'org.jgrapes:org.jgrapes.webconsole.provider.jgwcvuecomponents:[1.2,2)' implementation 'org.jgrapes:org.jgrapes.webconsole.provider.chartjs:[1.2,2)' diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-confirmReset.ftl.html b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-confirmReset.ftl.html new file mode 100644 index 0000000..f7e3840 --- /dev/null +++ b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-confirmReset.ftl.html @@ -0,0 +1,13 @@ +
+

${_("confirmResetMsg")}

+

+ + + + + + +

+
\ No newline at end of file diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-edit.ftl.html b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-edit.ftl.html index d4e86ca..e86d9db 100644 --- a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-edit.ftl.html +++ b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-edit.ftl.html @@ -1,7 +1,8 @@ -
+
{{ localize("Select VM") }} diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-preview.ftl.html b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-preview.ftl.html index 1cd0392..c034504 100644 --- a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-preview.ftl.html +++ b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-preview.ftl.html @@ -1,4 +1,5 @@ -
+ + + + + + diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java index ab7238a..1534f6b 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java +++ b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java @@ -54,6 +54,7 @@ import org.jdrupes.vmoperator.common.VmDefinitionModel.Permission; import org.jdrupes.vmoperator.manager.events.ChannelCache; import org.jdrupes.vmoperator.manager.events.GetDisplayPassword; import org.jdrupes.vmoperator.manager.events.ModifyVm; +import org.jdrupes.vmoperator.manager.events.ResetVm; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.util.GsonPtr; @@ -93,7 +94,7 @@ import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet; * The Class VmViewer. */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports", - "PMD.CouplingBetweenObjects", "PMD.GodClass" }) + "PMD.CouplingBetweenObjects", "PMD.GodClass", "PMD.TooManyMethods" }) public class VmViewer extends FreeMarkerConlet { private static final String VM_NAME_PROPERTY = "vmName"; @@ -465,12 +466,12 @@ public class VmViewer extends FreeMarkerConlet { @Override @SuppressWarnings({ "PMD.AvoidDecimalLiteralsInBigDecimalConstructor", - "PMD.ConfusingArgumentToVarargsMethod" }) + "PMD.ConfusingArgumentToVarargsMethod", "PMD.NcssCount" }) protected void doUpdateConletState(NotifyConletModel event, ConsoleConnection channel, ViewerModel model) throws Exception { event.stop(); - var both = Optional.ofNullable(event.params().asString(0)) + var both = Optional.ofNullable(model.vmName()) .flatMap(vm -> channelManager.both(vm)); if (both.isEmpty()) { return; @@ -479,6 +480,7 @@ public class VmViewer extends FreeMarkerConlet { var vmDef = both.get().associated; var vmName = vmDef.metadata().getName(); var perms = permissions(vmDef, channel.session()); + var resourceBundle = resourceBundle(channel.locale()); switch (event.method()) { case "selectedVm": model.setVmName(event.params().asString(0)); @@ -497,6 +499,16 @@ public class VmViewer extends FreeMarkerConlet { fire(new ModifyVm(vmName, "state", "Stopped", vmChannel)); } break; + case "reset": + if (perms.contains(Permission.RESET)) { + confirmReset(event, channel, model, resourceBundle); + } + break; + case "resetConfirmed": + if (perms.contains(Permission.RESET)) { + fire(new ResetVm(vmName), vmChannel); + } + break; case "openConsole": if (perms.contains(Permission.ACCESS_CONSOLE)) { var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef), @@ -577,6 +589,20 @@ public class VmViewer extends FreeMarkerConlet { .findFirst().or(() -> addrs.stream().findFirst()); } + private void confirmReset(NotifyConletModel event, + ConsoleConnection channel, ViewerModel model, + ResourceBundle resourceBundle) throws TemplateNotFoundException, + MalformedTemplateNameException, ParseException, IOException { + Template tpl = freemarkerConfig() + .getTemplate("VmViewer-confirmReset.ftl.html"); + channel.respond(new OpenModalDialog(type(), model.getConletId(), + processTemplate(event, tpl, + fmModel(event, channel, model.getConletId(), model))) + .addOption("cancelable", true).addOption("closeLabel", "") + .addOption("title", + resourceBundle.getString("confirmResetTitle"))); + } + @Override protected boolean doSetLocale(SetLocale event, ConsoleConnection channel, String conletId) throws Exception { diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-functions.ts b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-functions.ts index 71bb0a4..1c20d66 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-functions.ts +++ b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-functions.ts @@ -31,8 +31,9 @@ declare global { interface Window { orgJDrupesVmOperatorVmViewer: { initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void, - initEdit?: (viewDom: HTMLElement, isUpdate: boolean) => void - applyEdit?: (viewDom: HTMLElement, apply: boolean) => void + initEdit?: (viewDom: HTMLElement, isUpdate: boolean) => void, + applyEdit?: (viewDom: HTMLElement, apply: boolean) => void, + confirmReset?: (conletType: string, conletId: string) => void } } } @@ -74,7 +75,7 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, provideApi(previewDom, previewApi); const vmAction = (vmName: string, action: string) => { - JGConsole.notifyConletModel(conletId, action, vmName); + JGConsole.notifyConletModel(conletId, action); }; return { localize, resourceBase, vmDef, vmAction }; @@ -83,7 +84,7 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, - @@ -211,3 +221,9 @@ window.orgJDrupesVmOperatorVmViewer.applyEdit = const vmName = getApi>(dialogDom!)!.value; JGConsole.notifyConletModel(conletId, "selectedVm", vmName); } + +window.orgJDrupesVmOperatorVmViewer.confirmReset = + (conletType: string, conletId: string) => { + JGConsole.instance.closeModalDialog(conletType, conletId); + JGConsole.notifyConletModel(conletId, "resetConfirmed"); +} \ No newline at end of file diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss index 8ef8b66..c90a45f 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss +++ b/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss @@ -19,7 +19,24 @@ /* * Conlet specific styles. */ -.jdrupes-vmoperator-vmviewer-preview { +.jdrupes-vmoperator-vmviewer { + + span[role="button"].svg-icon { + display: inline-block; + line-height: 1; + /* Align with forkawesome */ + font-size: 14px; + fill: var(--primary); + + &[aria-disabled="true"], &[aria-disabled=""] { + fill: var(--disabled); + } + + svg { + height: 2ex; + width: 1em; + } + } [role=button] { padding: 0.25rem; @@ -28,7 +45,10 @@ box-shadow: var(--darkening); } } +} +.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-preview { + img { height: 3em; padding: 0.25rem; @@ -37,14 +57,30 @@ opacity: 0.4; } } + + .jdrupes-vmoperator-vmviewer-preview-action-list { + white-space: nowrap; + } } -.jdrupes-vmoperator-vmviewer-preview-action-list { - white-space: nowrap; -} - -.jdrupes-vmoperator-vmviewer-edit { +.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-edit { select { width: 15em; } -} \ No newline at end of file +} + +.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-confirm-reset { + p { + text-align: center; + } + + span[role="button"].svg-icon { + fill: var(--danger); + + svg { + width: 2.5em; + height: 2.5em; + } + } + +}
+ + + + + +