From a20602f67191a5cbd540015e555572ed2e0fba4f Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Jun 2024 11:54:23 +0200 Subject: [PATCH 001/342] 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 002/342] 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 003/342] 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 004/342] 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 005/342] 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 006/342] 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 007/342] 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 008/342] 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 009/342] 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 010/342] 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 011/342] 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 012/342] 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 013/342] 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 014/342] 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 015/342] 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 016/342] 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 017/342] 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 018/342] 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 019/342] 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 020/342] 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; + } + } + +} From 65a5cfd2867fe168e66aab6a61c77e84e9ab5e8f Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" <1446020+mnlipp@users.noreply.github.com> Date: Sun, 9 Jun 2024 22:54:42 +0200 Subject: [PATCH 021/342] Develop/v3 (#27) Prepare release. --- .github/workflows/release.yml | 3 +- README.md | 5 +- ....vmoperator.java-common-conventions.gradle | 8 +- ...s.vmoperator.versioning-conventions.gradle | 6 +- deploy/crds/vms-crd.yaml | 7 +- dev-example/Readme.md | 8 +- example/local-path/Readme.md | 8 +- example/rook-ceph/Readme.md | 4 +- misc/stylesheet.css | 62 +++++++------- .../vmoperator/common/VmDefinitionModel.java | 3 +- .../vmoperator/manager/events/ResetVm.java | 48 +++++++++++ org.jdrupes.vmoperator.manager/build.gradle | 4 +- .../manager/ManagerIntro-Preview.md | 4 +- .../manager/ManagerIntro-Preview_de.md | 2 +- .../vmoperator/manager/runnerConfig.ftl.yaml | 6 ++ .../manager/ConfigMapReconciler.java | 6 +- .../vmoperator/manager/Controller.java | 9 +-- .../manager/DisplaySecretMonitor.java | 4 +- .../manager/DisplaySecretReconciler.java | 2 +- .../vmoperator/manager/Reconciler.java | 25 +++++- .../jdrupes/vmoperator/manager/VmMonitor.java | 14 +++- .../vmoperator/manager/package-info.java | 25 +++++- .../config-sample.yaml | 6 ++ .../vmoperator/runner/qemu/Configuration.java | 3 + .../runner/qemu/DisplayController.java | 3 +- .../vmoperator/runner/qemu/Runner.java | 21 ++++- .../runner/qemu/commands/QmpReset.java | 43 ++++++++++ .../org/jdrupes/vmoperator/util/GsonPtr.java | 12 +++ .../vmconlet/VmConlet-view.ftl.html | 6 +- 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 | 58 +++++++++++--- .../vmviewer/browser/VmViewer-functions.ts | 80 ++++++++++++------- .../vmviewer/browser/VmViewer-style.scss | 59 +++++++++++++- 39 files changed, 500 insertions(+), 132 deletions(-) create mode 100644 org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ResetVm.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpReset.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/.github/workflows/release.yml b/.github/workflows/release.yml index 3e6b3c9..e99ee03 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,10 +18,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - ref: main - name: Install graphviz run: sudo apt-get install graphviz - name: Install podman diff --git a/README.md b/README.md index 1895bbb..176437a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Java CI with Gradle](https://github.com/mnlipp/VM-Operator/actions/workflows/gradle.yml/badge.svg)](https://github.com/mnlipp/VM-Operator/actions/workflows/gradle.yml) +[![Java CI with Gradle](https://github.com/mnlipp/VM-Operator/actions/workflows/gradle.yml/badge.svg)](https://github.com/mnlipp/VM-Operator/actions/workflows/gradle.yml) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/2277842dac894de4b663c6aa2779077e)](https://app.codacy.com/gh/mnlipp/VM-Operator/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) ![Latest Manager](https://img.shields.io/github/v/tag/mnlipp/vm-operator?filter=manager*&label=latest) ![Latest Runner](https://img.shields.io/github/v/tag/mnlipp/vm-operator?filter=runner-qemu*&label=latest) @@ -6,8 +6,7 @@ # Run Qemu in Kubernetes Pods The goal of this project is to provide the means for running Qemu -based VMs in Kubernetes pods. +based VMs in Kubernetes pods. See the [project's home page](https://mnlipp.github.io/VM-Operator/) for details. - 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 114db51..40ced48 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle @@ -21,11 +21,13 @@ scmVersion { } var p = shortened.replace('.', '-') + "-" if (grgit.branch.current.name != "main" - && !grgit.branch.current.name.startsWith("release")) { + && grgit.branch.current.name != "HEAD" + && !grgit.branch.current.name.startsWith("release") + && !grgit.branch.current.name.startsWith("develop")) { p = p + grgit.branch.current.name.replace('/', '-') + "-" } prefix = p } } -version = scmVersion.version +project.version = scmVersion.version ext.isSnapshot = version.endsWith('-SNAPSHOT') diff --git a/deploy/crds/vms-crd.yaml b/deploy/crds/vms-crd.yaml index f441cbc..bfe3985 100644 --- a/deploy/crds/vms-crd.yaml +++ b/deploy/crds/vms-crd.yaml @@ -1012,7 +1012,12 @@ spec: type: array items: type: string - enum: ["start", "stop", "accessConsole", "*"] + enum: + - start + - stop + - reset + - accessConsole + - "*" default: [] vm: type: object diff --git a/dev-example/Readme.md b/dev-example/Readme.md index dfcd3e8..516fb7e 100644 --- a/dev-example/Readme.md +++ b/dev-example/Readme.md @@ -1,16 +1,16 @@ # Example setup for development -The CRD must be deployed independently. Apart from that, the +The CRD must be deployed independently. Apart from that, the `kustomize.yaml` * creates a small cdrom image repository and - + * deploys the operator in namespace `vmop-dev` with a replica of 0. - + This allows you to run the manager in your IDE. The `kustomize.yaml` also changes the container image repository for -the operator to a private repository for development. You have to +the operator to a private repository for development. You have to adapt this to your own repository if you also want to test your development version in a container. diff --git a/example/local-path/Readme.md b/example/local-path/Readme.md index 7afb948..bdba8cc 100644 --- a/example/local-path/Readme.md +++ b/example/local-path/Readme.md @@ -1,17 +1,17 @@ # Example setup -The CRD must be deployed independently. +The CRD must be deployed independently. ```sh kubectl apply -f https://github.com/mnlipp/VM-Operator/raw/main/deploy/crds/vms-crd.yaml ``` -Apart from that, the `kustomize.yaml` defines a namespace for the manager +Apart from that, the `kustomize.yaml` defines a namespace for the manager (and the VMs managed by it) and patches the repository PVC to create a small volume using local-path. -A second patch provides a new configuration file for the manager -that makes it use the local-path storage class when creating the +A second patch provides a new configuration file for the manager +that makes it use the local-path storage class when creating the small volume for a runner's data. The `kustomize.yaml` does not include the test VM. Before creating diff --git a/example/rook-ceph/Readme.md b/example/rook-ceph/Readme.md index 1d2cfc6..3756e93 100644 --- a/example/rook-ceph/Readme.md +++ b/example/rook-ceph/Readme.md @@ -1,12 +1,12 @@ # Example setup -The CRD must be deployed independently. +The CRD must be deployed independently. ```sh kubectl apply -f https://github.com/mnlipp/VM-Operator/raw/main/deploy/crds/vms-crd.yaml ``` -Apart from that, the `kustomize.yaml` defines a namespace for the manager +Apart from that, the `kustomize.yaml` defines a namespace for the manager (and the VMs managed by it) and applies patches to use `rook-cephfs` as storage class (instead of the default storage class). diff --git a/misc/stylesheet.css b/misc/stylesheet.css index e21b9b2..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%; @@ -71,37 +71,33 @@ 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; + font-size:17px; } h4 { - font-family: "DejaVu Sans", sans; - font-size:15px; + font-size:16px; + margin-top: 1rem; + margin-bottom: 1rem; } 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 +107,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 +120,9 @@ dt code { sup { font-size:8px; } - +button { + font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif; +} /* * Styles for HTML generated by javadoc. * @@ -185,7 +183,6 @@ sup { min-height:2.8em; padding-top:10px; overflow:hidden; - font-family: "DejaVu Sans", sans; font-size:80%; } .sub-nav { @@ -193,7 +190,6 @@ sup { float:left; width:100%; overflow:hidden; - font-family: "DejaVu Sans", sans; font-size:80%; } .sub-nav div { @@ -311,13 +307,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 +388,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 +406,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 +453,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 +490,6 @@ div.table-tabs > button.table-tab { } .table-header { background:#dee3e9; - font-family: 'DejaVu Sans'; font-weight: bold; } /* @@ -508,7 +507,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 +518,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 +534,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 +547,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 +586,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 +646,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 +656,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; 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/ManagerIntro-Preview.md b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/ManagerIntro-Preview.md index 50a3024..b6b9efa 100644 --- a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/ManagerIntro-Preview.md +++ b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/ManagerIntro-Preview.md @@ -1,5 +1,5 @@ -You can use the "puzzle piece" icon on the top right corner of the +You can use the "puzzle piece" icon on the top right corner of the page to add display widgets (conlets) to the overview tab. Use the "full screen" icon on the top right corner of any -conlet (if available) to get a detailed view. \ No newline at end of file +conlet (if available) to get a detailed view. diff --git a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/ManagerIntro-Preview_de.md b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/ManagerIntro-Preview_de.md index e5e4d68..bec5f3e 100644 --- a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/ManagerIntro-Preview_de.md +++ b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/ManagerIntro-Preview_de.md @@ -1,4 +1,4 @@ -Verwenden Sie das "Puzzle"-Icon auf der rechten oberen Ecke +Verwenden Sie das "Puzzle"-Icon auf der rechten oberen Ecke der Seite, um Anzeige-Widgets (Conlets) hinzuzufügen. Wenn sich in der rechten oberen Ecke eines Conlets ein Vollbild-Icon 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/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( 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; } 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.manager/src/org/jdrupes/vmoperator/manager/package-info.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/package-info.java index 54d4efe..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 @@ -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) * @@ -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 <> @@ -119,6 +121,7 @@ * [WebConsole] *-- [RoleConfigurator] * [WebConsole] *-- [RoleConletFilter] * [WebConsole] *-left- [LoginConlet] + * [WebConsole] *-right- [OidcClient] * * Component "ComponentCollector\nfor page resources" as cpr <> * [WebConsole] *-- [cpr] @@ -147,21 +150,35 @@ * () "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] + * note top of [HttpConnector]: transport layer com-\nponents omitted * - * [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\nconnect here + * * @enduml */ package org.jdrupes.vmoperator.manager; 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/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; 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()"; + } + +} 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.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])"> 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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 8707e8b..a441313 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 79a61d4..b740cf1 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,10 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 93e3f59..25da30d 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/misc/DejaVuSans-Bold.woff2 b/misc/DejaVuSans-Bold.woff2 deleted file mode 100644 index 373095faf51a2373b8dbeb990a062d1ee5d0fbc8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236792 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%0Djo?;{|^8Z5m*-6?wCD1DACM~{|-Mj{*d8ZOd?;9 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∈CucM^lJrPd^1yvgL^ki@#`W^H0HUJWJ+ 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⁢R|n#JIBy@$BC2~ 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

#3r2K-Rrxj@p`}Nq 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 bnSERoeV@9DgSt*4_MNhCCEqz|UQYgh!ZM0I diff --git a/misc/DejaVuSansMono-Bold.woff2 b/misc/DejaVuSansMono-Bold.woff2 deleted file mode 100644 index f2b469a6c224ab9614577089d40917cfb8b34ac3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 143796 zcmV)ZK&!uZPew8T0RR910x`4z5&!@I1rW#p0x?Pe0RR9100000000000000000000 z0000#Mn+Uk92#^RxN01T1_o9DtTqUP1POsF5ey2C%TSEaAq(eJ00A}vBm=W>1Rw>% zLI;8O01SzETMHhv1tQ1T-DAMi+KLpzS_Lu3XzMY9q{u`354;eK!}}&;b`1|aR#jFT zbAx90Eo}$%W_1eOVc(bR|NsC0|NsC0|C>pEMDOOCx!jxC*}dIM2q73E2?+6nQqfAa zf`q;&QjyBAet>gJD3V^ps*tFUhe&f}Ph` zBL%U{Vky?jvjMrw$lddJVPcmOu3kQeCt{Q|;_#IiQW`ZQW}w*MTHW&L(Rh+)$o>0C zJ$qeit+it4-%a2R#nfv}wN~W*y$x+zYfZIQ{H)jhyi*%%t+iI<9^R_Ia9#3yd_b&L zBSlLxi(d^1E;cSre6+iGbU(3A9X_k1N{aiNRf{8evX3-$e(1%!y83O5@m{mZpXgt7 zQ@)gqhssX7WA&q#Y!8vvOfcWd^|n zI)j2t27}Gbs0>s$E)9X@8pTIBoetx^ei&bz?aySzZ1&?2UL%Rw`Z!NR_rhvTrN7CUdihq zA5px8o8P(O?jj*M65()Oo7gieTfsX}{@L|dP;esot4ekz)n_lRa3PoF+XuxF8eds| zZnu{o*J6G&k5oiVd}Q~(0qY_e3G|f z`fqEkwJGYvN(XlTPpzk|wf1kr(Bn7}H}e0}NiQdu^sVYlJ$Vd7L+WqvX37I2nB?%cTqmZ33vy#!U zMk-{@yCGPc2Z9)MKRl8D&p-9>QNceS1$^-2^TZP+QC6a2V4;mQd*O6Wm)dN)>2&rs zb#6lc-+qx*{ohQ_Zr?CV;NyWUqDIzH~?Qg_Ihv3?Df{1Z?4R@R_v@~tWe3S zq(P*Rd`6k6&{+SMGyQ{_kw=nIwoKCQ2H2aFz*E40H^|dQB}H#Sc2F&=WbfgWcQ3&? zhuaeWwYOiNJG(mz?+FiCCHEaN28YYZC{$7g7Zq7kl*c0RX@>uwuKt{6=I5N2c@ptj zOloPwsuJjt$U-BOGE<;C+udo)`DtP1CxIu*h@&#&;3JORB*^YQY~iUxm0oI6655-G zkGS}~z1x|>1QIwbvBZmutr+^Z5Bh2^|LfW5Gy5ck47q&B#_*L!h9oS;;ZaDG#Ud>K z?he5=I~8XYI_)7PHi8P)lvEJ}qcBi0F=L8i)^q~)=Gs`sZ!YRLR&FhecCuce)Qc5Ys4bCl!rf8a?X_^M`-Qd7AilQi*rfHgXgA=eBq9}@{D5?qc z#r<~xzyrh(nE!iWA4QS|7EX{nuuM80@m=eUxto6?z~PvR$Iu!s zpo+Vz)RJ0&v%A{;0HDa`>;uU-$7jqkjR8OtnUZKtm{XXq2i&|;N-3qd!GT*8MNu?O z(=_b?H@`|LrIhkln)bd%H$npqbfbYhh?6l4n4w59C=9+sl2g*UXlH4h=f|M6GY_+t zLkK7CFUjj;lC#PumQO67SpURzlrw98{{w$hCD7q8o*Jw`=9^+I7l=5&i%WPh{VE`*0h8nh;oVQ_rJ#P&dl3g@ZIH5#glpBkTerX z-)MLwa;WB&&JNN80WZF3#jtK^Z;zW{P7X{B4Xx3ns6DHQ-+(yY{S z+Hy3^Wgz78@JjELCcED^HSM%IQi@VgE$fe>_Xa39fRWN@8yihlWNox}Nbk_xqCKOD zP#8=>Q{UU707MVWP*a}*+4RFY#tK5nD%mNTTL0aW9cQOCcCu^PfrH(>z`_v(4gk7) zBr70UhJ=@GXR4|+$$K9(xsPIF5{Zp5%0#g_&|o--ou!YsF@WaL5q*y#v9UnC`Bwm0 zG}efOBDOOt|F>^~h&CEcJTw|KvC@cy`q}?qHPL6|6Zil=3PF$r>ygK6lupGu$))$% zo1M(@n)GE!Iv8wBwWW(|MD=->JY9bJ3K7y7ULiGunnFd%40|!7_4{ASG zz(tj+$w|==z&5&8a7L?C%q3IHhVbVyzi5)h!N3H|6Z9ysv`fRmZ)E~32XJj zO~j%Yc@TzU$Nzf%f*^<>mIOs-QDZaue@(y7+RcjNYKmi~{Jt~x6v+st?NE@A*ghBH zGeHjh!>MrpQP!kbf};g$DZpJ;9$Tac-K>cP_^;nj@9ez)1856m>#H0PI1ZgW*$7o2 zBWeV}W+q3u^uOwEVON)6v;c726A*|zGalI<(AbJI@pBxhRTsmf?<5O!IPQsn0v`yD z`Tytk7fGvjIz(8dvJepujr-6xZA8&NNytU>7j5E=h4!r~&wpLL-E+@`Rt<$T7P1Ka z4O1RVc`!gb$Zio_Y5LVKa3C-N*>)4{P+$Oq8*T-|nNG_Nb{eY(91oY>kYY&om;Sy~ zt?O@4(ljV}+*Gh3O`D0xDbJvnQ#!-go&rg+}d?&Y?J z^PU_g<=cjIy3P5xDV_FmT_|!{($%fgvh9y6Cxi`X0?dS5>9XeT{$J}P=|iRt5vGWY z5+eyg6Uc1;zoos=dTy0n?WlIjeSF#>%aP_tkPS$6^_N;#HT_4@k2O8xkjruyeL3|{ zahwAIJ_f|U9i^Y;5CaSeWw?kh_F1-&Eg%cf0>t+3E7j_n35qr-yE;hO6{X(oUgcR` zvtBKiX4#hG#GK~%^S%7|TPBeB36MYnkiY~fk$@zFNzw*E%L9N^1whMcQe}5jvU|dE zc{)_HTJCKlLCKaVyIZDgk1cm~_o%9SKh3t=v+T=tJDh56Rp-MT4woT5f70xmOPcHo zoWQ%bZjXlW(@KH2Nbj*|StZm|Mdg|?GS&l__3zn2A=q2h)w$DVX2-qTH{Nv1X0KfD zy@d}SKuOdhPcRl2U;+@x?^CTzr+1ELw6V#luGQ8scuMs*V$ z5ZsYBp`MZ?S!KrmpQ^gz@b5nY6kzjI93!1+dfq&YZOi1BEt&khOdoeR0wi#xNPudf zi{#RpOsCMLrzjpXt;)jE&i;c1z(SN==?ad9}YR)*c16kw<~v{r;`#UY_WCMl11 zm@gC4v3swx|8ae(EQ!EnRjl zlZONF&;vQ9dF$t=!`Q6%R(IdE(m5576qt#W{)kS$GZ-?OaXl_Sza<2W#|8`@k}Y}6 zC&?m)*ws;Z6wPJ;=@K+2g$%2PV#;HLeQ%$)em?rzM{>?N$z&!;CiDCMO*`|*QeQDD zM8F@Olr&3~RP=xD%yuFG07`(K1DXBDRR%xWnJ_6c2xpTC02oG)77Wxv+N+PGyy6VV z>-MHjEBB^6D%(~__4Bp9GEm%=~1`jyd2lpVHZ+ELBaav(bP8215QOEye!A zo_#J;2%r}oHCm8+*{#+BO0PQ_%z%4GQymW!cQo}jP?2*NP^tKK3=^b03|({~J{~Lz zXR^P-Jqsgk!37tw;$6pY%i zn5w{ni~Af1e2rNeNTMalOwNc##3VGIG0`|SvE#XMC3K?E{`xz78ap##0Q+=e;(;$2 z_rQ+~kI<3w^RCo~n$`dDDO5oq-ys07lsor5VX^5s-Xd!RG`oTo>(_0-a z#+8$7kvg-A9&>637611!q?xA=SNeYg4lCd=qv@GG{Vo)!?mAwTT0u8(>C|%t*z0}W zA2%ld^1oJLNtz|?ytMt?Mn$(=zX&C0PE>Tu^&1jTWeeq6v(t-eFR6y@p*lUG*!Y}yYHVqxwu&wQf9%0Ee}!qTOiahBQVnsqisK^|#fwJH*JxdfVEOkV+ftyqJuVhMtL)gPV_# zN*l{|T+bI$X=9z&O&L&J4+vJICLq|N zPop6%giDgH8mNg&nU_toJmX`f5zgcor*aKVk`{EyQIW?hx?{*k$@T(#B0st8qQyeH z)Z?gN>^1&v0#7&L%TCe_Y!B&o*3DjM;2Q6j4UOt!K zo#?eWI|=`vUE#dw=&4G$!f4Y0+ayV5M<=;ZNEw_HV3-7S^B7ur2E+OzUreR~IuHukN7h`i{8ZbP>DP(YY~phma0?n!>@Z+7g%Xn zQIF+3l`WIha-)~;@zSWQHO@A_SwVooKA1XO%}L)`_W^vJS7w98vRm3ZhPw@SXzOm- z0MM&e(ErhtRJrg^FLDCJ%nXO>Ss($_%}NQwF>9s|*Lg2XEX*tU&&rw4mYM_a8%|wY zJQx1`PVg&>>Q{edCjHm1OnuGv>tJ#@-i{hgc~s)+#{FzT1yo=KLqq5h?oN>;>k3uZ z>3*@&U*|mM%=+^3f6bHQUiy}tM!&YGzNT;X;*AY0|8h6;*HyQ@Sal!v-14X>tGa2s zzF3(`HR?5K)uCITqO9ts)$VkA{i3YurtSKAlg+{90T5wA83&L+B!y{)tRg>4nlfiOOK}P~Fqg)jye6 zQq|Db)8DX|q>Q|hs)n|n(CEbU+~P{x`t|lZw}Pyhjvv0sMqVEwl{VISAq{0(+ICz| zNTrQsJFe#oskCpbvsuZDP9M&S6grE`F9b!PaYPE8#pO37p2`mPKS9C%*8hUdbhMV| z&RoMqNLE$@C(gn`zeEQ~X#ALptgdD4Z{#`S;#KFkxBmL2C=1JWnxlt{11o`6A&Bl2 zvfIbrh^h9jm8_N*Yr_!WaEh0QLw&wu|G*WixN~ctLgNa+f#W{{dLtc@zq4+de8vP$ zd0Ul_8N6z@aC=NUVXZ72eQL&R?E=QJ)IFgyx!Nb0%%OP_`k~?RNJ9v8$Tm2c-e9+x zBFc+b%>oTG;#D1K&4&1rl246Owkk4(c5%4R^m-3c^zR_3%dz<>%mxY`Scul2xWfKP zho1%-w6{t>BU)E&&_Z1R$@{c39~0&Kf&o@{vRT+qx8k{amfqrNJQGI6=^&l%dabSB zihAQ&;Z*GYY+!DTm0wtf21;n?06eTZ@S6xYe8o4Uz?B?1C#$%%50yXM%RH|=iv+`Y z9ZIRMM|)4dK&fA96fD$&4+LUhg@A&Ug~Ch9%kE=;x$I2Zm~%l8ZPnmp9Py7{kQl^~ ziaevB@Au-7g+BLS;b|t-(S7wU>X3BA5Su`!LBEW_>?~#KvPx&R3ayz$)-lZ)IX=n_ zpH+tJa8ehjGxyPgQ|vm*T~~T)VKn3t7gweK2QnU919TjP{P$9Y=)6hl; zf)3KDaT=c3IjcrT^Q@IVyjCdZ@4wypg0W?NE#TJF{}RlLr9$rZ01 z?R1xWzakG?v`=N!cpN76s8!HtCopnAs-g;E!aeNjs=x0piHo8;GC!bQdU$;5&nB^2 zgxg=Vi&v3Tp)n;SoG;tt11A5CI>s@+y#GeBrG@;8&hQbl{im`hB257peo0Cu$*&k9 zu_+~5(vY+hDUXr%rZi^f;||dSnc(%JAiBpzQ7kTsbKS+Iyfo! zx<(-m)9q&~ah&=_8BWvCsK9wz9V56*@5VH4+<`x=1i&YiD2tG}DE6&l$e0B?&%EFx zNVr(Z(qt)6s#2Y1olU!aYX9H4Ulcs(zbDpdX8g}JH#=_ zr%pvXE`S3Wq@b->M!lQW=e=*jfd_nStYAj@{$4eU&pJaG54Z;f+#wF*nCjCbNI?ox z(1H}SAO)%VfEbI3f(Zz$G%cEs!B>HTD>juTQ2Gbm^#JiF(Yt{DL-TCzooby0i1$?S z`@k&%?W3f$f-%J#zyS;>U;zRE$g)WQj(U;V|%QGmVhNN5Ln_9!uS!cP{N9T7`TI$L4^X) zJ1U-tHF>JQ{Pz7Xf;4yZq|BBW$1=8YjB7j-n#jZ?At?z+NWv4H_#`Ja>B&l7M6-Py zj?J++md5T_4S|3sFa;lgaA;`ZBmj5tWmt{?^xAU9t;pqxds$W}UgcOZ_|=PwCv>r( z(&1RFu3Y#f{BylIMzM%Z9O4p>gd`%E#3woF3C_zzB`!&Mows?H+=yh`I2aq__xLw< z#{bX}a0EsIar`9oLJd2DA5u4tH4CI~k7zyt=Q^+Ygzm_%lR6t*!mk9)0}lhFdCxJb zW)Kw9zjg)X-g2lMc#c6_UE6yHS`z*R1~GJ|o#EH)8YkCk6F{<-^tDRHY`rko)w@Wiq9*0Z1Bs4wgP~I0sybfIQy>jf6G%t z`22a3|NBk&)q4G0gkSzB?tK442mi0))@Q!nzY>$npE&KG^}@Wz ze>A1R?g7IHbg@F`;lKRu5ZN~{9EqXvL=u_G;pTtzzrZ3T%7jolvL=^ekS1x7Uil=S zK|~wp(7}l{c#RCaM;WS7j}91=7_s9w_Q*=%K3SAd#xg3|#=~r-&zv`Zk)pJ^XwgMo z(M>&8hN`qiM>SO|v_|UHf>^V6)V=XjvX1#R5sv5A9MBawy*o64|%p%c$K%i z>#N`KGRl|=i&`|}CEB7pUPeL`M}Os2>6XuuS~5ymqABy3r^!lwinBZ$a(R~I=WI@z zMK-zTU-giBa{XWZzXoXBHJ+P3&9-&ZvbP+q=2m+ryu(hl)A=9IWp3vFX_}!FG}vg3?ms z@=tOI>*KF2+imavDXh30#Y&iM;eV-*&5y_=m@D zcH>#;i@-=R8&#V3IwGX_I{Nykj+7V6Ur8^e2_;X;^&yTYO^uhFWe(Zxl)vl2^(5zC z|EcNO412V;8d}a)>%If{=h5t3&wbC0w)=OE)@chaE(0G@9Qgcs#s4m@W^K0GPnP@9 zGD|Er&m6PO@U3r5HQ9JW4D_j$N)*YHD@V30F_xHPkUr9gj7qsF2b4X^tWllXwP|&Y z8dRr(i!P8M;WSbFj^V+D6BF7a>e2tv&4V{PsaL&Lqmqb4LIICsp@G=#{@2W(?>R;* zA!9=+7joGwIu;Fw0{w8{mW9@iiIIU?sgTR`Bw~?(PjU&C9i%Fxihg_c=-#cPOG9_t z>D|&Cr2D_2F4DeTZhc*CsWKOfW_V)?s=JFX53lZSt}c!qZcdgaqP{ZLC=7;l}Nb8M5dobobg0tWm8gINq zZ`&TCPmXXpb%ECpKO;TuwrAz&TytN@1tjyR9SbR-e;eWXbqqbk?2E$&M-zyX0bw=$AjNL zLWKM$Ezatdh(%?PBHaZ!^2jS!PC>0+ik^EBy=RC*QT-ah8jF&`a^H zY0f+^n>P8_w$0bRBYrM?Pe?V{-Q;+wQk4itjzsz8ccSkZU`H%bqT=`qNPKM(_7<5$ z)R^=3-uA?fJV8R`i-Pf9tT?3-BSSR~yQj>HmiY#;jX>%?nFHGgfKd;#1%~0gL_+p{P>CipQF# zoOVVfNmRM0n%ACFM>RE(MS#A!5_JIKQ?QK|{0>0(s{+^`33Kp@!kcw4@*6oXlfgp+ zEp!l|hXF>I1PBx)Scp(z!bOM_C0dMFapEON1d${eREkt-(q+h$C0mYMFmMQYkWlg! zC{&~vT8UB^SU7kDL?mPsR5Wx9Oe}01Ts(XNLLy=kQZjO76qL%TsA)c8CI<`kQd~J8 z%{!SNtL4a+D_@}kMcyk>tW=qgDwL~K<&!$K>NWI})Y3Dk>>@PT%z?R=^IX+BkR?*q zved0ZH({7K*6bVMMzEmpideMPck1^RBmy8_syANSDDxIeO+~fn zhM~FQT1@j*Ql?vtpc4G7yAo{_TH3}@=5~%4cLjzEQs=qqO#rGL3#R4pTPSCMG3Ea* zML1*01dA}q$`M4St#+@h*1PzV@zsiIy?rx)1t1fQzhX6VB&$1x^dVd_#+AgI1Qqt7I}ol=)R{bw zJs;?Yn(j6EQ>KgKQl|!=t;||YYbo+m9}fU4W!U0(p6PzHi^&y}F`sKabIkyq?VYRBOXReG1T4H3 zsrA#B8dE7Obb;x9>`iHWryc$DsVJ1*M&W3$0o_+VZbw#8sb@YsSXL>odGfr52yM2P z&@t0J^5mItLsvSpkz|kviha-2?u(Jl-^m)2$MF{O&_>nw8I zF}ABHw;HYCM9G775$9MYgU;P69i##mJ)=-{8!3y^GBEt!tJ>Ts^E#%2%3chUsP<7G zj1gUB%1bH8eKYuW6`1xk`%7cI+T5yNBcTDA(j0KgaXJZ^!k;B{21CooD zChoYLjOBwWv}V!T8bJ0?O{2y$pwP9*Dz89Z$<{g9t_<%3P8-3Ck)LxdyNKWwf?ZX4 zQmhMWe)%}2+;ogrsno?YCB4SHchwD3$>=t&F!Q!2otFNr>)^8^O6kbyV>(sj-ch9F zRo-oYZtG^`%bukg+()LC9|E>?j|ucn7PdvX7y9-yt=fOT#tX{pGp!`p z$z(!u(kD}PkvXc(aX4M(NU|?(2#-7>6)uGL zZaoOGC4%H@3)Tj@iibGqab*;zMoZHV5XI!l&-~UQX`R+8pSh99jKHi48o99 z2xzj_9p!CKrHC{{1s2FIktqL(m8TeApCv>!6C_*AP_;b z!fZhUkr1#gh*oM2tvHEB82HpJXM})w;eN#g)C?(7__wdRifP zx|XfKTb9SuqO4LXRcS&@%^__==)F!a)!TYd&sJ3}k9%Q)EJeMgWf+E?byiAOr!zsN ziI3`dR6ToALapq+J>sL(k8j4dL0qotjf19HbTYZmhd~Gc#ux!n+<1%bjs}j194sWb z&cc9{fXJgkB(N5sPX`gO6T+Ge0CmXfceKp`6tD$_DV~w#h||}x?t6=S z=fcp)DQ=Wks_QE$b9+y@^7FDJ+}7uaQqullOoiRefC-BeNyE91sz4uvph#XCsX^+> z*V4`;rQ_Viqbdv`c9EZigo>w9od#@Dp^lb4EC;rB98>aO3yEZ&Kc{ZzO;gkEnI(3$;@mD!Ah3REJcTK~?A6rN|%K zqPPpyby522@%DU^j^#P>bLV$lmjGg~uQh2aBW>)Fy6rX^}tnodu9Dv#tlF%v4O+XAa!&#K}j2EY2qzZP!V0xL^I84 zrjaI|wuC|)DIp!^n1?c8iRfe<3xwi{5a+y>`||DS9ST)(I6b`JCtbd9d-e9%F5U~4 zFMhBi@BH*+U3@7%l3(BcYD&vXh{+tUc9>QGKu>scQ81&nwg4z5h8|Eli9}6^2=D=! zz})C=gAvQ&>ggOyQOnCk4GL(Qlp3wgF&4!lXo!7*N$y;`#yC)fU_T8?Z4-Z7*6qi< zM|>r18nxdGRf>8LFTzq*^s)oMP-3gNpAeWLdeP)ORFaO17gKA=Dqwo2M_~p#57-$j zllE7F--O+B&;!;F^7V-U1F-fXq{hEc>MI&VCiXG`dtsJE1}4`PQvJ)J-$WL zrL4*v^_)pzwU4oFf9bw^csiwvck!y$$VgPG=Gu*Jnk%l98n>VgA+_zq1QUuehSTgR zGT1s->Y5h$m~Q;Aizp<})GCQ{S&`?d8X!=+uJ0HRClJ-~zVDxo0CES4l;biAf+{fQ z0dLWBo!rERI73V}!fNlvwhTzjG+AeCMR5~8JysmTQcCeVhEP#tL9utbD_ zAM9eq@h#gXfFfnN>~ybUmT?{izAko!Y$pKH`pFE#3AEChJB@9Jka3o=&BD__NO(Yw zb({c+%+`}q5D_r|#(*$BLT=V7Dk>z$O$OC_1;YjPW+j5u(faobpUuyP>!BnA)0Lqw%~ z7Iu1|H3J(Gj@#tKm1=vq9|3aUghbtiK;Y^awb(fa3D<(Jco-zdmEkLg$T9dRW1+~j z04u=a;q^tDe#O$VA4h4-kp+Q3QA!M1W74= zPhJs~F&woiB-jr#;Sf>a^5$*1AFj`9n3H?LLEm2z-BZz?WpC(hhqrrvp3y~;{*fO; zL8O9Gs!I)c4zVn&R%NiWYaC!8Y^HOc*Dn?McNSi#iJD)KB6rW>sCNqS(Lz?}oJ(=~ zQFzE*XFA(Xi@kcS(6c;5E(;m;!wV9or+C779()e>{v!>l7|Uw4**bfXtl5xUtiR}t z3CQ!0Rx0?JuA7(qZr8LjdvR%bl9yZIoa@85X}}1}S9pJS`C29_okpWNS86A9Srh}C zt7H*#Osj^301K~{D-)cG!6+M~&+BsDD*EX$m~wLIdRq7H z-|v)*q5NswKO)4~&#bHpJS5Lvizn~X{r{2r%>S1-#=rhxpV0X2?cZA9qq*$3nY{d; z)Xu%V4-DS^cNRpg@k&G(Fi}GKohn$1@xXzoUWhLtjR*1All>JxmDeHE$53U@j~q6+hxZFIFKcY3p+mpuDVf>I$<~Won&CKV9XJ z!h>gdLmQTR020wPwzn$M%B;UTIYRG0kj;8HnBSik>>?kF0)fDXYlW`zwEAw!zjp}L zd)^44$9?Gb*NA- zSrQnjl@X*`lC_?7v5YWzHV(Q2XEeLz^&bs&Bktd9LHB@(%#r8VYyt-2-l0!D><=GK68>aS%>BY6l~8Wkx{WhDQ&H9kl_>cV7n z_m~wr`K;+Y2i$N=KiX0^AJKj>PGK+{bxR%@m8ys7L1WeIQm|8vlBu5Tk8I=PO?j=} z?YJOnnn@bTHgeKOZL`6`D7eXB;wq2D(HLaQmu5NFR{xJcjLY1H!Jblm9|c(1)8cQG zVy(WtefYk-{y-a1kpJkziM`q;)aEpjHB(cYP6AIZUineBiyL^%a4(>f`3xKd#AVpC zYgKRP@dr~Zm@L6v#t({LJjYyKG%GF05pf5TvzZ)n$@Z^-I!t`~vkm51&^GX{n!SGsrek!I^2eaO?(k9Q^((T+L& zl{ljvF5JkAd>q)wf5?ktGySzga!bZ}0HY)yh>#r_)Uza#vXPkbOD@&soZUi}ydjAwi!$T>X(-7`A=`t>!#tWA1Q2#Qg5H?Vifng8f=iAFB*LL3>1cVauZ0ld7j4S! z4hdQk0Z?i;J|yY*hs#||@#}7<)ZJmT!tqsT4gXcO=DU7lgwY>nBHcmlzo4X(WeUP5 ztep86S_?NCPt06$l##^^>@L~8DwacJ1~xC|hPTINTC@D#>{Ot&SS0;Tqc?5EDcp}C z5q)HZg5JnWiY3c3hz?L6W2@N`N61;lMO%Bzwjp8$D2G{6DF_G{1VJ-T0NSQbZ$70q z%Qq?m1us@7EiXyLf~tND@q}ARK3`rcERTVU0-*#!q=+Jgg2X{lZO&9pYoWc~M zJXUsWxBLq65(~VJ;T1^h!eAjn^R#oQAjQsbP?gIn^*3N#6pN)1IKF@~%%3P3l8 zqDw&7?&w%HGFo@j5NSJ5kb|-|R|Q|Z$v=WSNGfbx5$@HtYf1BhvWtxHj}JLt>4EdvBbVS%rDOiQ0T%`F(z0Dyin=TD za<_YL9;)HJmn-gP%vzGv6_}EPwOWXcb;E)zjtU#d$pY0v{;M0v+8s#ZVe=QBz;AVQe+G^An*mb z$Rv5p$ilQ^a&5He8fP(Fl7Z}sxu~nO2;^5*u28MJlZu%4p>^KInqVp*SCRoVL4A4Df=`5?i2OA z8Mg$OFxT~mRVhD*a#b=y6Ewd-!SD7bQ=9**xv)VwHVDCq)iaj~R#AKItM}(2le0aT zs}w!fa>*rh)GfB#9EqrtN5?3Uswl;;AgKr#Vro&bbtMRHH*+2ZP_;5S%Jr)%>dP+$VPF;gsX`N{~5hj?e`#ek!@f>tm zINKFlU~~4?+i3y!7TPDWC(DFj@>Fdj)w*hogIwk|21Ye2Xr}eb?KkOESQSa0yekFt z)^o~Miqy)K3Tx4;e}ay3J+ zSOcnIj3+0!U>JE359NL8b`q%d*152xX6IFlZt4~{LZah4gKOK0OE&*JER^c@xR$%i zm7FWfj@T$_HGGgk+8hv8YYfBP%6QWFkKE)^I2`S+n?3RAu%y4RxAo16`V$yDou2N@ zpM;ZQKR~B4as7lVneO@*(;+QFhcoh2!N`!SnAlaW6b+3KYyh#487f~@(UH$b#FG?} z$XbbkDiT{?BPM0>GTh>zDJ%*wm?VdS=xJ^&Qw@r_q6TL%`Eh9*0t_!k+5pKe4GKRS zo1Yn>CB!{nZj(Duz$IUGz}BBa+rtKDP%;|--Gi;Y7doP^X2}R0 z$kgNuLbAAaWR>oW~7I`>r&x>Zh^cK^-%^lliddyy3wEhHo5 z{`&zv>o=VR3HEF%KsI3-E@AZ@*aW{8;e}t-^e71_>h*3K&BMO@S4`%MI7$(Ap7#4_ z7To4|r`c|jN+gQc?oOC5cp`Kms4!OKj^EvyCd0Wx<4iL~z+FRnZz;M2T21c$wZbK@ z6{C&sTZl>FhhC4nW$iKTw49UNm&WjH;{a9;1Mq zpf9*R^PJrYDC<%T1hax%4H5M) z!cjIsY%Ho9O-hK^xSW(U=k`Qwx#V-)4t%*I({$WK)mhhjrawbhB2KV*qHOuuue}4hS)aCGI~I zM(|-QFXP^zOg#LGQaC!kxIsfHFOTe`Wy9P46HPXup3hc!=o>UEEiCLThz z2dO^`=~Ug^VZ{_ire=6;1!~F}<=?)_Q6))MY`Di{G@1svqNjj8b3z4O0O>sdOmIja z2uAZZxH59p&HL`62F7Q6i22oUMsIYPyoq5-lUc&T>|Uj}YpyZ%oKbN*d9%*K>kuOc z;P>3bT3);6$m8-a7cjOfEA@uqgkcrfA~=ds{lD5dQ`150N!TyoY6n7RGNHS!4&~|$ z#@j|PyL*_cg@c?>%M1nRjBef5KWL?jFnlt_vrpO9EYX%V-@&nBo&_sX={51)RlK%B z?#}O?Dg-j(c0tY(1=^uYVAD|v*mld`G71(AysTQ=$~KPz7gmV|6Krje9D@Q3&IZFR zPJ%wM>k&|-f`FE6=cX2i8Y?sW#b)zF)?B3V4wmb30GX(&pmR}chQPq$X}YrG99gK< z5?sZb_#$KgOV#i=jtvbatjMe7Yau1a9JPG;wrrv($5x6HYn$)R&<%y0To=jvY8q(6 z7Ya|OI*bPVPO0F`g8&J#P%a9)l8&pSamn2GvgLYnz#WjIc~ro?lm5>6{fhw{55#3d=C=I z3G1vFHrmE@R0U#}=?=5@DSYzOU_D|pl^hdrH{ zv6AfVB9rk*hX&?H)?K8z6*f(lWa(le?v*=(cE*#BDIx=o4}wqv(SQin_s#~DZ z!EEbcB#bNFvm!$v82G~vjX!A0qecA(?W^{n!s)f~LPjn6*EzBTdRMlm2r*}$LvZbaoy>Nfh`!9)pUZCoQ$X|3s}tJfIv_9sC+|=FeD8Q%@|+SeXt>1h#DORvAA%2) zxnjzHe6NsJIM}(l!IZ+|I5UkNXPwZ+6M-S}Wg8l`VNq%YPg|7-A7;|1Sy~2OiYtp)cbe14zZ#_$=7zBh7{Y?kh>CwYr(PRjYv&z;IsBas_9Va*T{~F0X@S z&#_a}8Pyo0F!>$Csvhw zV2}H&Wn#scJ!0)63b6o090-dabSQ9gNK5R8L6abB09q(}c1=_Sr{n!BQpP>ZLNN8a zJUz{g?Hj;u13s=RyC$oBVswla^wv`C*&J*QWoE?F{PxEkM%0Dx8ML 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

F4X6 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 G;Qs>-o2{w< diff --git a/misc/DejaVuSerif-Bold.woff2 b/misc/DejaVuSerif-Bold.woff2 deleted file mode 100644 index 655ac569759c0c53bdbefc1f352df3ee1e8bbb5d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 132740 zcmZ5`W2`Pr&-Jx!+qTcPZQHhuv+c8O+qP}nwr%sfpYP|pGD$m=Hfg##&16z{d9gnL zAOHXW3?2+X`A>q`9sQ@H{r|K7w*MFWVqz+?xYz-NI8WHPQGdYI0D1I~L8MRtFi5b_ zu>*kU5PXT`ug|hD+N20xj>9Rq1c_k`~g_tfvQSH^@iuNmNqfs+d| z%Grx)gW%L(;;aaC7gKZh(~IWIOleED;^k-{sh3b#PSxWgfa$Bj*0lDg6t$7rP#6|X zt0t1#lBr0k2vxnxUx9t-4L5wIDtwDhhHm+(bkj@eBe&`=q#+ zS134Xu)!J$RXuSPB#qJ*$&1Hd*S~*-r1eeU)E)eEM*48GF_|7Xu-HI2{}dGcbu}`S zch4PK3rCDUoD+q#*g!QoRsn;NpEg=8ncDwDGxai6nJ)0c zD3AR23Vr(!(4t5P_(EZoRgy)~kb!=pN{A^iEyD~3oQx!>Kd*vX zMuoDG3|mx^Gg@5?_Vm&RjYu0lHAy?`{>DLPD2jr&W&T==zzkc8&4x{Z{;S4g9I_E~d|(RZ^9F&k8{QEIy>7VscWcobS1dAvHnn;62%ql@01&Rq-R!!8Yp48A%$Q%K4xQs5b6|&Bs5sW1C zAL&5Y6OqC=oe??-Xeo#Ki~LLNGPPlZ%e%``9nVN_5X+_1Z z+mk9x`fK^quRYhpCrC8?{HSr61QGYomhyh)l(XB@LeLD~=l1U)Y0UU{(^$%2{ovdp z18Jo4Vrk#c;V<7ikz9XaLak-V%X)Rd-mtix|I_(^Ka<(sTwW2bPo~qjM_ehsM&ho!gP*AB z=?p3)o|TRoYvga7Mox8ARieYvT`i1?VIR}S%q(YBQEx2T|!$0L8cz!h!7wU zmR5KNSa2NLAkzk;OKp*OkRqV~#e(mZe@OQ|wLQ0&>KC8o`e?uAjaTa5#1~cym7>Cx z%N9W9aHIr)S)d#IxE(j6yn7)NXOFzXs~uc}u@OS&q|CQk)}L!6}d+4H)h@aMU^hVr>N^MB5$%5gB!Q*W(7e`PLrot?HYU z)Xp7Igm^nvfwf>nqR`?{d_qDYSVTliWI|LBaETN|ElLb2;QX*a-cX}r>YO!?C(aIh zBVq3Axj`pP970N?5X5Bq5NfWv909pN`>%mE*Y*_dWOGThvFDi;yq$I6Ck|0pGHMLS-SUDnhdLd7a;#|oiK!~kR-jtvC&BgC-Ox8Zm zSR8;%|5Yt$J1opqa*L3IdZwFy{Ho=&rt2qPB=P|J*u?)Kv6V1ubf9!8fX{+JjR>z` zZUjjdU~sso9^3jN;5X+_tePRc#*m>2V-O9p-sE;Bp_9xzxbhs!a)u|pBNOj&Ixt46bx?cn2b8jK*BCnGEbb@hnl18UPanPNhjQbhO=V|hLq6kTsW zN`?yE(f*GEF_eZp(eiwpG%DzQv7stuuz_|Gc(xJ5E2$4vtZ?2!q|jn>TT~HMbiPzx z@rf#;fU=_nBJY#{0G2lgz(Pmd=143LX>9&7c?LO0u2?orqIlKD-+n0MYOjI1t01Sz zq?%jK#^r|LbJ!SmrOVZtP!r;8l1K#_ zm?%M`1=b}jioD>Mu)9z@;)3l{AE@8U8x9Ke4C{=eFwWanu8 z&(tEL#F7i@>026@gajR6M1*ZbjDtxUQE=c(`~ACk2nvB2M@cOxVkGmD*(|&Hnetsr zgA!-UKL0X#ochQxyuvX?6ufR$kx&`RAV6TKjEvlUM?cvp@)_S%X1la1p|`YhXVB^= zmJl_TMpRjq9d)?&&-paUb!&gke23S3TQi%LD=VF85t%ICq$zIxEg6e0`g^f}*zL8k znud-kxJsC|3*-xltmu6L0Pr&zkgQDHkj}bZ8=w&G9}eO#5NCTqPGi4h<5qu z6MFhXx64z2Kd;a)ZILNNMLRHIwi@qO9OGxB z0VQV{wNu~0Ii*dX33q*z&|SfQGjz&{s4Pmf6?ZVUDgctT6@(&Jg=p6SGo+P1VARMG zx@@>9S`0#ISuoVu=qKBpg^qf6T+;IRl;a zaS~vCXE)7CyR0&)-~P)x{`>t)_DELBFut!{BG3Z0n~;Aj z&`g$z&8gB#2YU^0WmHJ+L?}Ov>zGZAqFOJ3Sr4Q)uK2*jaS~Tgi<8JcgHmyY9t=)H zpIo1|%N#W0t`yy(HEWhJf}(Xx5qe%P!R!!`~AJ(#MxKQ~LPhAL2h z?NP72==N0IR$Ye6gN9?Pm?sV+7e$mkbn(Tyvv&nru=HQT_s14i;_{+wbbe~K8;Q&t zN-nEk!oHNF|9)Q2ihhxK333Ut7z{szYp~e={EfuZkHg!5>1ne2{Z2j)CW(zaD0)~L zd^>$jRNdv5OhJb$heH#w3yZYHJfia3zv7uU86AT@gjc}Px_2Ii{Nj^c75n5|K~9}4 zqA9mO^;Pq_Az!Usrnk(ymUe~4L%t#Y(Do`_;lj<&LW$UponjaHU(0LF=|++$ByYvGfk{GP@aC67Vm4 zm%X~EvJ-YRyf!+GD&gl=$+l9Z(2KcIkvoPmc#dvbM-}Y@n9Tcp}Ux%!GMHF31n-byF@asdZLCLcC zkB*nS4!&rB{jFtxKVd(@UU#Dh?wf$^lYFoE>Eld?-YNr4)GR=e1>TAf*|;w-+kJ2p zl(DZP05neFo22q~JNGdH3D#_tW{Oz26E$SCB+37USeNR;(Z!}A(z2Ghz?b8*x2ju(C@F=_0*UBUq_K4H6%qOMb-Ip5toXKGOn7! zn9G^dPy62A-x{}dFFhPNkzfv_7?K8!u>TMoED|ijeA}DrwL922{YwBF)!8Y+js#Q3 z1f4x!Igpk`2rr&``;GY}`w6q~QEeM%AqgyK4P4xDts zrEyiX8~XKON;5BXS(vQ?7HR=aNklCOy93qCL8XH4nN9p{$LWIz2?+rS5ZDvSQ=mjY zoAp*!7b(x`zGc0W1Oft|r{V&`#013zZIS~50-C2@fa8xQ*sLTMAs|O@e%=QEf&el= z(rfE@0s0AB_2Y^WZ|S{+1<3US5sDEm!&LNS1TH0eLRM5RgOq1JBb3>x^B3K$Dl5pY z0*X$g!7Ki;LYJ$v!dEP31TSf&270Q^20eY%Lt;xG;+b?|lH}bxc>~9`I(IgtGj0+x zJHrQH<{e83e$(@s<9RO95%@AL@J^wp-vwa08?jfcGfO)bb=?a@Zihiv@x|o7KU6l= zy(xS%C%*d?jge8?hF*N+LhB|e)uGc^7qbF|2UR}(O z-CF%K_(kg#^|UsR{3jI2gzqi6LIEjcQ8HI(@MHOf;2i1~gfitGWD2R7{1G@S17*4K z^#{*rqBx?(&bY=$$4P230Mu#PhkXC+Mi~W^kem@l6ljK=l0IUe53#{fiVNMq7 zjn*fc9}yaoG6~{ESD*)NX;p-f#)B-W7AhAH=v)2=Cup|D{u9w}Ex{=lKR>U3fw=nU zde;i*%-)@OY?y+U+;*e@Ia)`M_TxwYqPhqj8VD{kE-N%XTU@NQI0fc0)3*{41)dtE6ZY1TGxVN`trNYs=tv6Z-NEE3ZYZ%}5hxP{0We_HrtScs6W1UT)m0Siz>w|aR_SB31^%4c*L%)? zh4&_0nG9Mr|Ap``&8fUPw*AHR^F->w+jKqV5=&o#HMibo^x2yznN4QWO=s4TS8+oF zLhIeBL1m-PKKuU?#A?l?w;c! zw^~|Zw^8#%RH9SSVcE$yloa_tAL|WzC3@CdDnAE8V&ssKzBi4migP24mP1dzr#m>1 zD8_zRm@0)562pJs5LpiWaIs&hqFKM*K)ZbicbBt+i<6uChoD55f=pS2|>#*EXLowAqx*@AD6j*M~}*_Vrx)SN@+_Z9cAq z_;Dj=3txJM=?BXH<>BY&_TMN)lA<6Ql+u!dcqn+rtiE3tzw!YP6DieyMSu?pES$&4 z0UW+C!bR}kC28S1*;tJxDSmvXOWizt=KLAE(EQwbC8-?M`P_29k$%4F5*!bYkV@7f zxwLj&-Tda!yPbV~oqeT8mG-DnaqLI4_ZX$?tn2DvGR3FV#H?q$v`nP9cWi z0ue^1y%_-i0BqoXTyv+nKsAM`H(*i913Xms3s+;sfl_I1?A2(XF}w#TYE`CmDsg4~ zy784h;7dlvz9Ec^g(bzDuqw*D4B#NlU=PID6rwj^M*0cn0IRpKSY>--&|4Ake6Xy( zau@h*N=UF`4ONr;!ppI;XF9eE*IXBqWuYsK`xeo8Bjc8lI66gXNl(@%bp1>Bd)WnG zrH}$yh{lR-MmJ))w4jqHVwecJ5Qaz`_BnPli1UEd%db2e)tf`eINb*ILN|ZX8W8 zjbIqB?J3*9wFqf?JE;5!ekYqsRCrwK{Kf?SOM(@{bPW;0mBUQ39KAj+{n`OiDi4tL z%P=QFL)AsvIR%&~+X^M+!+R@i|J>KsEavUPtCWXS(jqEI6l&`<9m_Y5RG8b~+R&h= z!3nWszd*jQSZw8|o1}-ZZ;$LY+){=*4^q=Yn=?`E9uL0W-lJ`_;F#0)Rd+`M?R&j9 ze`K&*lEtjt*31g*9ozIM|G9Fw${n>BCK%Oe45I1mgWPewh2wm>j7|sNjvxHl(4FnJ z?%yagiYyW@rx0<=fc$6jUf#+2q!+~S(RyL0apUcDGz_Bp`iKHJn&EN~*F`>pXq-;w zh5(-eamZQ@oQOF}4N|*(dMsV-?Bv5zY$REY+G^P${sdTvc^eU`2Dvyo_8el8{tGk_ zq4qsDXwmtSqBIwx@j${nS)rym=JmK zY{K^z6ObZF-6f6qGvz`DlLWH+;}}4=H7yd;)VtaIs%^IMZP>sZHKV4Pps~~q8ek=H zbtc!b^{`uzi;VV$p{> z_y(LZWnJT?_h;j8kDGWboWQ~v9l`qcyt5FA(?D*AuacF3C0;R0%7aA^L7uixypy~7 zcrs}Zp59_CqdX7K+UjIa4^IXN)y~}E&Lex&YNHtiTdUQFo3Q6j<>r0gNs9`cbzTkW z4g6CGQ_^v!}iHmEj*8^~I}LfTQK2eyk;Mk3-{`QuV; z!9ZcUm09Df$vL(|=Vi3!+m-vyz7?dz3Y({CsftQqEwzRyW?SI~4(Jl);hIjk2Z zq%E#>8V|d4H$72Wz8h?ZY(LFEFA#WtyqePycWx;TTk3R8k4}*5C`dR)2&q zOS1}e=v68@J!{G?oKSzVZNaRlT&_?;F&+KD=>~JWE~9*)IYm z*|%6P>&a?;>Tbk;S`0K%(ie|kJbY$mFhnHPoce2g*M68-yeb1S z!)6?!u07NOD(`F2qHJ4+8u0pi2@GNc6&RSr-~CRTdFJjMWDDJA=cV(?8lXH_{;1B&7gDXUDqxg%mw+usNspGOM;Lv@ z@n|h+sT1qZbZyrs(CN9=+?4D=@nZP;pwT#~_KuFsn-lp%wo4iuYA-G4^=)s|)_%A3 zq;8RGWXNL+4#QuWvGo>pkW*eI^Z;+^3-0=$sG83Tc9hAB{IhY418Mw&IAdHD@bjfS zQ5DiSeII0n!~mp^ZRaP8`t+SR%{MnLqOuD>+N%-wCE*mvIB`X{)ooP#HbI%YF0Q8Y zU@m^3?lI_)4d1qrCAHT&0JBpSb#9rK^v>EcY(lH=`E7y9A@aAlME3 zh&=`2z$bXepFoN8h6qw317=X60`frusT16f!9yxkA$b%x4ftW~C!j|qfgqDb3>h<5j$IDB+Bc~(n@R@L3bsmh~a&cZc8~Dpcqd@NQ26JkPREJ0wTW}^FSvgMvD*6vv1&hT(0kexPyX`8%Aq&IhOF}B^ zq}$fZJ4_%F>i;^-f9*v@mYr_Xk=HLP)wPpb#~v~wk!3Qn;bN3O%>&1m5cD7rGzf;T zC~gpvd24JDReIW%PJ33Z4(+*vhg$4-H{xfXX*xZlYsJx^fZj&eW4JeRrHr*=25T1Y ztW|BmhuQX?Ucpb=lht&`qGR$myNQBbxubYXMQmuN* zKhp$0Il4@z7pvd!DT{mTV@20}c*f;d?~8uQTi&5!%F%wP&-*u;HPZVrn>iL8MKf~u zz0GGrNIxqMifoU&9y>{3%rEx|3nBTB?Z_Dq@t=(+Sd3Lm{ngIRFA|m7TUy|DuHdUj z4pWx0T>R}=F@TYVKTGz_gNUoR?~}IR-0`Z;z7m+yPyLzkCXE__Rl?f>aMLl<7_B_$ zGqd*O%cp+}dG1~R%DW6tS<2OcZ<)D->m~e9;x>jg{cZ+#ON;gO@j33E!c$`8TFy!x01L&%iv)JVS??I zxCKkPjm^~+E^by+`o3@6P zbhjElmG78cg-m2Gggs2Ge8dV|toj}_!-1(b)VPQSeL_I}!?lM&SC(e}ue zHD*oiefy&OW}&{(gvuN{bh2>h3|Y7jLjZVUzG!bl7S74f(jL&5&D{$@g-CLVG)7K) z<9h>L-LSok+a6)bsV)c`(1A?G%z4I~O%7e7VarU?I=GUW{`0B;+=@i>ibi(jqbrmR zF=?;4vsucO4rgOyx#!7LBB2k>+Gnh2plYS-JUvFrjIYnLhL3#qcB6StPMEXvg>o zvfRjbVEQi69?X=`V$*Yd=+u;B)ky0TGkZAOvgPI(w-#NS)eZjZ-Ilo!uIAE?n%Ac< zpQ+bQ`mQ8DCb-5kV2k5sRkE z%S+iR%oSwGg2#%YDp<=R)dld%m*sd%dKUoKFfOrffo|H!DB;Xb2a-6-WLPIO497&C zeLx)~ykd}|@jn>c0Aa`h1%El2KgVNJu2ltki9ap^xsFPdflNHWR70aH9{iYaJz}2^ zn;M6mNxM=TJLp!DV)a#8#aOIMZzb>i=(JvR>Iu?YDA?%uFs=A@_^n}^1K+(Gv#kQ* zPhY#;G`s5Jw^pEiCY2>Q*Qs7E@;2{dqyALy6pvRtU=TG&Ivf#FWla-Rg{o?&74=*f zzRxR%o*Qp$7FObJ-UM7Fcu?%u0q;jyC1p8}-U6nEz)ZYQ(LMWAnIGqTp5dYMvr1?% zf4yW{Ofg?P`VHlAxdB-1foZf&4^R71R_C$JN0wtpc=ar zRT(P#O6hV0tA`a)p!9%3W3O(O0*LI9+L`St&;GYKlnEdUqabj;KBxsK4Elzb#g; zU%eiXc{snmbAO*K7mH@H(@V2G4`?Q)!Q1u#Fq8rST!X&b^{GFNGD>JhGR6r%g3*GG zSU7DZK5s19|RD>$NI0dbVt1Cx?Rf2mF-z z7Hd1Qibm5Ug&Im#L(0c%Io1ou&3c19nCsRKSD>v9=}eKUy03TXugqUTc+})0!7QBU zPagFrFtMZ}0URrD+fLl= z;@BSFQcfoRVR$;e38bX~z})5>POLD~o4EQt_z$PI@d5$(gOhh6ErP!|6V(UJGTKHr z`K4LBuRt5-`ba*nuV_D&j%5`?%H}65&M6&hb@P)ciG1{1x_dy@VeIzm`ytp!Wc|S= z#b(LYb;Zi1u^-Q$M_JB%oqK@{;JPo%Xe2$IH=e#b4LS!#vp^7E#1don2SeYkONzf` zV%4Am+2C>?PmYad)&v;z@D7Ke2wFKoX=zo;dYp)v6OIRNP_ZDPxI^~Ah)ji~lxamG zlRhQ1JZ2!4$t2>Ja}I2vF!xGjjI~Ut9+hjHxmy!U4&mDmS#5EBmxPl4AQQHMrUHh~ckCs8w&nl=V4RNcd?Q=1`x^PuP9RUST4rQx~#Pf1~9N71n~SFtW?D~aCvA^ z*1^PjNGNXrUw2j*Oou^dzqt?z8xl*bQEUO8jz~IFsu8+H=s7cw`VHIS@bmvMJeFIj zdhGvJXQ$_T+HxlNyD!Se_X`3uPLaWu@$Pw`eYpC&D{v0CwqDF`ugh%j!*#8Ba((*o z^4Rj2&^n&g3F091v_6pjE8Zn-b_MlaC$LhYLi#Eq)_t3ZnQ{oGcwpS-kC;GQFG8J2 zlSB2&3|slp=SamAu9!NikKVuE%F7BTPMF=XG3iq={aJl+THsLOSA-UK=#!fdgJ z;A~d9_^?7Nh{p8!K7lsSM{RpZiX9adVB|LTek(0p7b$L~MFu!7CPgv-EOL;;U@aX@ z7zq=Y8F!Q&l4b}0A@}ADqNa1wtjtT$mp#PX8<54nXNK=?#I51M+-1(+N6IgN>Yi;K zLD6FskI=io&G9>)er|NOW(V&A%*;B~tYr315?H<&f1ZSOsa|(lXkpsk$u?G*ZS(u_b zm~}D}Isp2Z6g=rs6I|aO9kI`NW=7X@k6=9Lpz#i+fGOx~ zvkyY?kAzM;vPk8iOy_)~yKPtrl1DpaACiU#;<6U4RExA z(-L+5eo&Eru_$3a?zcnkPEB|!T0y*+n%F;P_(yJt@Dhp8zy}k9dQ-CliSWc$Pa1-% zmQ-FH?+t+9vd!NMPr*!2qB>t=5vEtY_ZrsPh8eEIyWLlrF2QOWjlWY?n-dDt*Amb{ z)`{v?FKB&XmaX7Ik_r%x>=25lxiY{K>lR{DGKh;G7nCIb{Q#O|sY?=mZo{+nttQ@Jtkh4m|UmAeiTkf-S~;WhZ!5`)!kxj@TN4AmO-)uV*d7y4vh;f z;9Q|^+&SwsP6F(WeDx6b!WA1(fF34E#7SCkXU||BcqcZMf4ilW(x9-ZO7wER7BpiM z7BZ4bo5KjiVEXn47-1PvbVL`8-8`7iy~zattqof9>;KxEB`HWj7}p@$(5@~|7eZJ( zk4s{a5ICT@`44h#^0qN@_s}hdZG@3+@PDPl{}^r0eaGUm7F?wR^0WP!Qw2-6uZ0>+ zx`T7~^TUjWy0!8ce$y;?urI43`>A99H5aT>W4$o{^lA%rDc*2C8x87RG`kZnOKOp+ zZ`$!47E&oHcGkSUU6Cowj?C$!zw2AdZdW1h~E4Qqr3Yj2Er00{f z4`2d7Uh+^(49to8uaH62shV)0Yd#F&X^b__k2w2hX+1ZNQ_pbM=rDs;V0apapLCV< zA&g+Smazh#02Eg$lv!7Nl;S~E^|pxPt+bmtIPCPje1eVTX%RqVt^G^MooYIZ$DF|f zDtk8q68r~{5{PI5C}+!y>4S<+NP{ciadM6o5P=Gmt1l?lAa|2K=?EZG>E8vqkH}fT z)^9wmO-g0f;vc{2x_S*Cvo;;o?d&Y6IQ5kdvRO8fZezQ3*#Ff@eJ`;L#tkH;prjZ8 zwXp0XP0BDR!xmtYgMc5oeL)2?j2r=etCu#)F9dK#UB?0q zV`*z=1kYOnW-$?I5Fni<>6Hs|lWjc|j-+%ABf_uBKu}5!;^NJ{g+p=vZ@!SjeNuny z?wxTXdSs`!5~{t(Ns)HxZ~d`$4sk7uy?iHP!L@fzCn7Qf+(%BEbk?I%>sJ#35q%)5 zlq{@n_@@}S*FTNgPbj8p5P2YkQyY-XtFf-LQY1~i)h*UC*TpQi*2_P##!>W`$KN`e z9k(dzkdvmE!-LpA!SbqqHSOh332LpKd-zHhDP+x-v*g?&^d|@9u7B!2ac?_U_p{`B zV|Ekdg?OknZ$P0e3`S#&`FCL>+wqqhSqnX2*rIcfJ?QwSXKxSRC+TuN_FZ*mhZ|dy z+odi}i^Z-GmD}vL$L&tE8!wv~Lf=oBe7kaP64#0#)W5Bz2+kRn^$2{~&ucrM{$aYf zqGp0u4p`J7RZAwhp!j%uj{!Zi71QxwB|-=zZ8n}{x}($eJziTf z!T3wXRPyufxAO1^VLT<7K?{@vcA9-^RkIZ&vaP{j^6!j;o|oFxp^$CDi|ETXYH`^l zjyi@IlJxX|?$8qK)uN3~9LaPVZ?=HE!MxAujr3ld<62w2@l*IdXl zPdht6@{vZA&>xsV@q&9W0Kf~HafGvf^KC_Gl*XYi(Go;Kfg>nX;t+?-_QbMah{KYK zbRb-G&(71Cpg>1*LWlTaN9eIAnUm*iMy7m_+zCUHrrgt>SwY=Z-Tp#(CWeIgQqh)Imd6CrB!G;gTX$hE2T+8XplH?l4f zKoZj}re*f8$gCSc0gC#9f}`FCXRY!qF`K~7B!J7#s)!lmxw zl31n@O_ByhqGBOGj$`0K(pez&`!)6UPPCm>)Y(Xp!{qx9qELpr^M*eO>Ml{Pdn=Ec z?z~^>AExd{IT;S?0Lj)Z5Jfj#n|G z$!RIOC}}O5nU>mT;bU~v$~O2Ip**P5q=6K%Z7?|22|3gSeHSRE0zg0@>|dZUTdx^b zzyL6S3Zr-)r+#1SFmUyju3V)fLrFI9egu;}gf$&ub1U^swY&cq)7Wy!h$UT%MYm4v zdUQ72Ww>^-cK5fiv-ew4|Ll?Q}^`}^a$bob%?o*}vY>*Ls|6Ss2o))(*e)GrI( zp5TN4?Kq`HK_{sxn)h!GnPZL7*Ty-!HW6r|P51W!#;H$YdzDqggy}RVOgiF2TyxU_ z@JQnrb-j}&x!ZbNxOutt49*M;@nn1Rwa{cw?L~<3-l!vRjP&Z%d*IgM&Q)vjhp^gv z1tM?BIHqPdbWkHZ%#d3@^|yilgz*rVf6alv2ORiLnthaN})8Va|Yw3Futn?JSg;L`Yf;7N)6B z7=tKdX}Xd`Z~{)*8tF;ZsyQ8tZCWF=aa(Y`@Y2IS0!XAZY}v}*QIDA1UP0E8=CrE& zl0339CUXD>BE++)kiV2HwUk$>E!E5RS}M?H$PaqXWXu!K5pUop{AImxqhWYc%z88m-|(7#J9YM(}uJ-X;cZF{IXGBg_JV zr(3+}u1Ip5)V5NNK>K2e5hdj%YVxx82K_ri&D1qOCW+2c3~f!P6uQ7oIP&vGDNoQ0mNS} zBwQi!%=+fznlr-wVWeL^Ai&~I*6(?K{GT zy0~NpUh63_GF!4YoGrz)EJ9SonO+cDq5807dz}7|@d%97j zjgSfzQu>9@ESD8apCRk`*nMUH@(tSfsm>65;a}wZnqlQ8N6z!@5Urwy!VJ4X5Ut&2 z*02YnAPAoiP?|TDNnn`fKiKrs$r84QJ>t?-&EyrBh!h0(K@rwgI9iWUI5|=t?j*@q zZBq8S8upJr(EQW6_{)_o-Vk(cS2@-k*zjslAM=6dKnl-krVp5tx|`HX8w$eGgAG-I zBjU!!sx&D2HyypaWa5;zsLG8`C^wTg1wj`|Q7D2q*>?JOkwwxhxDkY#X<&sjB} zxNq>tfV&Du-W_i_n>^+6hC{1Q5}0)>Iq{B1!EjS9a5X&h@-ay* zgMqkqLDM=Ee2DeC<=O635c^9SdX zGLqF|%^vO>w46yJywpl5#+-B6a>?4&G+0TnKveB4U9zMqL(;z>W1nH{l+TQu2+tKy z3K8L}<(3gGjaO{mQ0oox-TbsOBZzG=7UyK5NwHuk;B5_VBooS+a2 z_>cvtokfYd#d3p;=+`$EVjzq|iw86~67gd)+xlj_ZtDKTKWkHHK|m@jEPQWJrm`3| z6FmqB3867SIlJnZ&e;7648q;MU7OMnotl0QJix*pVT@4k!J6iSt(9c-?=0Fiin|tS zQl7SBU+{4FlX&PeYPH&DuQ4#3*v0|Rfi7g0vFCtePyj=F7h#VrbZ-NU8=e_{0SyKc z3(j(6#h_Rx(Y3ElGbwgNiOH?(WBSyN0;10f71n}59eJ}$*@{1jww2iQ+;dgyy!X4bFjE z=XeTWf2gR;T=>vLQU=6BfLmy^GDXazQgQ-*{^}W^3C=WXtKNjIWfh7=K&+C=PIsL0 z-6e(oFzY-rc^W>c$Z+3x*_QeT*}q^hZ%c;L1aneuwSdqGJSH&*uSqU}^A#Ztuf+@~ z4~2Y}xPzDx2ytyBWIDH{1W>Q)gp!s2W`2-)a^D6KyKWe`dWIf%9p2ZtCoyhA-9aQ` z8}0!M0Jm|FJRI}Ia3P&Nl)mIvdfMJcip@^umqn{(TNu~Mx`3IZk7~|PT9hT_LSE20MQ|6U)vmwx76e9_N(w-pw6IQ-YWIgQ9JtDYb zdaS%d8I^r-)@Eha>zQxxq%0SfU2jyCq4+c24x_*#)3>jZMLmMt_#|Sby@*jra@(V; zrQyBUAy6lQq;n}4;CEe@FO!frzYItvOk|IUt%ic7Mf8$|GD;V%Yc4Jh{84rT)nNl^ zy$*eRrj0av)m5{72ysrZDxW;12SyG>AcsRMo+S9 zhb%U2ryUtqKJwcAe47OQB~Owk)1dhkxrni=uAHJA3L=g`KgFY}(Yh}BzR{r-IdKee zJi5{qJ&4{c>D#COH?pljus4UPIqmYsB%d`8y&7uWAxWWhdKE)PgbWThT26b3OgleE z0_YrlImwaRF{invFQ%@JmZW$<=PlYGFCy(pqyv(zEpBxW;r9%fz2QVqC_P`>g5J4f zVGm8Bp;eQ9w5@ae>qW2lchV6DS$-HUV3gYa2B$k$Cs6o$g=-wtA4vxL8p4dK6}`R9~pTC@-+P>me$iw;I%t5{T(O`sb(cA}F!l*CZk0Er;q)%^h=TQ>51 z)}-I$zPKwLCa9BOHPVujCBeke!Y^!c){S3e6cK}cI(VbU?MgE;d6GOjSsVnx<2oJ* zL+oZp{Esfi^`|0(iX{3htsSic5~;T|XoA8{o5CVf@3n+{^~l(=|DG~RV0t1($E=c~ zeZ%NXEQGCF9211Bbeo=hW9K>cBA z&$Wy-o}|AMm;#G54dFRJe+}ULy{(dQ@hX83bp^V%Os0J#fkXR+rN?z#_J6wrpc|v% z(V!;CxIh+P_upv+8^Z-r-&I>X`aH_~bOJ>}^1qDfPE-50ei zkfu>2&4O@U?NX-zsP+|lZ_UbW`~`wJ2-dW5$vhL|y70J=;wB2|D-+nP-XNG+|8q~p zOIGG);oNBm&Y2?*qTwnqu?X*;6XMO44j;69snj zXA8BgyouX%4TiYO`q86BkuG`|OzBFL!gmHdo7If32~K{>NL8fzFrk6OS~SgU|9m=f zjXTbLKkPZgTG%;6-Q;gfd^FEh~pc5Bt4IusH?KGXHB!pdFfsYm)tG>JYX3qy*?h7RHvEG9O5G}4g@%B|b&j+Kv!{W6O)KFmUKs!$ z1TjgC^OuO?4Zwqp!R?8i#v&iS^p8~SUt>2!c9(ZUl z^bf2INtW3OMjcsmGiG^!ep>!k^OruUdY=eSb3aZVS+A(F)tkATMK}|AGrrA}aa$P{ zVEGn0v21_%V&N&21Sp&G!!TVy2{Dz8_yw84h=deU`xAsdh}MUYBMjl?xc=sT%tkP? z8^Wh)z(Yowp=6avk}%_paf+U4!eEt|Bk|297PU33jeYR8Kc!+*U`1gQv4tu*dwN^6 zluBRC5ve?GPlT*nW9W1VXhSZc80ZQ-AV7sq) zO@WVqFriCccP%|g5t1TDe!8ia!x6i7VWjNuE@71bVKQ4Gv}=RDz7y{d&&5p}AQt8R zk}7ar+pD^rb{+DyQjpJDmJ7F{E_VtweU;5E=IWVU_ObNSU~dK|Qowvq!56cC*>a;e z6NSD9yAXJcTS_egNbLrl5cB!xYfz_VOqq=W4r@W0IIM(m8A{f+)#h)r(CIn>iHBfc zO?ee61Jd5g+(`N7cFT-rx8{ud;rQq?!n?)Iv3p%aHpc9Y9ETcghAAeY?FKO7Ue?6Gvi zOMkO_j%;szXJW#KYqboSar&tuN;TCLIW@sFk+SJoxnnl_7#5N z2dUTqjI676t~M`7Wz)_TW>yCPIT}YJ)Xhj5h`=gwn=SDfU7Ji8ScQuD|1ZpoH#MGc zccJRkNA$$I2bRpj{$laik^5)ysFqs3Gn3SB_c}EXwf<5_d2~GKPwVxpp4<4dq?lQ-Z9Vh zWX~BFdeXDsco4$Ps^}KYS0AjLd$WCc0$BDS_Q@uIddVI69jw(M#V6vI)Wv)|#Hdw9EI-X5&2aV<$6_pzJ3DQnzYzW*?zW`%*+RA z1~Y-#k`SDbP@={8`o`q+`zf!EKV-*GQ~3PN8BF$OGhr~d$6_oig~QQHNnRZ;P(D~* zlX`)9@&Fz=#SN&?!;!l%unh&n0CsnfTkGi++$PhboGG18V?_s(Y)O(x*!PcgL7OI5 z+#4c+(V*ekBOo#@#KvsLMKY&0w~RFez8#An`e)r*ekPl0D~1dAtKayRgOl_fV$GX! z&OdwVsW#=x9Yl3uGZ%eE?}yWr@fgd)B=e@hoE-n@;zYXTbZt-4L0U}t_=W`KB1Hzx z>6KtLZsA#ns>BUXmlzTb+#<_Z$b@Q;#-l-&-gm9+zak1XMmF-Z<%H|5?gC-?&^!#; zYz-yDz4F6fyJ;r62o(qbaD~NP{dp=AkXAt*iK?Y`BV27)YH4^DZ$*2*i&E@ese1fm#F0ji#w98nnuT&b1a0OnU`wnFz3qEt8 z&XF_e@-u25T>>g{o-4%Y=gqTXpWWFh7ct3Bm5IdmpPMW*`I4~2^&*}jjS>>qGDH%{ zy5~(v;w(T$LSbq-+ERXkkQA6>LUBxf*=tFzXAE}W4Pd^+&7D*$-T;@%z3&6F7+uGx zN&Ez)GG%Y4Q`I)pUPqhl!tX?H8z2?ZsDWtg3a+Qj3HL{&G&CMIK=9w;zOZ!zWm=NoMMZ)6Ig=Qg4p3k@WAMWs{ z!@K>JMS%f=Re{1Lpk#}KEr*pf`X6X@;%ldr?j{dlgsAd_K0rnLQsU9ASexFclOBtd z*ge@gZ`DB*cY>3++Jpc{DzmySSWo`y-H9wMq50A=iwI1RWvN80oj20<(UkVbw{WTYD2;lWOo)T6U%~{shrvZs4LL58vhELu4|ebc+)k9vQm15SJ=U*=_vgO z2%U+wMxOxnBjO8CLT0-tA{2bEk5%738;_V?%JUbrz~tohYqWd4bsQ6 zyw^CfXP}iq5NVJE47;YtZ*C-?NV@fHn2->z}0GvxX5=Xb7vUFivD-wL@$YVyH@^q+YPN}h|X?W z%CvH$!T~ixy=&*$lgmC8AXV#ewpiPVfb02L;IH$CFRXfgGIr0e9)yW?enr5nluun& z%*X0~@h1=R=lgaZ9g=k*9rr_cv)T;i0dk(f^n{V{O|*wF7Br+d#8|spzz+Pz zFz5K6W=*J4%zmp``^mbQtsJTZ`>ggoAEuVfn^EhF8NSt{Q--y!eU{6;Q2e12F;PZ9 z(Cr+%7If~o=0ypU;cx5-k0%^sPx5gt zKyf9T=Ov7V_Oh)(HsB%g7Yvspc-$k{TtPSNwYLJJ&)K4rk+%)In6=)M@k!}B>Ci1C z+6Q0vxEcE=I<*sObLP4|-D0yuVxa_v#1I zz`q+0k?&b@bP^vx|FZ89be}yN3g9>RLP_{Nr@$9u9()Z4R@%XE=NPZsmq8B~Nv+qd z(M#Q#V=E`x&qP0+Xpd$vc$@cVa$*muOB{DRs*N7-CyU13GPLJ95WMl1&`k4Q#vDE?BoKPZs~E0eDv!|+TOr;C7m*8?n5=1*Jm%|w4P zwcf-ywO$4_p~*uf&4eiPt%(88#Ak|)!Mj^3oCor(m>XM(ffw}{Z4DkuX2tPZ5hkF2 ziQ$@#R&qYHveI4I2%~>>_{Y?qR+9WLyD^7g5o|B|*l3p5X6Z}BSpl*-tbAJR@r+is z%D%JbaM>q;OK#$7oDiz4n|Xb3vMEW_&?OrCq<2AB$)+LwQi^#^#JmR;g)hRI!0DC?riC6&r^!OY;4CIRMgt}02qrfWV^ct+%TXLs5YWQarJs5$)d{;nGKigvwQFMCRTxpDFKs-X3u@M0Gtr) zwT6ODwh$`0gLhrBdx6sHZxiH9UCP=cT(KPbXxl2ScB=nkU!z-|jD*y#`{CTnFP_Yn zUwdx`o~Fo!KJT;lXcSbCd3Py0?P{TbWd@UDfW`t5TWGyhPX&RMWdFH)X*@ktYoKF< zddzp^WWDeW_mi*KKVZ&ummNE&HMLevb4KJ(%6sX65 z3$dkMsYxyk%q63Sz7WEY_oPSTlR5XFMaOELmepn&%_4&0wUGN8i;61E`^^5gKmVAy z+VsPhjJ8>=wbOQBJ2dx;5@LkQPn5W^$spZ;yr${3fG?J0{dB&=Zw8H8`#^+CW zUaPr*$Bfh8Vl=MTOG58shSZc#mO`d01J-BVZoq2`LhVH?BIkj2QdSVt&kt3-R~ujY z)nvIK3dLy`(1S^!e`;wDc>HBP2J*2(fbFQ~*7{f% zCN_ooMI@6L$7GF?Xu(CK`dSXHd-beRcBZZ%tda6O=o2R5lHI{`H<4G*AcLE`KUzt~921`0u zswqstpeJMpD@5&eP^Ynsi*WERQR;f=c&=;rd+NdeswK8o8}GQEb~(DHaLgFuu6~f& zRDvocjuvhzzsPmPH@`J*tc9awg13GUTJ=-{o`G1BL80g!ii*F2I<0qE9~6D>EcnP{@iC|uDL#?Mw}Cm zq&Y8HSV-HCKLsuxI5Oy`f&&9Ceqde%4^!PqSV+3DH9KlXb112aFFxRRYWi#vjpa^m zkMfHMfhP|0@-58ajzqStO_LtgaglwBLVFH4%&tPpx2hAlZ&D9w8U0KIx?U}z{ zH6#g7*#Vv}OO7ld)|Ay$fa#`HTFOmx5Q+_B=Ji^=Wu0fJybt$~aonSj@uhldP7ngn zY7OmSxtO1V@N{O-*kIpunN5zzGJszDYidgQOShHD|Iqwb2!QYNEx_*c4FWr*igV?V zJeI4*6Jl0CML83pW!}ag&zcO_7jX*>2*BIvu%w|yZ;-lIe}gVM+XyPGi^7m+I(ElW zt*JXJ@X5(}YKlx$IswO`;aPF%0P!fo65sMLfdkmp}>3&f+s-uF4z2L z)1r}>K&6@AHo~>THPe;j3*UmLBs&vQ`~~$p2ONk>Swg@v3~3%cM*9%-yor;Oit_y; z)Kv>v%UNU=PwAEwSu|5yNgaG8tDf1SC+Ld5(B2cZPqk_NGyQhYfKz%YaM}LZQMmsXeIgm z4P-{D-FsFeBz#xIeI`!_RK`s|)imgSfJt8b#TTFOVYp9keMva^nWENA>;j-?+8Lc8 z!{DV4T;4Z4F^#ya%tZrdHruj+|40OGZCUsWNz8ZX4MgVcP#*gf8+1SsBm<%7+>8QN zQKzBpQmEkbtAiAks3i9$u`v8(E!z{&97dEv%2#XuOh{xmeL` z7?1Rx}S2bc?TlnddgNgC<=WJws;qW%Ry@=ZQ zPu=EONP~xC2A#sm>x{Q5y;3eVFJlmaugYDXtT~yF*a$}D^HZaCdu%aTE5dpuSS157 z8pr2;@r+5W;kth_=Pq&1J~C_q#8WWYuiOAD_Lug z^^D(PP~eFmHH6f)H_oTC2a~%4YJeSZsA@j_^cI;HmH3l4oQah!UI~a+`wB)bq3x_i#>e+7_<3ZbeBO~)`c~9x- zhi}#>vS_JnPRO8S`KNKrP0EXtG)>7MvcS2Z4r+M%@#h&IIFF~GN?C$qAsZqNJ#DX5 z)4@^@8jl7~E$h`egCp^=iR_TpU8y{%qF-Sbhtz}GGg$8`WgPvD-4mv@aJZWTnWi1v zUH~jrxfdiyP#_gJV!pvsd%hWoHM7ds=Ju9kA03})&g6kizt+0gXMMkCAVc`-6BRb{ zdt8^tQ|*DT1<+Zyz&EdN^Nc<=^s}0I>jn6q=Ih)pQ-xVS$*(PiL@Dk|5zV1`(OV4Q zvc>hotdHiJ)!^RVCpAWut z^TLi^H1C`7m&B1!ETwy2Bwxa7t$k1)7l9NRNQ`geKK`N;L9$}ynW&oQ?$lqP6d=Qm zX!2rzAK#6MA;?HE6TDTOrHjuellUY4cfjit}J6 z%EtD*aj*Vv7bA|&ULdCH>Sw`AW+=LTAq`Bm2gbeE`6xm`N-Sd2Y>Wn3koO@YZS7-RXUQ8c8;+1Z=(eR}#4rQza7k!k9np%y zUsAtCz9k%IQOwsHCZD|1SKSyG{)Q1tzoJ~_aQo^)NOB4fGVUA+xkd=Zzuv-o>X27l zBJo7XJ;LNy-ocI@F;U~{X%VJDr}41((?+AQr(oCU=!M|SLM!M5b=~$XHoaU%!NtnE z)PZY^%|4KY0QVu&c6*C zerzk2-yuwu9RjJSW~03^t;B_IO-lmsu*(f8%Ub(^m(d_%yCG2b?S+| zglH%+*Sv_miKP`_y6k8g-62@n;*>Gjb2yl5a^!NqT1Vz}IADQbek44|qYFKVLqa9< z)QFUUxdSeAD4kzvsL}B6H+gqgGkM@~F&I zV;F2s@=ttDXk!9=dAz7iOmT8!f-t3&kdf>r!2lX=k|Tan$-ZpBzW_qQhl- zm&#Nl=1$(bI=n)^5iXYdnxwLZ$m~QmQ4)A8wt%7FIgvVzvhXJk;jWLgRA$&_C-ON= zd4rBlFb1XKX|_j4y-Ud1@k^WtQmiQI6H>foFw8N#Z_qzN6|1#wNGI4584Vrb_k$CO z{*bD1Tr9%CGd901TWxZ-cuW=twyM@$qbD!c1X1yb(AKstWTqdTFd=zt-z&in}&*%a>?DvNzC# zN9c{!pb6@2F{&E)WX-{;S!EGgRHYroQ7h26nv?l+ zmH>fasP>AGSCW_xbba9>kRk)1M7w2P$>H`K<*>e6Gkq;Hl+M`;l^M=`2B`}J`qC0u zJfp1;q>UMG!)CfUC~wEqSBzy{8DQ2c#1K$oUEoyqtPC%i@D5O9(fptKyfm$3xtoGk z*AlVaj6a>?l_UIJ^js{BF6GBE*|Y4=cw=4qBUtDf6TeOd=Nam==pJ14SXmp+E1@sC#xjlzrEKkZC^FQ%~ig^Tg zBoQn#7gyHyVf&Ss%_?Ug z6XD1GaA&Rycd&n*2YYPD3{?o>PT!x^oy95wdOm6kckS0y=6IDdgDdV$HKIiaJ)e@V zD1Er&)zJ5szzt4%iWC7qFhLK^6VYR(^UzYuvs=b%ED?i|d?UN-A;taNO@h77{vcnk zk&1Vl6NUS1PqZ#a*uTtAmqz8>iX%~5Z#*mvO{v>{TJK(n z6ZaV(b}9ONdH90!qriHRji@VhK;N(6iuWv~Po8b96Y((v-T?Szgr0tyzflbB#Xn8- zb=p2fVbUN9J;F%#_Uo&1GDgvmP7`pZSd*JJ8@ZdB7_?!&7qbxh4Q`ojSok&|%7Mt+ zLylfhXPMr(MH%s+ea{@glsxtRh9XUFhq>I#Nt!-{xfW>?sg54{b#)FwkQ!)0(?myI zvw`AciHCPIWaUr>Dl1G13eenK5+t@Q9SW(Jk-trlusSi&%o6~Pma8b#r zdg9_#+l?Eh!ox^Plfe$ArgiI-&|l&k;ncdN6i;$8$wxx zry$+a-qDiU{;1VGtMzAq&?RV2ANnmB9yZBt#&L|p;n;47I+P+bh7r*A5x zICUf`Nt8_zUdwl8+v?+jrpT7OGLe+|-fRfx_u#s%4pp9ovc>J+#kn%bz&f!@E4wvR zW&Fc=xjRUyu@QRPxIft-l;f_Ci+A%uo$>dpAdp1}{XhVxW!*)A2}m44)vq)D7!=Wg z&Sik)7-zlD?o&L|FG9c{B-c)RW8`VTsZT|u20$@|#Ega%aZCAE?8Ud{apy_sR+jem zF*7V&%jlfC;)IU3s87mO*U9cYWp>-0R0x$bWctsQ*TXn@vA*`QIZaoYm>-d>>Mh^f z+y8bE|4ODB-LI-^`lKJsUC(Dkx?VVKJ+LB+&K|hFG80+bq3&3R?m^PP7^%FeExbvj zuW8as$SwdO)-a<^OOhuFJv=rwwsPUD2>sbRx?KUC2DTtawHy{fM|0;cuT9LM zX1=_Q&1Sx=lf_snMO)`hsxqA|ed?ctd#%QELYv1^f30|$a=W4+A%E6mS~c=@rvW?VfiiG{S=B`exR4Yl z7}L$)4#8d5CeSaBj(;IlvnzVw=I_{n71~4ncBKVwVI%1kq*oCd%q^=CW4KUhWP$k? zW^Ndg&5mjPij`U(Wgh7cP4R35(qWRr9K7cSk2nuH=4MiP=!86Z&HLMKSE>#+% zzN%t1h#_L<*@gu;V8f^Ln zj4w`jcTtYoH;7r)v7Mh!Ryr_jTg}H&cys1uf0Z)S0sFH%pdOnB?9QaqgosGVQNHs7 zEqX%8MG!&cD%FO}k6o$0EWwR=XU)D9%)3xn#apN^g3s zc8yg#TWW;G${<6_48{I4q?^wdAYg2{qxu&Y>+Hi)jh=O(&%6-7V{14SKF`Dec7d8A zhTwt|rLt2zBjjF@>ox)d`=DZ(oVvQ{mWJu+*qUy7c|MmDYcZh z7Iea0c3H{-hF1LZF9t6qQz1C7cUK;bbOXCG^8VG{vT zZm7q{(x<6~9$Fa*H|k^7H)tM~9oU^Q6Lf0P(fjk*)r?YgFz0~BRX%0yO@5SgkuCdAnxGns<-sF_lzFr5&E*NQ$0(;Ya_bhCJzg>i9Qb@m zk1ctb$Z`Lr>}JrsJh_Z4HX!7Z3=TANK0+%gt>F|Cf>(YH!&F-Ai7hmTb4bKQQ4D#u zHAk;8y{s9t7;&*SnFW7w&~u8GS&`cRTG*ve9p@_+1r#rF9@iYFS@B>c?j~FLlW8STzti3_ z7T7CCD#0os3Nd&^6~@^bt>Ihi$ST0YS+oGpy{TC>S=_c{fZS1#%>xCe6IJs@Uu(`H zB%O0U93A!LgqWFiX}jM+_%seRisB*4zcs3861AodYqH74H5rAh_xCir#$l6?b$Ajx zODaickakr`&Ynh59h|I%``q3Ytm#yEAU@neVaca5OdT@{ZOh>5qLLSq%a9SceiMWm zi`j{KgR-_}Xt(f#bSxTyd|m^r09tCXJ}yu`z)7fsN+sahlM|6WQ4qlpdMg}56D+5r zb8C#ETB;1_EA=y~m&tDL&HGMyE1+Ts|r41an1huL!o>UjjZQrYydr5Q~-<0&2Br@fN_Ci8h=n@ zc5!A|S-+fK;(BHM4&!>tBb=Cvs>=?5CH9Z#3!#wYwy1SY5GB18qO6W0>W*nv8hG8G z7XiCwgWMf*I>yS#Y@owj8O@88xrkcvm&5DbZ|K$RKDw>HkCSyaf%4_Kj<54nc>D~X z0@fjU=ijVTPq{U0sEkA|c{~ZO9EWlwr;rSe#}m`E{hy%rk8#y8)#Yur1REc1%sv*>TT5DHg2O|#kHaEEf}RL2AP7_GC_D}0 z+$vZOEavUFMm zC=Av<47O{bDgf!+rwN@Y#C&HHbB~aNVDYQrP85(`C|y%SKao-D8q%D)E4kFlPZp`P z^w8>0F`d$XkTRZS(snE!cMObDP==;jyJ`iM?Ia1HZDTc~()dTH{Y~90v(_(+9JozY z%O|q(CXUMa%=a#aWVv0wj;)ZnoD7sx0nAyk>=v~17wMpRbqkpnscVLXzl~QkqKHga za{7V9<@tjhX3O1%5#DDQn^_LNK`4Q3Np!m zA~C&bT349Bbk%8eAY+Co(nW%W12rk+(SeM+QQWDiJdg`2RYk3&RgC6fWR%NyPUPyf z0K9UGubsefj*Iv!qRLpuNY)Zah6B+uQlSX#{L9XgIL=9~=SF5xRWez&Tyd!wIMu+H zu^;#orC8?yIE}A`qZ^!(m;ku}<}m+avaln?5rnkv$E{{NYxS}Wvdv@_*4{mWa4Iv zNnd5K)WULO_R512T(6L;r5K&d2TUf^|G!$Wn~9Jr;Kt+s_rEM{ka$+dRR`}995@==Bi>`e~aEEX2WXd#x?Q6;wdD#OZwki3R#%mf~0R6K~&flp4B^gNYn zD|UioM@h+OE@dtW(GS#rewo)*>5^esYF6&VIj@n3WOUT*CpqKiS6ei}2d}Iz#MkKj z%u8@RT9^<1c~*B;f1dRa%2{23Jntd=bm>6&s(T~+9bQs!Ke*z?On`ZqZ^$UDG zygnvx#iU-S>Yu^`@n)(3lJ;vI?2G7H$@milNaW)p)*8N&QlQKfH*Y6TvSkmol2pS} zH?9bJ|0YrWf5ji_f9r=1EK)Y=fmFm>5w?0fS`S9tDB3qnQx19#vkY*J4NUh9Qb<&Y z5fqZ8RAAGP69b-s^%8x=Xtp7|#nK2{Jq##z**Hh#Y4#>ZmoZW#ammV9OE@Q+&mmp- z#`^96GRIs}G>ZGjB3)QG(6%5wVEZ zGAT$fnory|Y}JEwlqqP0x5BHT2)T_^v@T5U%WXYTibcFy*Lrm*VC!2~-GDnBDt#^_^{hv85<)a>z@4 zf!XjcZXu$YkxrhE`*FsSwWZm(z3f86)&_v;Sp$Z0}!Lg1aavGFUpEHAI;!tk#rUDJOu~ieh zm2iT8;{MFd-8j5r;`{{ITb}hR*EKhU&f)E>5p}-BS~l!#iLFaBF7Zxh zxXgap+XvgQWl+1{aT0t^o(i}uG0sJpRK_d8z=>1^%`Gw~e8WWG<&$8~_~4JVYt~aZ zhVbSneq|1bgmy3C^gFR*Kry(nB3fqC-hSV_UF%Oj+6mGOhh6k{j zl6q1c7qz%jpeZ;DovFZEwCqNrK>6J%Wq>&(Gr78rY>0Bu&89^gILS#EHFx8|$`m3CSqNaYZkty6(3ZsAK2O0e?`dGz^ zffOh5$2P?DhBvjR@PxE7Kk9FIsR$LFvFp<8sF2V^1AOyIw7(GnH0V#G+CuuJW5VF@m*_f)T(%@1{Hu!_dHa8HqkrHaDUOGZct) zTEiGP_1;|txnz;M?BqUsdC2*DV73@Ec>^Lar^ud^8?}M++9Q$?DZMcXlkXo1(8Zv1 z*m1&-6QT%r*@KNa=IUSuV4dk*OQ^a4CGU=vPU@B5M{tBysKA`!G;{3D!$x2$R<#Cy zYbWkyn)R?=leWhS%yyfJs@%Knj(IVo%?Zn=DPp z^BZ2b;nzz(EmtnHTRC>xgd@8hajl$|*M!516?bKipD8;mu|d<#!!O z_e+Z*EKDD0EVYUY6m7=Ed>Q&yd38xeF%70=1eE){Xq`_B{-d4B$?-%4ccLYG=ivAX zq`yhozLsmPJkCVyS&fY3@4cE=5W7}$|3S@jeGMC#X9rhrX#tm8{j(35zH)|8XW1D_ zqO7pdFwWVI{O&y4Hk`ZR*qRL09(Hunj@EP#STYcj^Qrv*-~yV7kH`A|Gwh_?wA*uw z&}PAL(`w%Y;+^V*94O5!3p$sk4_tfcq6$L{D!$0f-|`+U%^!`9v~UT=an~61DQWHE zEZ&9L6SEWkY)c8$HkeC86K273=>Q{nZ^X4<38ULnl{ga|29}PQ$RmN_+vvw5NfiFg z{(my?BL3mq$Fv3b&xzW;;Qv>KZ=4@*V6Hi}_4(GiwPEB$tk}4<&4|J7)ESGBpgA$? z5)B=9R^E4mG~4A4|ClDOOxq@Q9uINU7dxYyecRaG(NobwbfA?g+&Sa_T^ z+?}vn--Rp;lhZj%0G!lMhSwHmiOo+Hi-|2S%xv20t1rqjVA1k;i9pcshN`0k z8?QQeEbI`m^I<8Ed5i0BeyKt2I?c)4n%HzPH}RTC&}5)9!kWoAOR)!D_ief1jpKW2 z$C(@cZI5_eqFd@Z1R3NU`zxeIl{vCGCzRqJ*MJ4Ju8KFAEU$J#TcWH1-1GyEq1x;c z22fV*6>b^qCw<4}+Y{0(t1nOs0@`;2$*nZLhVH_^p7!z5ZOx0R0Qdqkt%MTj$P(}rYUf4AsjqZ&XA=S* z%IvWD4)e@A(VeinE>07Kp+*m`9cQ#~t>vngzUupmWZ-~caAkd~I#?Gk`UBRo&4tMY zXZ_RhBPIM1m6HN%lt1Z+LJ_6!jj3l zJLuzirQuC?ro57^@|`&Av&uozta<0OvAM3S8sn_NU+iuN$Ppl^R&%@64xz@@*N#9IF8Ow_IqH6VMLXrhSaWadrvio%)d%w-_bqJ=o|91tq-fh&fxlv_os zNQ}7$oD%UnYSmg{&!Ddugx9DZjVjbTc(X8?QSclspisK*5@bP5D}3Je69C(!rOH|+ zqHzvpK&w0+<%d`OV{v0fy>2 ziHln+G?8pc0v^VF&ldqHHEKkGepAjD? zWqQcJKljo>-SXAx4yQSFO_}AJmr`?p+xKydR%Ty2=Q_!wMt>P8(o*IsTBev0aYRSwTxsrcV2V=0o=8ZB5 zrbg7Zu3CW7p@&lPcJ3(h^ALsY8644ea!7{`*B`tADCh=8M=dC_=O0krpE{%rOzE5@ zc0^@m^}Q2Y*v(*oLz@fcjX+i*dw$%^my>%)A-*5LG~*UuoQ5 zugzXA3*CZBpD#d3{`d)swEe;Q&sXwzCVS5yQs`i>H#4PB#GXA&NgNoI2W9k9wV7&r z$A?;n{?G!~07F2$zYR&?OTswviUGwq!+>Op1&k>_fb0$3V8P6Q&h*z2_r8RL`MgU= zMNB(Sj3^(q20(f$fOnoafr7WHt)SZx9Zp2zLJ@@{fvQAJ3Ca*|?9vcAcpS8b!4l7? z$JJp-!DHM6z+s7DhF~_xr{a=kU(&(bG~_R6Fu<5VoP^R)dWj?>jj_0xRMZb_1}wZ) zhs2=q3m#ho3|2+?2w0~ZS;y*WrOgl%VEayqNLBqXS&BeCT_8h3&xR?E%w-T@ifsu# zH(|<6)|n9LEIPJ2x?3u{2%>p7_-E?zYY_MJ{iu-fOsak;yLCzigUOU^ns)&YAOYAr zFb$zG6^OM@_XY(3wNaQ7J;lJEDTTbiogVMba5o5I00y}t=l}mdXE`<+3xwXu{Hz{M zjWA{-41f(%K%q^i0)hg%H<-?#aD^u3qVPrkq{4cc*o)y)b7sZ?SjIA8fb(pgI9HKj=1}Kb3b+joSV5 zK@~k`1T|;_d1C4cU|)|pZx_hdV=%9GkdJicscbivTP`@()lkeQpHasq(`(oePff`t z_z>m}$GC+C#1*)XTO~T%OJ~aN(lz3R&Pga78db8H&bM$&9~XcGz0{S?G)XEc8I*Yx zO;CRT2GY%0{P}FoWi^w*F&`Lu@VOSMv(MJXC1>gi@qf!<8#hLrsO>Oq3`(}{^O!dC zL(UW|A5ZtOv*quu_3xNfqOuqC$qI#ulFmYPj=T@XhuG#W8o5^u)QeZdy6&<+)w^*ezSjOcZKI zA=-QK12vX-k^y^)|4w70^MxVM-IHB!J?1RD7SGm3{B#<>+Ep_?B_U)D;B~^DeMi1X z@*gS0#$15+(DgkXchqvZ4vYM*TBrRdRV=?otLnV7jxCIA*P5{gwf*dMTXa8azTp|2 z2PcZk0#9S;L`VYza93~m(9dhR^?gC0t3;L>mG}Q-GwBK@`S7hlV?Xl{?!0gH%+K7S zN$y(M`)fdt)()4H)Ai9RKB{#h4Msjl=9$uIov-ff)iP+Ixb}?SAbZAN!{pv79^NoU z(M!*1RSyx)VWn2+YcIeWw44N1!SGoqW3aRLjnUQ_Y!#%h1p1z#y=(>U-`K@M?F7c^ z8*Fp9v-8#;DvQdy$NyzEPiFB!I`0H<^F@WtY_aC&&VCFfj6&^ zY>7AxDjz##kgpnfMCZiMKd2K5EH}Mky@x;DsiibZwzl4HUbx3h=VJ7C8#QV-+0o~z zUM<7mC@cT&D{#QfhGoXxph~)9Rg`y+bvI;8w1Vz|@h)C{!6 zltvJeg{YFPG1p_gUpGw8i+U18T=Tbt@ik&p^-QqEVV6?O5mRr1`qf0!qqiUCk~@CS zgr?T5o48Ka``A)_tr)ihYWIV8KF)S15;2G1TKCArv zn>qELviBYj*<(iCN#6~$;)4Nr;|-yU3fSx2h`IJb29LCidbSkJ+;U!{HVGotul`PW zYNv?4665L)`Oj)Eui?J-8J*XteJ+uF@yaBMR)d|l?j+ICL~0A)#d}|MOS85X-^7ly zWC-|ID^n)4a-(DA8@TGRCpPj3;e`LA_3wDz`CRtBy?kSPz7Bvm(sR=BtlIrp=dDS? zUu}5vPF&t&>dZ}D$cg3e=Cv0#&Xa&}%D2nk?M#yC9CiTxAFo-g3U;6Gm_%s?9P7j; zbZE&YGThI?BTknZ>|)nWVvfHxToa%I{`XJ;w?zA#jlkS*HIBvWV`l6ATWMr}7Jau0 z1eOI>B$WbE%gb@nxhruX$gEt3M4qLj{*!RY*=$;P$f&Nf)Fk^eK)zn}mS zZvJMrVh9$g=lSdP0fD*Zg?P^QO8Dx7QQ6TOAA z+_LPk#QIPl=q=qCB$RTqRJt&#_wj`~lN z!GPMqq{F)GG|T~bZU~7$Fuy9eZOgyzDY$jxMCgv1WdGd4#!2OMJmO|J-pnSS-}7oD z?sh}0)6C6yvO(UiM{x}DZgWC%C$6pk7$&r{f8B#q0#qTJZ4Dil_-8i^QOv7kpw1ae z%_pV#2HicLI#ecQS)-pdzNZ+}2b-p9lk_L1r5Q;!TsNxmd?7rxAWYaTmly}O0K4I_JsR@1Gs z(qmq$Q!H6=m-E|lkCjePKKIIQ7ynTT%)P+Y3&n^?XwlMpH&`>vVun7c)?ENgyFoU` zpBN_)9T zuQul-Kv7^z14@wl*(NXb+36JbEO&O^ObEHMfw*5ivPb>g!p*rE{QHC37+tY&j!uGq zu(H>C+D$D)U_+FE|62lbbPMi~F#(4u&IJnA5TYXjMGQ5=RlZ@>bz-bTwab%QcUxL5 zo~6p^O}?sbU!=`GiZj+01)ze}d|j%IkRsH@=q;8Hg1w=nn)81*CXo5BH2fcsWLSX^ zUF8waFTUGma`?WUJ^S}2m}qxK(-WUW9HQePSok0}sJ#>~5GHerHS+e}Dku2!M00XZ zzzUmY`{S629tu;yGhWnl$LWgX`F1bROQPp-msKTcsd*-AT^c+VEWsZqk);D5m^=9x zPaM32b0t8r4<-g0zO>K327?Yl+zvuNpr}vKA&88*54zCz$p>4{*UIAg@P!d_Uac(c z#0LZ&6qpCGz1=TkC{Z33`Tm9@FTktX;UxA5j~#GWI+Vjay|mHPLWYorVaq@L90-tW zN93P8Aq&ul>y*LF7oMAz-DyrlFJ$rT>1Hvn?g#D`pMpM$hBl}3aUeL%F`aukXg|(c zto^@>%rnbo@~Qo5tL%ho|5AgGYzOld!M^;f7(|b&6+zAX1w4M!3ZTn}1v zr?0@RAVU08L;bF8**fI9z|II+a6^vRk|Tf&#yF}WM9R7Rhb;cS!=#;x7%@@Qf)m;) zCzw?H+u*T0eeDd(mj;p=qff`_K!2Rh017m35@=@(FUG|93oe7E9iBi7XbY7_~Rp=-e4o>j8q=?{xWxs>H#Ni?{XEiF5{_C5|y8RMrNe^N4~(X z)ES?hc=D2L2pUV^E)-&UE*0MtYsTuJ6GXs>4Zd@(%jvYQ($Ud#gdoIi3dWYI@y1kz z=&Ej)m@RhRxhdv;Qb{-ps|sZKcus;y;I3GXX5M^*`BCC?EHx{JX=M|81u;X^$1UEn z>X_+zAXd{1)9{vSZPyGZ8nj6zX0h=SJYqek8-~7?t*m{k0*-{$*^eYqOA|tS^1%%x z7@!fg2!cl<^0ZTy%SN;9E-PUC>qC>?a?0hv8s0dTvNav^I;qy#vS?VZvXlow3?Xq? z%Ik!Qqi2TG>1Py8Suf}t&HG9gcCKySlWpnYfUe0=XA3Lg$ZCM#q|IC=#_P+ggn$!d zTB5r4Gu5)Xr!0o-?OO9ievec7Z9JB1jeQsz6>($v9k3S5YDec)Vr}4cR78f(@Nn{W z3dFT@pNU%7H?;vf-5>?v5DQAV4SeirO3ls7xugUs0}XrylA^Pjxc|p3m-4}dM`SXk z3T>iY;a}F{Q7nZO`)z?i>kyx=ehv|_JrqWwJkIFbe7X7A)<@~SjBIo$8b-dkO|WNpId-FB(rQ2~n>)3it+mg%`OI-)QO8?7|koE@nsBw}6Dm#iI0NFdYzB*M>_fh=17YoAt38?fsKh;zZUF{+9`ObVH;Na#$pglJBKq(T zr_Jz`WI*tC?Mis``MI`bc}M@)2JXAbktbG*gLTKBZq3uI?g?GZ_Xm!&7PwD(zb09< ze$;7x8pA78?v^j4GVeEDBNo`6QUp0y14oF;M4LK(05)c&v>cXN+VI zBk>bk@b9fea)2l($3_u(&Ld0md7;aN>$A{h7Hc%U-@IUxCvm+KUW{{W1T%JnH1!>Z z=@G6r_NL-5h09g-=c0(H^{{Y5(UvGUdGv%p5x@USRFr}*$$K2+5P=e`N<-|5O1;X6 zXcf%yqab``iJX1Eq$+65ZZptmN5G%M;@~-D&Mwcsf`p&-$ZA?PVsQx;#$61v@=h;2 z>!pB*u1#Kq+tX1;P+kK{_RkO#PsTH&;SIYA4)FR+oFo|cDA+0%7`3?QxbaRLq3(%Z zGPb1aO+Er(I^vGPV*~rZpeR@d{KK_#ffR{44`eipLT>;F;sn|*Q3sf_`+LV-yg8)_ zH!tH8vGca7+VzH5s^!*(P+P?v##_=Go@s!k1|Z@8@R%|`RA&cDN}vJ%IDK78DnwL1 zzSxF67KM4ckS#y@djVnAD0W>l1}S_PFDw&*=B7g`p1np>r?MLZvrM-6L zrnaSOK{WvDZV}a-u5afOr%ywD4OrxGLDFALG7JJ2Sk>}FDxTa_?N<$4&hsQgVUdrn%Ii7?aGKx(D>%(FKQ|ExfJ|~ zV@C>qh@r29o;S^uoGZE-a>@m3ei=Wy-ZuDk?&&@_@q1rSYrmd zI!y`@q37-_OikT+Fg|wY0q=gnt=}x%caPO2t?}Cnx2A3{O8UjATlVWjYpHRjcVq7a zJor47L3ICVZ;2-6|MlViohul9A`;4*6}kM=`I-bRD7Q_RR#Rm)*XV@mLzfL|?{1t# zk`D5c&rrW64j!uT+i>!_{jm31v>^*k#7tp(mY=k{RqFm)!9EJ3URt5utdIQsXg57` zsEznSs;|6XIpj)l?(sefLKQ{FyPdItcLcrTqhES>A{KBPXPC!#B) z(czPL!LW3J!zVA(hujFkosrm&ieDyS4R;H@U(DoSK}T1!?9C(NcP~6}UNuYoi*`!Q5%LDh^37y>^iANI_(8Ho(8-u6grQg`Zb{XJyHBV3UvE zZMl@lrA$$Ce?;7&rY{0-v`Dgjj~|1LM3Mr)tAw#z?I)_akM64Ej%?gvZrhm@bjVzg zy>ho>&iJW{3g+ot$JM*%WgC>(-Hb7r86kx1%`rwp_qJ-2OR8GKtl!w^oUDPptW8Qi z9>7dYQuPgA4Jb}b&GX;?@&0Cd#EXbrBfDokAbEmsgQvG1{8LOBQ-UPr?5It$1%! zO>W|94fj+L-&lMy8;eK}S4)+(|gzpz= z6sgmP>&sy!C9b}Mm(D!FYx^ISL2C#jI`>sqQ_m5@TJ@ z2DRzwPN^#U_4%^c*JQkk^SfIiW5X_xJQP{$FvSiQk(qRUr6jq!=umsK;h z=*?pd2g)bvZ;O=o`DyRqZ+TBvq;+?8g=r>xhkXIs@*gFy6^t>tnd1ck1&^4)-b4!i zsJurJYqTMw#e56hcRQ(SC7rG{JZAQJj+x%>IbRP*d4BJto_+TjS-QoQg(}x z)doa7S=IwUlix8vV9VBoktaeiCNKw~F)FGPtHa(h_66>du?_6W`v9Wx1j;P81|S9- z(`yIgor-k!?Ny}4Y=&CUHHmv#RpM1}kFy*w0sl#N_i72XTaaQQh0bn`!HBSJW73mj zB&y1IlI;7ne+-v}lPGP<59L}i^^Dya^L&XF0k}MU%vt4~i8&B3e%0EA&616ejo3QT z%U`F$d3IFPo(7nTPG{>RKMa^Z6?bQ5Rp0+F^63X$UnVo^`zy-pdUMFm7=9$=Im?a+ zaqcYX13KFDX+4xHkV_X{k9|h{KSVJ@=cdMZmxrG-`%t=3Pwq>@#}}QzlwP- z3Y(s2m>rB%=qNtTDk(W#Q=C)X=s;+R*zu@ioZXs|sI(W)tFIaVXL4cs%Bt#jY=^kU zw1#s_#M;Ty%hjjD!!@P)8wP8}^9CbNZ)}>p(W#Wz`ybEDt4npe%#?suu=M0^!_o|l zUqMlyO+)3a#M#xQx&C#rw<*Qj7m%XGX;dkR60SM%AIAiRih{514*%#bQAt=R;7bzd$vK^j%m`_+GiHuu~o^ z3Ymr06!z@F&4U+$I-+9b`?t4!24bVMb0ZFp2zKJpHy7{7nk0G?3}~wyFOMguz$%w_ zvlxlh=`%k*!TW{L*;xV&y6B%qB1iBYk#X{U+uOe9Vk32PA$=_P^Q0zb4VwIlQ-t9- zk1vyJ(VD`4IMls8dP4cfuH8ZY+__1S|5BgwzK}drm{bA}*KAiG{MYlDsA`-aL5t=~ zkTNu5f5lefIrc0HpH|(*JP1jsdvF@EjGACm-i3{!r?^%T*HvbY|Gt)W%de!U#|nut z|7G!%<%iMR^BZPhN;lQ>6aG4w{>YCc+e6a;qSQzQ9acfxuo;Jk7Vm4+LK@U&RA3t+ zu@-OWd(MDV?p$(Ce^6nk6S zPUnVs!C}W$ugJi|eJ7R3$kVvkSF#FFu&F=a_Ghcu-oh#2Z}%*dAS2Y2)M%8&cVD%n zCNi)Ft>bzaI$7p}la3G0Jiplo{!?UfC@ys|-cmU<44b?Jm#r=%nP!PwL1PW+ zTRE!`T{- zOA#!A83F$LzOL78)_oRL+LsKKP}3#Lcf+f59oP2fFq>eBV4BIv64(xzGZM2BWpD`A zN)_vNQD7gW|1;kEgHCc!ND`tUkQ(qA87x3qGDrj-6=r-d`IVLgnV}Zn+COncunf{a zIWm*t^KK4NG(MxKX6L<|pqO;oFRZ}o-8NmhOOmmbf3c$yhb$m=C@OJ!k1T4tEZe5L zTTLZZ3N*cf%|ZFuaty`bj%J|(m%vJOL38s6C(xm~DO2(4xBbX4K}8Gp%Wb!KJC|o?#zQhUkeJo5MAVgfl{~%~7;OxZUSC?m z&3G)zH;i6niHJge0horuVw{#-z+wXA-qx&=k^rmnYl>(k^11dcFJ*dL+&J%tsr&Rn zR&kwq@*ICKQ=c*Wf*BhLU9h-;{S$l4cT>Rnh%jXZd$7Ylt68mXZdT)7nx-b#+J(8( zFo1=3vQhY=NbB>3d$o;oi+`deu^3y#(7i>LsDAH}Y#h2MqU^JUMRwimz&?+ZEy}ls z*HNLfepM+|C(XOPQldV4#)Lz#mqT@X;3OP`1<#%-r)YC(xCf#A#^7(MZ-0J&^j)A9 zxW`t;H1N_#3ML7Y7z9cNDGNnVWOh4@h7@-tMN~~Bs0%aM&C0$ftXb@!cv#?%+wqDp zLAgxLpk(C`l+9ywjZo5+NU9!7)DUKHTYXPGslDZVR=fmzUduHDt2Ep5c6i^^c1tZ( zn;rRAd0)L`?ky=S6f;R8Ey!H5vu5T}jne50WU>%a84K@uo5K?uzHzg9uH!^=CqbUd zp-79?)Jg_$vFqTx*M^cvcW7yh!$GNgIOw|VX^c;!eRY<}?%=+yNf!*GhOknyT8Lm=)$IWD;T}fSG2$b0%;(8}WRSZ}q{F4cDxtK)3v-3ajKwRA zW_mn{C#I1|Vj7R6nr@sSt>^b5*I!CK7UQ{P$wdA)rAr}`;LcnBXh`zV*jP!)#6)qc zBe9rHHyRjxF(Zv`DvtPcv)fTo%WhE#&l{fZ)#<;1sCZvTTdq1Bo)SeLoykfR+FBcY zzvMRshyHagFB?0OMjQzA6lxhoQXzivueZHLCJ!TyT#X2&mubw)8+cvEG>tdYZljw; z-2<-&^YA>lJh@sTI{W&sLUT)mj_cRA)tA3MdWK@C0avVmt-a5za;i0$Bu8eWL)aaP* zjM*F&JQ&dx!q3fOa-^-k5N`G<1a%Xh!U=`nYstnCkfg{heL?MEL!pt+)3oDz^aJ99 zwH9hy3)Hr6pm#@2rBI!5rLF>2P-9<_4$u=#QiAws4jYAGv(X$Fh3Y;vs2irm)c#Oy zNoCe;?@CE!8|GYCcU&R#hyK*yw#)S%UI|&g$?LYqrCFn3%X|f3b+f#;{zO@6a-J4r53$;sP0I8bo@;bA1V)pxDF@KE6f$XN10%>J2T3(IQT2{%%bFAckf6TD4#1Zh5{ z3a{BC{cLIzuj^sX&3nGS*Jk~~lwR992FjKLs4(`8JA%pGn<&zOe&`kHQD|o9d3rLg z??)hSocIdQjK8tcZm93+{0Z5dw?*a!p!|#CFT~kRe!j^WL}8%}cOWZdCZ^^8OY7(X zIb!4jCb>M&pk-@hbj!A6w;euKW`<%zWPWpdQqXuivC~O+6z7C%{E|?ErRoQa$%_(; zsE2EJQh&w#`Le{7bBx+Px4|T?NwD= zokFT{Trv6PdaZi4^2K2bbeKOm;r%B|t@rD2-lv@q_Scrxdc>f1qgo4MP`G{I&}&CO zG-IuHI5Gc~vv7<;j(et4KT&G3g{T{`uNb+ zn;F@Md=)ZIh5GDUk)wXzzH*LTb$Yktz(+z7LDrb_U^0IG=I| zc7|%t=sCc5bm4IBM7?$U_AFdg?eo}RWG7j(hPt=VPwfv0hR(H*GslOztrpFKgvLT?*?h}YRQB#H6SWsDi+iYi3+QX`5Ofs{{9Z1Q)%UOO z%l&Dz2h7w2%lsw|^T@-x!PUg0pIA%XOXU~CdWp%T`40KL7$CpNhQxCHPX!I-1-fcE zCl7B>C=JHh)vk!nh%g*QA4lhqgSDIi+qde6gV+(k06yR zH0xfm@I=Ke#qwm16?DmN4=7ez&h>caTHnjw}$(a|qs(8y6;%9>! zd8~_iY)=X^UIaJ*O#z;vDiGMrlUSMjbm8f|m7gyBH*dQtlW(|jC__XRlS_orfqu0_ zq8a7zz!J4BifoB&uJ6e~7>&>hAYz}B>{}-v?4-gGkh3ibTP-Z5I^pN5d`%iJn_1)V zR<9$N#YD02z1(*x<%cGH+|=C7&HgST zHSGpyys;KJa+vPr_B2_#^u`HW?d7L!kDjEYy@te6X2Dp=7M-kinNC#>?7H%QRLuRr5D*#TtDB zOJtt?%@sjDffIvdEnT_}qz55+6@|;t|KmFa@&I@M&CMtXz#Gf0B|j<*#=Zc(#X(pe z=NpzE*?b6#?VK^&sU_FOA7*jX!}|~KBXK_`#xd@-ev}I6BDM~X2ekN?fM|BF2J~&r z%kJqZ%+JZGDmZAENDSU{uBo}Udm?9$88M?37k2$!I`XpzeRm!XOEt@ObQKILO!(#g zIO?#ar~NGQEu)Mmw?;7}kqKjhn*gGLe!7qDFOQ&U0Bqutj@Y@1(-ZP?!`>Vs`&TNT z;?PU^T=H#vxF9#LZC>r+4Kkz1G61Lq+z+mos7G0dA}d6gxDV2=M0l6U&%KIih;GE9 zOE;1l(N(!qrAx)i|IIy}v%r9l{_I^hdGG_X)74c&*<>ar`aZ1cfjcmdqei{vI^=~; zo#O5?y)NY#^miACwD@hZK$n>V>p0nZ9G~NSqDenz72Zmsm&WKB;YJl*NVLY;;v4_+ zckK~Xl2{QO1Xm~5MZ<0?`bDbBZUY+H+j;f&Cnq{xSA6}p1C;~x%yVHBzL(>Rbm)m2 zsuXj+Y0uII0u;AmUurRjp~F%V7gKKQmp7kD2!Jo&X-mY^h+gta_j-}sdD4JJ7>9=_ zkI@EF;eBPn@k*$ladB$<{w?)MKKRY)e>ZmsdK_Otl zp6KUJVtuv;E0+sDE@fDiJ!NnJgYG^kNc&{$tafzltakKrTP?uRFtM^HF>aI9V9Y!7 zlZq(ibB2Vw6oG?enJrmvt>hhPQ2W}UYzAP?%fWf}a`rh|3iVt-i$}=;;dM1XOi4iN zm5uiYYS0COJU$k1hQo!iE&KgStwYWy;K~n^r|Z#_QHGdaA$uAZNOIu_a^WC{MI^kUHb zCg5LZ8$-3N6=_UHFAb0OX{AQ`mGf$UC%83;_cEMZ80^_&70MBzL?oU%nHNKMwqW9X zk4J+nv0oxJ`8XYV5yD@iC0v7|?sT$avX*e7-nfcv5y9O}_v;Ij+}Xx91OVXk;W!ZCcGvNv_T}VgKLl>^4}?)#7c%!RwQCwdIhG1KlxzDTP~K zod87Uo{Ccv)4*0)JvEtcy%cvSV!ffrMhD2mJ%mn@ar}EV;#y*THnE;ir}n-Q?<9d* zpzQ-hP`YNeesk?cV#3QC>l5bh!Qy^m2LyS5IXP{3e2FvLj&2_6{LQCo3bs5mpI{`K zG}E_wZg(%~u>pXksHQdU(eouOW62hnXA5doZbPxE#0wf&2hYkSPi7NuXgbvc=nUQ| ze<27IojJKbFFf(je1?1UH>fY9)hee^4q!RGnXmX3V~&;o%O{wt;fH^|P~_S7*9&B{ zIXn}M6K$d{=CGq%=bh_cV@5170XK0C@6(bM-En1JquQCdemYbxD^G${_x3eex=|;|ci( zoKHn_30iLYg%6i;y+&?4edmvraYpJcH1(c{g=3at94@>m5FP|sXl0=4S&AXPg1 z8g=GYAvGdEf6i~lmqy0PrwV;pv60EHTSCfO1O;lD{Yt53&L(&ilxJ>7CrtD6d!p{V z#*zGr6aMxiXH7XE+v>eR9jHt;M?^TL z!`sL=tRExs!*Z@ZMpVcA=09WEH{mGGTd|`sE#kev;KncKc#()mlKX%voaqJ`-m^PF z;)mrNeT?W`XXgk6J(7qDAE_9I%|c^XY#W>1|J?zs$OX$HHzC$7>Nvi_h?g#`rwqqR zk>0K3OYbi!38%cG5bQFX zL{>iW7$nq>j}9(LHK%Nrf4c|&)@mR7I?_W~b|%->Z~ZL9vA{h-TL zxX{#>KgPX`7`kFWV=#kKqs(EIZ%p(NZR?p zsv2bJ$=Ds>-n>F3@KolZ&Umz;ryW018y&v(lHw~c(X;2&l$Y>V7ymWGwdA@xWdTbL3Ve)O`{Df@1cHf zWIuTl&-=O|iST5(|54i7O>xK6zh)Z!CPNGt;WUhrfzuek9ym!*rzfA5lw_Xmbng=l<$0j(#i_ooZU?pGN z@6NKa?(QtsqiY41D-HY(@z3fMiWn!mvhu}!LBTm&E3kMMC#i;@Ol>l}jC^tE3yx1% zHsA3usuC?R!qxf^Jth-wBI3AiK^7}QHypRNA=;$=m^KfQD;(bOB4_b0ftR?FFlhIy zzsQB?C;ASyj&?b-osLm@6X-q%tq?Wuv?#Ov^xa5i6ac6xm3Y<>aJ#CaPZ!< z5x*o+k>O=T$EjYho6rK>f}j8ST9ixl{TYs;1!u?dW3k$&U*xaGI5Q2)9Or__^_N_K zkGi)t^~#bMXF{}mjHM|z8+3#-AJBS)GDz)z*}r!;e>XUf40R%s&|e~_1!v#Rdl>SK zV}|psw)1{-8%Qd^Yq7CtDLYB;Vp~;?#1lz=May1{cU1}#ICPgZcpmjCkJj&=HF$m~ z^RvlerH0~_=v8PM_uhNc|AI!OkNL}~C}mlfKxHDaq^NyCwmYHVyYu?Wd0bMncg?L9 zROLH&jJE(Jgs>mm3v;x>jc(AKrj1eMI9~`m)4QE z?_@>BPd%Xdy7|;jK3gl^@B-1y$P%$N3O=$Ey&`s5H%fu)YSGX+unq;MDCsq+iA;6P zK{rrYNL;XP5LypxT4C0^RP<9%mi(1w41H(8!^*pYAop+egE||})!R%sn?Zd57ku(y z#H}^}v2AkBzDZSm$lUi)O1)$Uh_mAEJKYOziyiMVZSPgb!QVtr~*md#7NgXgO05}Y^=R9UbzaiHGg8AaO)b4G>F_x^h z3K8hMjPKfb?d2jm;nZ;6i`l_i7jj)34b$`@h^2*P?KVZ5P79vP(OYY-BeNc>Do(byvuI;03q~D4R84JBT~iSsmZ->29vqn_qVZ^9*lf34c(4DbCD6 z*>q_7_oXnUiv_}+Wu$g+=XK|L^Ys}%-G}(-IuU;g>;wVJhad!GRyhjFY73@KwynvK zoz)qHu1gK5N{nPLM%2T5`hNg`()ZfP0H;4?Yt|=SBtUYOk=wp}Jc{|NODXgGyw?Y~ z_0cp1j|>q&ki~YfR?o0E4XRR;`s4FZcnQyjxq9_*(vN~C#!JHQmR^={y11K5Dv>^8 zFsW_=Zf^cTJ**D^IGb0mhBZLT)pbXoU5m(&FOSxZZS(307QK4Yuub}0fOShvbGf=L zQ+5zt1+BC=fpz(|Mvg7tsqXt@4C;%iRO2@WEt;zxiXG@w8ep$#l4{shtYtyK!=6!8 zdkI@!DAg#GF}lB*=x2xdbZ%p|+3uf$L@hE5c@993_x&DjagHn2DRce&!F1$dhJVC& z)=68;6R2%=VU|2i@Q-`;nkv>+*jWdu56`|?6p>~HRrgdYVZ6*{W!L0X0=v)oSm*O7 zfX9FV%(syW@D;wsd;NU`8@4;ev5{-*%PrFIQv@lc!K;{(SkS&!`$mT*XtrYVem`># zoPghM<*-NniF-$!b@VvEz0`l2T1S_GHp)XfKxg7ldv;wvz8YJxV%*RfPEmRuU{il~ zn!I?Rg3EfRgFw{+-wGkw_&?|TA0->_iW8nxCheAcnd32^K3;r4mFF0MuhdIx27*7T z&DtjRP2GAb8jp+MY(>k2%Q>BX>-+SC0`evXt{U$}_8Y&9?>Bil(7&o?u>pvW9Y^=6 zF>FSG+#W2aNMXkzI*A%zFWrk{&fx1nUUup2oF1cf#DOK^@Q!FrW9l+9+>DN2!dUf9 zeZALW(>zL(Kp{F3*~a)AmiKwGmJTLa_@J6=QQ0d)uUt5V&MINjwXd{-VFG}s%bHun z!rYUYJiqo;AWa=~zRcq;4?84zgL(J6rpE3!4VJ`YZ-u!JznS%~y!UdM3CvS_=lANF zzzwfb{s?!=8KHZ5`lq76{kviUo7MOYgtO$*gJWm(U)0ck-{&DI3^UBEs&G{``NPUQ z;`e`-&_F?OWYpz3bMi>drB!z6*9?%Vy)1~UY^j2?O*CYCB@)1Von)1#-H2vl>EX%& z5;niXJjr9~lqf9JeKyzV{!OlzOu|%)wqQ_j?FnT32HRixwNR-&-;GrIO~@? z&ZZdyQ>2-xv(`nI5S(w>aBzZ3hZA#CTIj4VR6(xI5&@ykEFM3~op*k12w`2rOv=bD zo`!j6t3P9NTwC+v$8$HVU`c%ij_NWSW{_gW1OzdjDO&H3y@sBbh^860;GT30aV@)l zm2)f6>u_7Vd?AC&OvTk#lmMM=+bNrFE$Og*&1Is_*m9Y2uk=7s09jRaKS#pQ@>R_~ ztF^?&PK723z1!B`(Qx$B1K(v@xqj0NQu13CEbwxRyZ2)4gBVZ~?(uJN6qO=`cOrol z0XS_F(F*{izJtk&W}@rJlee$dAp$g><--W@zQ{`(_B14vz{8P~TGP=6Xz zPgyS_m$tzd^Tn_@yla;P)FirBZDsxg616O`dpA6Yt_--IvugNJ8bi2JWsLBteVXf` z9hRhF8ZN|@N)gUmxk3QC63o5veEQlQ?=AS%)}WtHApj5IKVh}&H2it5bh$=g5DIG( zUItL!zixnFTcZ1yfVAL4Y4eCwsbGOPMMOU~Fq^g7;^+kn%nbWH6;mUa%K$?F zEe7~Ia*Ip?D(|TZ(-^tE-X_ET#mD1gr@-Tl39A3%#C*la6@6BKCsz@F7K=Y80N)g_ zaduK1SRf~Jv@K#E&WQe&^0$uRjOYMN1v+OV${?iIFdQ7`$lBjqi}3{DEM(0jzt`<8 zDUOKHqCouIzPA#!Hx>nBCa3e0mw^sXG-R=cN*^FKo>pskh(X??p|WvB8R;}^HVVfLJ4djkuMKd{ zU}lc14Nj>JRZ1!aWPO7U*;`=|?44J_b~BMzk%U{3w!HGlCc7Zu!cCCvx#(0+M6ynF z(-}#`TT! zXe_2X`jZ!sUG51Uf=3Ga89lb&tMdSCOWOL>U1tT3_fwW52)nAGj+t)L^kb2SZ87`s zZFqn3Lb5wZR4LODWoL>^1n_g6(tUWjrSqByB}i1x1cy!r5CXpA0NkX&dlVpE#Fjir!(cB4Is<8BDg0)jDG@vrQre=RTCW=)xayPC)Iy`G_X|t1=iK6)}>P zS-ZY$W#+xF7xgbD6@NiMf*YR+NaGi%PzCh=&C9G0MUM_{Wwl4e?u=Fb1;oFI9tf+2UpHE9$(0~-kUKIT>yN)B!c-qeT}0{ zBNFI7eFjPe)@hL8Nsr_d7aQOaS>uE4t!?L9jm001ntMr{Q&M4pROZ|)!4I{yy`wYL z$f!&C#x@;|wqF^NGa0)0Bt~S)prIOnxfZPV!+WJhyH(;GtSx$3yVRla$kX8})R5=) z+OcPpkHab03c^Diw86bMBh~P$;k(Buv&EDrUnr-{_SW-!L3SMXgaH}kmn(m}%^Xu` zsXNYr>dE~K?cO#MV^6&C49@`*QXn|4+>zkqZ6vHf5)*z%r;JhH!}h=8O6 z?fouiUgB3+Y$GPa5^9WOKP{y^_|HYB!1aM=ENz#N2_pU}XVmR6PkUNoVl*CZ)dcj& znH6x&qD*1dK}4AlU@ohrO?cV*k^S~B-TM(>bpq+z)cq9)gp7Tfp zEla346X%|YhkKs1XfiQjsN+B#NeU=&uT_jz0hw{h05?F$zY9wHF^cjG<;)if@EY8z zlv-DBN(zup8BhNG%;zVH+52C+_)04=hSo(k-#1 z)LK@~?>;k1O?7U+y#w1zIQ}ozf1@0Tp`mFSvwaKLnsIQ%o`=d^jd}_QWO4iQ!QBfu zgdY5UaB8wG92$&|<6!^fw0P@^5kPm-U=3*I{vt**ee_z*Q&=)WB`Kz!qM|nXLw8lE#g{ z+~_MREUo~C^r`ZJxmp;;i@q%$@94~pS3<>Ubb*g!q6FAS`?_{f;-ixuflp_0WqqeS zD-VShDkemSpBH{{q`PkA=AN#e3}!)56viP=DSB&nQc5x*az_^p?KP|?70+$_xv8i+fgD9 z(#lUx_KcpZFzYl%<93ZdJl!pbv){5_-9^zZ{VRD@3BUS81%N|t!fgQwZ+DoZRruiQ zWpBP8B^qK^YJPA%%x8ywlCQit84xJyLmw7${U|~i4!pBz#w#l|RbOngn5%$fu3VHu z`-(CwQF$C!l_@dUaN{1(zSxGOu^$ zP({IkNPLz*`2M$z47n9pK&HnL@KFFS&RHnZ=)H!?wVHwXP6pAL14|`g7 zoL;dL1hDvc&nJ!`5brx0#~#371;P=zQpKtUeAwy-&Z~T#fU2`|@^0NQLI`D}sxS8# zhxJ2IcGrg@O1Dy?cL}vQTvgDx)g~7f#Ktnx+wPul?jwx@9P&RjfAcUxUctRBSEjM* zW9EVV!je!K8&2n}#%*CrW3-64u=C6Lm zivtfO2?8z*XzaHWu)c*E3ie;#lEFgZrGFazo^3PiO-msgmzF@JWKLLYU)`Avcf&h&D6 zEeAgjVFa(-^mb`9>v>H#uT20)C4AQlxZSCgqJi>g6@Nc@$v-qT78YtPK;ZqQzZ)tZ zfjyoZG_uifs=fRy=;=EwYLma7I8MlJ`YLe%L27@7^9_35j20qlfQ?3L4%h%NbS|& z(v;--o-e~zH==vYG0rk5ynCOppb+qaI*JcfSf1=r+^#IT0~ z8yXH?I96lO7!^AjV>$SSpYFf!XyNG+mLU%X*SgsJaIdmq=St2pv2`bWupW(sNYsQT zZ2nO-QCkSiFIjWt39J`sRQF%_5_h}yr~EGhn1S)ehceO|AJ#4$W5J(6&d)AbBNImW zq2>xG<^*L#GcW;mEK_>{$MBE5Wc+=HO>>KHG+h4|M$#K*wD3Wq%2j6(hRIoPr7GK?&Te{C7qp zUgZpWm8CxGxxW8l>)ARJ<({LNZA3qj{3Grjgu8Ab`-7!5Wc2pBGA&*cE)rXGyfLuJSqf`f!aOmdvS7`--L07 zW*hS+IX;|zdOO<6j?_~>fl9mW8t8B;Sy6c<>1353iBKPmGugaVb8}!Po;m=PR64iI z_a8if`=Y0M3R98{*O9dnK0)6=zidt+D>+v^rX&gleA~rLO)*}#s}=VS{u=tCI0fwF zTqVf2t$XGidW>)B^;u}waQ@U)$oIhGEbyFI6|Pz>JV$#dT*WHvH3W=PHZ|6CkuTV1 z%2j%y<~C!`NAWGoJ@-dcuVuw=M#vX+r46;hi^xyqZ-Ln}5vQus)Ckr@&B~B#t2uCH4x?t0%Z*xxW*D&TeZwXNY zp5@z*4t|^cTgJw(T65ju{lYFwx%tLe4ji(!L=5^L2ZQk)fT1_vPXJ5ok*Q`tvbD;t z>Aq=S;oR##_g)(X2y0hs*>!lS8>$Qp;z;w^vYQAzAArOT$Yd`3X{3+CN;07`D89Wp zdI3GrM@YyK=?O14$gvQ6oMPTLh$JQ}M*0R{QQyzt<)HS#5AgcZiCtz&@Mfoybz5!} zd{%uADAVG@!z7-fbQ1%ooH zO|%5%t;@-o(9<*1cHLW5&Es^mOF4o}Nx@v0nY|cWF^H&?pT;AA@vne%+4|R$g+R(YBT$e@UoJC%a<;v&uL#&B8)oX^2 z*PZ#C_WX4DB=W{51uazNqlN1PEj}Z=x7Z{rX3mo>Ol)J?7q+Y<|J>MYXj|LQpKTqX zlKzE-nfI?>ZLPs!n?b9WQgX)vWzi9xq;ZPb%IZ2jbng2O z5&iK5iA2?G?hqy)p_bo1^;gj`FbPGiAx`RGD zmShtAlOZBuNXSv40Y(ba*_U`H)nD=ihrBpsX83YJt^w4$=D=^?sf3&A{s1#oS%2P# zpxGZ%;Kz24Kj7p@-swc)MNbSow7>Yd|Ms``##i!R=6+n1+@x8f{V-p6Bo^A)&s6|L ze9|UbToSuC0wlT6^cJ|5@Y&9Lk(180Zs2duH^!hYx=D^|=ztk79^_dnQ~}D+E7!+@ z=4@vgv0jw4Qbc&B*hdxN-UoQ3KNdXFbCv}|v*F6!g)#dC)yD1I(>`A&|LyvhtOre> zV5O9&u-?l|$;w`N!-BNI-u4@WR^-AeI;Fx#yYBDkezEJ+CAvRjpu>U}rjuUBW1>sIuT)pk3`tjdOYahWJajDUe7U&x(`nCAaTOFA2y z>}#fqOb%N0V8)9DWjaKDM@?-+&;HQcobyxTO78nE5tOs{!PZZOK}U|q{e`Bcl?E}U zLmk92rKg~5s~?W1G*Q8KgYdk{8HBw(E`H?W0~zVhuOe%eyI%KU9cdhA6_<%y|pSR-K$4yW$7;)#S$V{ zEf5w0!rRPXia}gs#G!;-{CPt$QIX|N(l;>{f-O(mHz=B%C63~KJDxNEAq{@UYO`75 zPvP89P$t7*$ynQnjkd2Dn{h`)g|yjc3pcNb>bz4<&D$)$E3STi`00Gz^coD1H?fDF z=4aPcxup`jvM5Jj;|39*_{RbH17bVs*4e4EX<}?>g84ftZ#3-U?~RghT~MUS#SjWm z!ex9eUFEusQe`EFDiJ?O2igq*invcx3aCpdYWBgT2pgKR#U?|FZ@5hH!Z#%Vu!9qp zhqvsSl5kVXlrx0mFDqtFvmR8Vg<0#4@U;%q*CI!Go&Xd*v2wSk@^pj}3Y2>LG^L!3 z1D3LES~uX!3Sv>)scJAJtHfVhF~~}1GJsExa87Iq+!IFH3bm{Mo(8pOKC|m#QHoT4 zWCfEMBw`FNu$b`oxzyr=AX29HSZkVI%bif%LDw95^ZW#2>}FA925zPykga+@!3Kk8 z(3St);x2P7Cs3V>uDe~h^^j(chn?S>T-PJH zG~?V;sgOM`5dN;$S-_*J|Iw=j1QxxqUTQr3PhR#;tVY)oefVL0MNG}sntfWt^#Em6 zo!PUvZFP$}i`iAQ#p5%#syKCx9$eefc$%BVe$Yk(dloW1mD13U#E=`syWT&ia!+O?j* zI?!N=5e7=MV&V4ZAB2}nLoWM9Dls>4H@-b8(dwq-pe#Ayoz5H%sr#YlR1?Lm;Ivg! zQQ4*bM+}Ves7xKCIiQ%y4KD^(? z)NVsj%(wyCbKm*QRlXYuZ9g&fcIZg}yt#F9bpP93O;g+(A9zIwY>^q=m>?{$;A14< znx|oa|EAtpTH6H>E}J*n+c3tC8Z`=obbBAL2C|G|ZD8Ryzf&uW%`BeS30Pq@=mO5A zx|UFyyZ6QQpr5{M@c(o{{$Xo(LgIeIFxvlQiuf^d{wn~DH_Nc#7>8F_V(K=ESpk#1 zdGZ=Sm@4Ug>3=7P5Q%4|zc}E%%$Q%)L_#Gk*b1zSJC52pjUN-d@T!Z9Wm|)^m{8pT z@+ulGI7+=oj6dVC4YZxnNRdB#LdGlk{}bT2EL<(q%-`bF;>u3i<6r7K5IcAF_kttyAUG<^NtqTioeZRb+ zpNKwSpSW=v*0Ap^Z6o!OQ&&(T_4lW9P`#xYmKG9X$sbF0eVR{b(_fo5M24O!aa)M2 zmcmZ_Z#|Y9cKcNDIEhC5tDc;W%yMLk1SG$+&Q4fXA}h{U&BIU{^dToyMo%m&t}1`I zC=~V!RHSf!$i*<(VK6Rx@-ITU8V+)(hm4MpjP=;m8u5T}vm~zVg;8Hd=xtVzKa>lp zezuh`<>S>+g!aU&LF`ZKCLR`ru0Zv@1}(Ks5(i}c3%muwC{sMe6v|PavdDU#HakSf ziIv=?zcIc@k9yb|tvlyMb4o@G&q#Q+ygJdHMYvTtPRH1Xm@ouIRC|yTP9L?qfPSRi zGDsUocn26*mpt`qwQR#pQn4?#Tc@xCd+D^Fxlg?&^j=@a3nMzNa*=V8 zSX7^}J_Oc!jTU;L8SG=W)Q(=4<*>-6!f!aCc=eIk#nHk)$TAkE(`8ol%SMvkF>GTz zBO|QManf7OJ4m&z7AObo8P~D!1R?#VmC^ku*;%`|nmk~gcy3FE87H;f5cvOunwoa4sCW7htOFKGpk36=m{dO!YO3YKrIn#1zSVRs6J3;`#;$)5c2Gc7xSULm!ef z>OM_Xr7Ni$PwVyFYmwBa5N4GnAxvrKNuih&y8pJOD%XSuhR5yGa13o!9mjUM)jMH< zToATQv2Cp+-0RNTJdq{cdbmu7%9Yl`w>%^TEs93m>z&a!wBBcYQ>);}8B1?%c)RWu zLkKZZ(eJE-VsYxIZQ!WC8sS@8A{8 z-l{#Lt1_=>BydujDrPhUtjkOGo^;4P%dZ%D@jT&WeoMmJ3HBeC!k|ILHe?|wbinjn zluPWeMS*vwJjUpJW{t|7_rHV~QuHlq@v0XrjqU>I;PqoPw+TnbA4F$$*oWZtNn}#G zD%85H&ZHviY;x(OSLHs3Q1)`*)KlApvcc@KGy%dF;bNDS_XlmwHO>W{AmI-Cm3gr3 zb!5CaW~K6#+!@0M{KwKG5eFT6cDxZDYc*}sr^%`%5sKx}-4rbxN2}#2Jak`wtk$ak>o=Fs$G&0Wq>h+( zr|+8b9o-Lrp9`UoAV0}|zO%@hOBUJ}tO%v;dR|%pM4e?tQK_*-Ar?R8U99gQ4 zzlTIwbJt47S_{@%h2-&uZDYC+(~KzP1J0RM6#r5m&${;_%OcNRfO?&g`SUQA$4<=D zq>RF{B>b|lX(Tj&a9bHzm?RG{=zWy^b8ANzOth2NPKr~YFu+@adc^V-<0(9+k3l+W zMPZDKTH`3$fV!ta54@n*Xp<9)?=J)-PiK$vhZNzBVCme9Z*9HqL|t^}JY;?=`ep%CQRay0GeM*ce4jP#Ok$ z@vrm_eWBAC5IEp}GR-97)T5YQI_`CLF=hF!wp8npaq59WGe7!uI(a<%|CrrbQ6{>` zi8=z!>87Z52Pb$9mv2sO|FxIQ`j|@3u!xbb@sL5*%gvUMx=)v%eOm`OMi2kOap#r; zz&4T*d_gq$(xq(RXyywYhmuNY3m*VSGJ`Kmj`AfMD1r;eWt_CiDQ2CJTw5;iO}fRV3DED0)In!WsWflH<_k*l^flzrm3M>l;cAO-Q2x=klZh&-O1$SFW@~gFN)6^fcS% zSi-Hvtp|)0r0YwL`uUXIL*xuWuk^0j__egL3E5kTQ%(LwM=n2@izPIWSEw*M)HnN7 z24S~-MtDevz?M<OMp=qgqc0_TSS&EaKp5~J{40_+QZxJt4N^0#n zVJ>0$P?j2;G&%}J1g_?fTH7X&`Jw|wd{9NkkL#;A@^&i#VBn&YQA$s=yu*7zORq@Q z(f~#u(b$=2=8{~Jo{D}IZHYlPr3?r=F()PSjZ#GNI`mpDJO|bs$nrW^7H0YHR4IpJvPa=5itEp1UOw#H<+fUua=IwEh0bp}8>NZcdEt5el=# zFJMLH-5((bh;TaP)$dr}&-qLJMmY3!eMH!2if7EC`Po_N%yf(_stxBIJZ_LFwjESD zdS5#Va4i~etTPq?8*y=IGH*VWT9|E&93uSUz&*dlA7{=2?cR%P?h5*OD^@9V{9daZ zG$fQ|uMf{sJ}$c4UEylHEFMxuEo z!JK2qm6G-RrF$LAas!4EiKQ`{%;I>3uRTvxhqQCmc%P~lFzAU!K*Wym{niRNz@VRy zLk)z$X~XF5Yt4nj=y0TD5t~HjkN7%M=Ul#mbYU4zVP}rZd3NxuI=1BbT}cFU<;zTI zD9*RRPC*$%ZXp)T4ne65;jE=jz-S+_cE;lq{Ul2CP%#?pA2k6ZG8v5xOPX=CB#VK@ zXAz=lsYONRdg@Nqs1%8(ki_DD`a1LA4p3V)@LZ55+qXM51xo7*BHs%{%z&cZDb?7b zi0HJ%PHR6?0>19h8J6>@J$1imeD`slf}rIm5nUWHH6v1-M=7YT6l~QZS-wY>A)OfY z+AixFB~QhOPN)Li!V_c<;j-*CRd%~oV$ZHA3XhFTioF9>Vp=a&D5@b@BCbtbrFS?~ zo#t$w0HQz1RI;>ysZ7PCGXs9v>;Oy`WyxyMy(gza5BBMd$Uar{6duUA(0LAv-W+_8 znG~nMA_VZ%Wce)txR(cmM)ZxKb~q{<{PVB`?^vG(^^Tc{X`OLTD=Y^Mg832G2Iyti zC>_-80OC`7el7iRAG3WnO-Jc zv{Z5jXH}FLx~f!FMLv>{Lsigg*?;Bh8lX+zH2J98NfJdi3PFv26|WdKH>ZxEubsYT zry9y_EKnIql}SxBpC!OzV6oZl z4D5y)Ohi@GkN^vW=G6uo86G^gn`uf9%Au*5Ow{aFzW`7>z-g`M5op12k!#IhzBs*a zbnUV`yL*2t1CBoLmA8;R_OdCPmKBRHtp7&ySn@&{9trVOVN6dL9FykS=@4|jQm66dC1%t_hVDsJ&Y9R#-Ga zow_&{425RFGBp9~UWu`_1DHu@6blBI1a*R^+)OyBStWsc=s9A2I$@j?OfDxCUJ^LZ zDRx>noRfBmEcqN&Uxu0IjXkI@d+s9nS^RT;k9nTx{rU=^)I%WF2nl%H&Q9)+;`0{| zfObj)(PJCoy$Ec0$t%4D+Zw&Ifd9nUKIRzsW9*#i5~6WP({Vk0ca#>#nv8-#T? z!)|Ew8jDZs#rd^li@Z|z`LvmPlqQX7T_(eNWdF=sH1nCzE*@b%A5s^jN3yl#y;Pc^4tE`W3leBe2 zKvKMDr{ww**x0*AxJA3C= zTt_~-Yvkf;)rc%@p{OKUvIW}gWuRWUv-8eKd59%0wh*CXDYp(7j2@upe7ZC+kMXIJ zK$j~^e@UMmPiu^NiEoK|3N#-tBzJ_l%LsGzua|VW-QRe<{jedOpDuPmFJ4Agkblq z*6oTm&-af{4X_%5fG<724gZq@v^^pW)3*zKa~o&pB1d(u<(gI~51Nzk!CXotu1&=7 zXBX2e5p}x9KY`ftd|C3*Om{!qV3QA1Os(j{Lo8S7sb=>CuB=br&z5(k9PL$)8s6;O z^itfK+y0Ss=Vrs3p*kkABVARe>86h&D7CbT^7Z>as^`SW762VRd3ewM@_!s`3y0)g z;f6AKeNL+tXeK7z05UKd>{_mEa|gTUC3-N=0+4|wrw%M$35*MDOvyawa5>dbBY+Hy z6gXCidR@8DtOO3`l0%5L+BA76+iF>yTD}K#Z0J!oJai|X3IJV4^0c0Bqu%rKh4jT* ziE^;hG=b5t(X59%^0=;q{Sn>~FS2II)m_tWox2H2x@T~~@bl0yy5C>_ZvYHzEtNH8 z8&`KYOl|qJ696(WS999hb(sEjizH^)xU7Rk1!4L7pKWX$=>8`6Quo@S^4*y8T_2U< zE{yKn+<(RR8r`(Y)i|_DvIA4uO&C)wZJquKv?e%}%Zgfgczdiw+S5=st8%+)LdJTM zLusWkWi`YH_KiCRtGqKW)3Sj(OhSVp&Z-4|vmi5tWTj%O%=#I(#@$GH zD{V~_C(^pwK=+1~zR9jB0Cvm%v&NS>ugT9uO+-Dj$0eD8iGK?`hHPqP^hiDn9eu9b z=~F*_!`-qh0_Z;*+vR07$bk6p112_lPaQ+^dBZpVgt8{QOc`tQnjcMSGyhrh=74gf zJ-w$zvO38EwVX_C$l$xw#V3N!;XZtaOe+w`k|e93Y0|BBH*tN(A6X2mo|=D7ltRhu zWL#(do7Sd#z_jzUQ>{Nw2V0zIa=-Z?@ef4^EOvBbesNbummj2AkREb-$fRDa6pkW| z+dTtmAvb^wxLqJe>A4;0(e>zBM`;(}?<2RC*%U{K}d|&5t~_CGI?+Oxf%oDR22r)j!SSA^Kie%%JA>086fY%<2`vU46pc z$&KGOA55$a=QPA8I!T(O0tZ>At1C6C8r_x44y>Jy?pfv<&sgeRbu0cm8cqWV%KB!T zw7{k9oW{V*+EzyMz3~m%)2#%3;BV9xAGkZosdl>WguOoT&C0(E)PGa>i0GcyI$Z!F zb3r=L6H5#oisyvA11M~S6)w4sXi0bAa_(;3QQ+>Qk4v-N3vd22SjvsVdS;syV0o97 z3{bNdH{{NcHfN3i?O;o4>l@HQxw%{>W%RY^cV`=(mCT_!I{5ukfLWS_w2t6Jw^E~#=*BgQL%@KM5&xIFJofgqE56aXzpo3zsjRMRX3Q)j)vIb9=Xe)Vvrpf5QglOu6Oh*%(lFuHIAx0br-cKYXg2q z+$f5e)2s=08VuDKd;wpXqitcdA=i+0WxOsWC3q=E*-UA&+JXC2s#)7Vr#hEWy2^3^ zxvRCmzjzP&_L4(;tq~Wllf;Kk%`CG&b|WHk|AknuM4be~+s*Qa6cT%;On=H{0K2Oa;M8n~_QpXj-x8rn<$s|7S$W;#!#FONJw8~zF~XO?u3yRsa(ljGGMl+6o1 zX@t~H=tQiqpH2`a-uO1zsdF}m)!Lnz${?y#|K(h>4m6Rc8ruxZ+6kQ7qW_d0#vD#b+=RNbp2z4wQ)K9 zF(n-Ll+M`%AhIUN2-;WKO#p)36&QCZ*Q2>1_69_2Qcz1el#DADjV|%0K4hc^`cY&6 zDZ0*^A@Eq4we62}$4P_MfW~QcqpKjQ&i&ojQ~}I2tpl9!;LuI+1l3ksG#%a63YnoM za5L3AO{I!qOMq)GNCh`VtKu^+DfHC5c)E$ZbCgU9H_VnkcDkJYa zu3)+-8|{l4G<2j*)!5-=i~BowK)8fVaENGn3W%aJ64H*k+~N*SCu%iiV_5RXdM%Ep-F^S6L_0 zX!3AvpAMVLrG>r>0Im@HSiNp{ruAdX0ZeNbZCGyF8F&z~3N|}!Y;5r&X{)%ZY~EP^ zN6pRm02u$ufAS$?1mi_~?ACMZ!~DS3#(m3o;RfoE<-u8}+UW$47f#nGXFR#eM&T!a zFTvN{wuHo{*8=cHG%0Tmh!j zUbQ&CR4OtLbbSy#XY9)us?fb*p#7LIyOzRG(%)y!M!To<&SvyIP2-f#*@|wRIZ|TOKXsUb+LO| z+Qfva8tTR>=$g_yn?svcDZoJ0 zuIRAAx6-3;HAIs{Tr#L^rZdmkKMo$Zv1-)WVp~-+`AmeX7X0ve@4|~#_Xld=)HydU+c9Q8 zgEFY5xbQlP0=qw}+~>zGVcpS}-2QboGb zg-o@RYaHlTY|X78|LbL?>^yaOH)As?xCgGc%Xw@Arjb6?Vk91H?>ftMV?^~t zN>b7aU#nM*9HX`NQm?kwQBJkA9U|MS&T{*@IQtDbOEMTfi}ln3cgwo+*hZT)u>kMM z7<0C?bqthAVP_Vyp(d-Fugz+V0axkL3j3Zm=weYzbU3lWrj-$j<18vX-(+WrQ3{q6 z<4-UCqxm9A)Hqb=u#`!f-53nX@hh@6nSJw(f%Kq@hwlDZ_xhV)4oMZS<(36Tn-z1( z%B9D1S~^J+df;|mSe@8ASaT#_zw`!v${}4N6Jo3S*<%@EL|pe#oy&_MB@?BiBL4#6 z6FeeH(^R~X*Dq17EsikV9m>)3P^KNE0JzwPsHc%N{^@_vZ%`LoK#C+*Min`_UAp<~ zvizZxp|q?^#Z0Soi&O=_{Ng(}GPunKm?{cAEO+*!_>f(1tW?>_K9WQ25z*g%%fp#F z%L*M~Ij*+4KYH%E{uo+KOy%-SR1sJQ#;<1j(>?-TLJY z#iBYa{gTCfuCb~kArOdK@N4$(TI(4Hl6dQy7>@ z@ZRZyMRvoy{-xaEU9u<55=GbfvQuInvLS!Kv9L2z2I0r3U|r_CB4;YqSfQ@RRnxP8 z1IlCtqDWrdDfch;5Mtv`o)4y)_>y4vZW4jKE`%l)HLh~?9ZZHjwmyK`D8bi%LU~A} zk*}a1q=N;GLH19{ewoT$RArSz{a`UsWBfTwR%a~nvy`djmLG&^E=Qh3EN)=nq?zyv z8oh3z_(6LBQOL4qtb3Z0)np*nsw8VR+qM?WIZTOb><$&fmfnEEazi*KpP+5Mm5|Sn zut;%iKanPS*Nz}>6|0oHQrmjC`+!;>)r{yMDLZ|p8Azu%EsO5SRRvEeRiPw|(Z@-P z*L9lH*T;_cR~*hXti2}~Ud_1I;*?$+9XZ7_<<_zP08`dFR$VHkHu@qzF=Y7Ut{<|< z3=%ao=5K@q>r%K|KThk;;(D8bdeL=Cxl@`Y5#U=AR}a*O4mYxcAvw)M(_=#Gko42l zlh@fbRi_F&rx-_^Ri#;DE$YEEja?H$qWmF1T=_C7Ljm$ESXGFvhv)HZ=%J783w;GI zke0YLU}ByaMZlcImtDaRv8bJqba8d9GZJjTmSJYhLAA`9 ze`9W#o76jMUY&n(q?UNOY2=WgGFw4mD{(G!bldLh%2QLvMdC1F-E@;^&#okwQNo&aDl zF~?j-!K*4^Hk5(HY&eFyCm#x38*DzGSKWU;Z>&?&vjJYw$y%FP1`lt)X0$A&NK)!- z53zy^bU`lMi?x6No&3_M9|JhBt1_D#&|)DiO*DLne6#2jd8wwI5Y>H^5S(_J05o<9 z&TytHVzL&V9Zb$sWymZU&bGR)kl@XdkP&_N(AxVLSDF>@qa9l(It@wNFXDuJL>4pJ zBUwC7u|AIu|I!~{?4_rK2G$U<r+9<QV)Xw5B-jcI1)@%fV(ikS+bPD653r|NNa^ zEXJv$bdmXy_*c+WlX`@~z*j<+5d!;I`GWv5Ye%_PCUDn%@k^rI-#TJ?Q_ z$J9T{?U+)CO+QifRm34xON#GKl=bxT_%qSp?6t)n;xb<(Gm_*Ogsn4*qKyyAqoc1E z5%+t@C6smyk`;C4ndk&Zc{D?x6zwFG2vHsp+DKbty`hKPpU?+n_|W~P)6)Y-cup(Q zL8;IdhuOs$4dBR)1J~nWZAa_EXtio19G?{8pGwqob&eo%4Yh(oN$1D^^{kJp$x5+ogUrEb@byXgep#2e0&TeQMbpdlE|Z z36oV*r@7c}5N?{Rx{Y;T{HCzK9Sxbo@AIMBlxECFf=IhHtC&cYaj4yNp0YlJRN4}{ zS;e>Pjit0rQ{o_TXKyW-~Fi4VZw>~Se#^cj3@N`fEhYd8zsQ{R}*Q(x&W3SN=xujS(t43Z;FAsssK5q-CJWYc6>QP8DVzH z&Gpy~eao`23h~l5>y*f{9AE88byI%R4WEB`_h|{q;LR3|Ev*_S?=NvP_IBBh!z&uK zWTAp&o4mxqD-p%i?7p-4jiaPl;Eu}uKZHN}Xy$lAT1(}^9c}Ef3`0%OAX$1LJ&sbn z$rcIMg_uYyPN8e=DT&JKx`)(V%bihj;wu9hr$hq(;etq;qr$5dMfF1s{FbEDAaRUI z6+dzSjlMG#+tDNsr)Oy$3Rn)&5>&2SEw%;<@>MFYhrRo zej9Dr?ckps96ZafD6DI|{D$QDW&S~AZDCE;rDv~dJ$mkBc*doS^Hue)x(k7Di;KXF zU@+K?r3tK!lq(Jp2_l(Uy$+v7CdEZo#Hw@1nHj*%{W(uWql`SfW-2N~I9p?I2f+WB zv{`~Eo~L%UagSH2GPVZ$%ytK-Dj8YWtq+=Lw6eC1uvfP6w4Y>Vr5Hp#EF`-F0*Kv! zVbiE(TTWTF8>Vol8=7+DxhT5~TLPr{qJr{{q^(BWnKwqIZ+=y}@v!*kqBEqVji#Bv zxGe22N43bLuXievW3?>8m%g)oxW3jR$I+O+n8kXKS z8!njkrmEpwzm5Rrk8l~X7ma9pG)F5HSkPH#N_aZR>c=>$3*!utgkvZOu}pwkA9@RG zk42w}LkUlFO6rH=CH|8Vy+1Qg>ZKur#Nr)p7Txst0mS>|ZQSdj@`Wjuw!Xo{XS3MP~qZj{WDhyQ6-~I1>>8XrMo0 z@yZ+TUHCGyPVuw7JHzDU^C=WwMzOP1wSU5X2Cg5tNE>UB9JG?ic86dzn_V5#@+r%o zQ)w`w$Pq4ul4kS@U=FxMjHgwJO=`KAOQX`g$G$V=7utGrneh~Z0M73YiYic4`q8bM zK3wLHFhWU2e|EKtM3XRi&lpsOh@xIt*5PFo5%c*?Sn19}u}?(dPzyvXvn?V#AP~p} z*8DT#hn=Ei>FuEQ=A67&LXw8~qr*DCChVX{{Bde}g#M>utnuZRt;$#HhVB&AjvkRT zO^~iuFA4aT92Uf1x~1FQR55}tjwHtuR!_wkCgglnLtgGGq7d^hTUUq#*n2jJ7SDM* zyM>oPA?hv;UW`-iNmx;;N=B9HB+cT1Wc?!f+ih5nVW!rFbA}UKJJ5gK3eqh*LRXtSBK_pK%%_x->QMF$jO7o{aGA*C% z*rj2rH*@lGyRs}tI=XXbLEWfwHmR(ZNo3H-TqF$?ClDIy-e`X9^{@#(MWs^UN@p-r zgH1K})A-g5qoV+yH#4BTo>p1n$vflN0-==u{#Aj%osb+VR{Gi~oqwo-lUL|sivX|A zsZqi9e%sL;lexX##kHG-g{-EiZD{kFTx{mMfXQ;I0?*P|aY`Dd5v1A?TALuCq^1PD zJGXSqxblw7aC!#TT2+jiO0ODU*!i13!(~nSQEE|XGq*>X}FJdb)?1-j&mN(JZ z;@xn%F!~d3hMcqS5mhQvlV#(kaox^*owTYvwB5@QWJv(7$^-TRWONKetF#9Q|5KQ+ za15FM9h?|zMc_G`B~(Y~6dTO+sE~1ihY(qWVS)};VM&q%oD@L;s_Y30{MyFohz(!T zQSYJGjGXTU4B?il?Wo3Q)5a$S4|e)oN?+8vcZyJ+E#(zOSPcQIqx#OAQN|=5i8Eq*bDg!7b8y@H8)_(N%|R zA`7v+cyt2ihwYfAW|GkrGa0X!e=yN`k!mrWW{!2sPlI`Nc#DpoEv$UQX-X}j>5y^x zBSCH>qgRyp>^K2RR_sn-@|UkZn3QT8h}1Um(~1{cP>(Ysm9iO+b(W3K_Y{}$whz{w zFRB{8z#4IjHc6N{4PDA{oTfghOPosb)$v&c$fA(uPDXQ_Xnupx3|`A$)hZ%`iHOK< z;04-D*ZI!2vqYzAD%t5&C<^pcqfn@9?39n^>5!=dEvWSfnVlMD2y!E`^>$fY4Cb%` zIJG`YBVP&g`}CrF!evL`a*}EIOcYD0i4~T!D;O5O(1EnXCA5Yb_IMmCFdSVS;J5hc zVCcJOf*0?r#n>=XVj^e~bRpX*J>>QVvl-hF%8ATb8KoFzeNvxZ5<-`PAWoS-91-y( zZl^|kq$eDFB0-G|mmMf@ExUsm@8S*1E*j1{JT8C+;eh@6MK9LSfaxN}x%v#Up$$D; z_(}4_9lzv8k3>lIi8)g~In>4vKrwb6n~V%TY7%fYS@>ved3V@BHU*k0bz*)J4Fd&% zqP5g@YPNS(2K59g%4t5RO0b_`EKlUUD-dJXDG86cZ{OQ|%%g)kh%ICPe*Y;gbIAOA8-f_a|;z6NfU4 zjB2(OlttI3G^A)z8cpK**Q`Ym(Z4gT#@UPA_Vs zPW5kd?Hs~MM5rvjKP2O)^#`iTW$wZO8hzQPl#MO&L$)m!m;P7AN~{dB*oh1VB|;{` zh}BEZ(gLWNlOvmRF)8aRe}kjlMV*J0<)<@j!GcnQV#|hctPHy|-qFOL173l5y!fb< zBPUVov0VoZAu)>T4i3+cAWC?oeGO(GWrdl+ss1rUqEZRGq+&!1f+qk~k#!aCN-|e% z+6t%bzEPRQnbt6(7kr~v6RmMg!4l5Qfc;`_ecxI1Xs2WpR1X~IMw0B52)-)|Ec=thtUmS)^wlzheis;TOkZ6Os9#8*-Pb0on;?6)wpQ>` z;6P>bkYNzLfti|LH+1>Y0?S;d^6pY$GAgUStXvBf)V{;Zwx)`vdc+AdK;oL^?Q^5(n)~-pPvZKm zEv*f{K>u`Ehhl{+$FBH5^DfpugOKOA_S4FDgG-j#+CCuFFHW-%h83q2ygTP5qAlB) z`1APsCCMhz62)l+jmk*}5TCmr0`E(c{l{Sk#7U6)Kk+&AJI5+I)S@C0g^OTqHSD-DU zi)MxicuHlnAOA1*(s6$Web;9hL6yTcGrDL?>B=#Do^tQ8fRBF;(-qHaq<17fIa-yI zYgpmyt5D;)Xcf|P$_tek|F-ma9sfUegn-(dv#-U4c|V+^@FOpy zKt!A{OYwH!l(7%ta5L3Uz4R-KBtp{r6{oL3auFE%K)JmL6aQt(Db6l)YuD21Eb@pu}L#l30cL3zb+;gU+jCuN-;B&!q zN*qh0p8dG)W$U+VdjgRjubJQwf#YlPiQd_gp4mxx`OjHg>Gi)pv%^03|IKRuxEEyg zgG+x;O+`q1e|O#4AiW6mm@|rtvW98SZ@3};jkjPzc7a259&iF}?)wq8m3rrR@19d9 z+xPaPlo--SRYXyNMfkCx;wRCMH+qZyWO^db$hr~H;|&oCY{0@(AAm@2ND#k)&*Cxe z?FgDz+XP4;w~$3gKkXy_YBTk$du`*c91Ak&K1?4Lne94ali=Sw-5OHS*3E2H<<6RR z$!(y{yKo+G5<7kT$UIpY?9f>qUwD97I5tHBILk0pe+ruZ z!YG}A$ZxO&U?aQ1RHOv*)l%&No0kMN)Ez8OR!n^2`(ar6ZjJmo`~Yc0r9BGv=H>2K z35+7IWk%WGRfFwIyDgu&4;z~4+O5Bv2XE>8aEklCY99r()@DDvAv2fTo}Fypuy^Ge zaC$XOsMqoMdX10goK$?qAXa#Z1hiqw-#de+2IAhpc7f%b21SDG47w+amEvsl3x7U7_ zR+qpL4UXUR8@~o>5;rI4!6Mef)--CjU9TvngiUpENqiDL>#go!>)3muZpzhGDpg+r z>`V9Lml~CJ3P$&jX`6$X6rIEoTQ3))`kXGEdh6ENn5{=fsBqV~T@5go?yQBY4f%?E zzgOeszmkR2;|F$o&OW~=J5(&A%LsSN!;A+tW8(JIu<2E)+!b9qW$`A%w)!}HhQTFJ zv)*_L>UYYO!kcOkQ-}pk=v>W%z`bkt1BgY+hvLh#vm>Jnb)_@DB4xkSU68A&|7T>* zm!@2t|I*&mw7dvy4OlEf*!G?g18tr;m46omly3W-3?B0 zWw?ylN~bYH5=Oh6cmTAPRw0K6~c57r#U_?ka1iz={&9lbe) zZblUKml|S`P|=xxp@RY&PrvgF0$WLfomD%lWTd~5!S6f)16QwlXS1N#+(d7kyG7xw;_0{KbKjeAb4S02xCRuwCHe0VisnaJw?D$>RPCO7B?3%99mn2W) z^Xzs|0DrK-(PPmJqxZhoYqx|~4VIo2vW%d9T6qH%X zsCByH=NE5TOJenNYv4=sNpK-pR4h!oe%yF{ds1=i;P|Rxot2i`w>i&B0hit)XWxL? zZg))ld)%>Z<9DBfZ#tK-f?*r?Wzv4|E)wW?dPTf|fTg>3g5I=>yzV2dn$fLEZS-P# zlL%q8NkPK4y~m7Rco8%}W^X7ns6h(GxG;<{I7tQS_dc@y=UAp?n+GQ< zkc^IR+c84Zrr$Aq4iqLM-y<&Nu%|S$z}wn4x(H`gsHRE;A)Zz3HRv@CCbhWIn+N|u5oacof#j`#>O4whTDc+55E8BNR_1RlO)Ue<>sk*Fe z3hG+LlQ2RqsF$`M>RFApISWRD+A%`pTV3=YERttb0` z{gvUqY^p*qjzJ8S5e9;9F>c1!>Btw{tevEtm)c0@N%~7Bl8Ip$GWDZMV9Nl8`$8)T zx3~{1r;Gz{zGsg;ZlZ!35>p^03P7ipqy>cPUjgVp&Yk3Fvrr@u@RnR`ncUFe`ZM@a$<^Ay_R;U#U$+K@+G7IkNsi2FZQ)&H_{5-U|Hr4oq-dEQiq5-5I0=D@SgD*g4!Q^{*%3%y=wrcj<6zzP74DyoX2&M!l) zLRMWUOu(SSd7J=KLZt#GtH$jbF>&}ouEOI3gK3q*-2qB3Nhu$>q_?!PqDRZkR&AGBj%c;fos=)RrxX-5>E5D9@O^G<uZ1YPIHeU#Q} z!RVM0Rrt)dWtLR(-ZJbfx70+(M)9kO95;+O?`nK>>r$|I!=O0$(xc#|e^L^g2F0NO za;1&76#wDR0!L0ZkJV8m_^QyQxW`}G>RA~~=|%&wiU{SSCfuwK_VUS;!~~k$V#s4U zC}G54af@a?;)0e$OpywhX!1$NCk?&ypjO*l-i~NIn+tyZmkv-2K6$7ju5A;q;O%GZ91@C*UbiNReDduZ zQ{M6+N8C?Vc2!!ebDPY}akbi;%!=6c!jpfAqoNTVcSh$CA-(CSQ0RdVnjWDHYU zYTJBjxUL5Lyvfqz5x0(n8<^DrYq-5cJ{e1(g+y(~a|M3+$_bv_! zs7MjehhYhAfKYt!2|&jl>-VNeO!hDCCS7IC1WK?+1B*HB0-3%{B~{q;rc~E)y%8Kl zfcbj7e8G7lohDiDfv@u4FJ*XwNTUcg13+ZulMYi|asAzoZhaU!bnTm&2U-6BzT@=C z)3Y88lrsQ7?DY9F5gwCA(;4>BZi;*sRTZkxkmv-=o$h3+&HR(FodBCUw&#tuDQa!@ zr`D?(UJ0)uOKYtl;&!@RGak^LAx2+8WnRyIWi3=dFaTuuTc6mzdye>GY4tA&JBi}{ z*dr^xg*!N;{|z|(uxZT?r1|B2{jp-`FwdywI5H?y*4gOWO@9kzmL*7q^iojVfll#+ zr@Bl%pd}j(g`#e`-vWZ5#DRn{pu~nvGmnmG=byhQaj2b5Yl0GZJQ)w5b?iaKi(lD8 z6XH@X{@u>N!BJt~5jWDeeN|8;ptlq9Bk}NqnF6tMKY$Y{7S=TS%9LMt`N-p8YZ|8n8Ysycd#n+c zTO7syHP5g|P$jGwwYS<1Q=fgzjEx}@Q}sl2F)2inUaGQkmW)JX>nV$FwXhmK?9AsA zfU0snG%D5m!Zisb1g*BqGQN2_&|XfcI?&qTME_a})XIJn<^%n}soA?vj>l#-HDfuy zK9WRNxkcwPpHS>KBtgtQI~tPZD$JuPTWnyq_)-2#%!~xetN3j!NhKE0dTI4a(QYB~ z>W?YvuKVvh(#pWYoMf9>Tbgy`YNZ7^y~HBV5xfkZy&!62Dk#Z6r1hxU2QKmLveoMh z8T|Pw7BI`U8_oOc6@M)|6JIP zZzTg=M<)V*-Sx%OMc4q8Ym&LNnR&x#<|4fCI0qyNV|HvHrRy;lRc7lEksxGiGM9#v z-M%p{c0)XQLtOmQTH}hLv6!pK4LP6wkU5~Ub1dn{7n+injZ;n?<|{WPd-W3wP2;^r z(_4I?6j}Nvf51TLs?}T(?vo3LvbUq=Vx=L6MS0S)Lz&}Tnb!yO>6)jeofmQcTeS+2 zz{O`Scdvc^IC{?ob^7j$#LLC%gV5Mw`vwnu>j$GEzae#P!IH4rHIzRR>tgos1hF8i zyfNS(&4~k5Fr)XO+Xq*4#@xs9pM&f$nY?vWKQp^CKg`+0Jm$(0!vq~haq-U1cn4mc zijO@yFy7qJ9l+<%TQ4^XwoSoLaNcQ$V3^?r}@ymCx{SyoY#=>etp|PM! zRp+Q!Zlw5eJ06mw6=><<*a&*0Us;Q{4xu)SAd~)Y=GNi}ft#+ZluxaMhCiAvpMD7F z9p@S6&Zkn&onx5b8|n|}{U-pt(V{l4BoLl zKfHEO9Y_*_2$FCWv8)zW>{w)I0ik-2S_=#is_v_$!x~^sFd+SV0J#8W@BM!0Xk*Ng z-5I;?Jx?$I7Jn^Y5Q*2vDp0FHeCRm;JADQKLw{~>5p3yV_cTq&V-p0!Efp^vz!f$z zkSlEBgzzTjk%1Fd9~zYTgTY`i)q}T@L#C0V*%^rVcdM*&d_McvO+MReTt5|B;-@SW z3R{L7&`<3%;B%7yPxQv3&?defcByJE)V0SgszuKM)>{?DtQ=90_% zrQ1`Et-YlaRUUuxz$HR(FSqnY4FAT)*48r!;lFM|n$h)A*1PPoonUMwEX!%3$kz#w zz`nV#j!#LQ-TqDQO=Mga|Kv;iOSrRnjY_VCrZMA{39>o0S7l7d9cTiEk0(t8w8K@|f zSD$XWs@{VUyN@SU@paQRj1|dsWfCUnziD;*Z+qoCl>LmUj!C@(V~*+aYws^(AXv!B zAqsE_;cK($l8Fr7npyf$3!qB9gV{;`!Y&C3$nO_uXUW?cl>N8&+sgju_=@?_E44Z* zHo^{mXfk(&jJ+I9r%A(R@y=pd0D@n#LsrzhPsamzr0nVQLV!MG2MS)j^f4uxPnTvO z@LV}ySijdO^@5*EP;D3A7TVJ8eduE44JnR5k$KM5#m+8N>Z0Z+hN)|X?Y|58!Kq2v z?(04#&R=6{$9>1|u}NWnRi;L~Pc*)dt{L@#5%?{};VJhIfy2du-}o$~UQN+^3~xI0@ft{(U+DmA`I7lQ;#qGciGju^ET$Bh!gC ztncolscXcke`TE&u+vUInS`^pHz@Qb;Q)5oRxMOsbl697@MS9p6V~V>`rdATr1)9T ziBt<=;D4Y>@sj*5eO^o7lR$Nx08-XTYqxiM#w+UoJ-v-N`%=nG+0f=ok;>$?9loj8 z)_e+l#B=r)G8&e_-h3NV{(c^{ECa37fr`$-CDnF0z_YzzG>9T}w0NP(eCg&Kf=lk` zV283}`xfRYP$XsP7TJW&vZU-30N;JHC#F?tTMl1TdQM4>thYGVpljnk+(b8S9gmo= zCs)VTU$c_4_$k?WDZqZSz^wcK!v_`4kOB)mi-zc)T1Mc=_0%$9{aCDCg5?kEl#O5D z^QXTMi>7{uOU<`nZ=hx0x~ZZH?u7+_ysD^j^A^O>;h38kMXXV!gci+?hH}Uph4^hi zc==&DiyPM!s(xx zFlxI1Eqp9(IOB}pvIV_S>a?%rp_+x~nvlox4RP6)4|AELj>43vJFgj-+uFU%VM1Yv zM8?6qs{l!-gnDW-tm>YW`R3%J|MOcipY&kS=ef10nfpR(vtW(A#_ycVB?J9I z_K^HX0c_^y1NLlI2oAVfB1o#MU^1E%CT)IQG4=cW6BqmhnuiSD&xQ-XH=*BoKZ)1R z>fpsh*YS&%@1JzZ`(=@F6fzK(fB6bF+Z6MgM3VrShfz$oFCiiwj8Gr6v z)f|2aj1Pmdy>XD#7a;D?cqkz~nVB8;^z+;cDCGpzjTDbgeYgeawn?1XtpV~GBtTQE zL{&)KK%Y0WbuqQqgybiWU;+`YrV3p)=31=~5)8Hh+i2uAq?31=EkoS|tXeUFEsbo= zMy(i`7^CPfs;e;+i$n|o5g1BD`06LZ9uopYgpkVuD3Bqp9_j_y6f08 znCk1#F`1E$z|_2MdKRbzcA$`n1qKDAEq*tZu2ENI5j?)d%#{jftW8as!PQkvCNk1V zH)XI{G@H3V>a?Y)nTnjKM?eOJl90XziQp~&$YgRth-CpB#Hhjq4QNR&F3^VuUXYPH z+2y7pqU7o-W^f+5&4LQ)9y2^%#8r8;i1&i-Xo=Mo$(4wthJB$MTk2v(R*{IHagVB3 zG459l`>O_&YixGCHg{lib0tKDJn&n>I(0V;K0&7dDLnz=a{;~t4|Rz#h3~V^OJUKN zAH9^f#>xq(OaosKg%{KDhDd8aKc%-9yv8X^c_mX-m!u1%GJV}c$l1E;3OYGPb-Nz;>r_zJ%}`g* zMNLk@&>iP!QD#};fq*R-B5+Z&RiFYvGY<^<>9)C?xWmPb+?uFb?!LjG}V2Oxn%Pr!7(bBtoVExyPJUdhZ`4S~ngf+j0V=vU83Uz20 z$HD`#{pTaBc-m=Pz<*!zyqXWcXr1t57LJokt)1R(>T7QK@`LK}`D;sWb#+icWqD9w z5VNd2h#3@A&NB5dS+*hy2#`Pqkmn^fEC{HNDBx3rDq(eiY|QeqrW9CSc?<5DTci(M zb8lCxq+9?7@QW zWsRV`?iB&a#$Ri8@{B2`JNQ-#s}*~5V#~DWq#fIdM;_h(Dmjw4mQ{#GV8~qHvS@!XLp%sLM_%b0jzn?bp3jO zfRPyDRH6OANKf#`)g8?WeCxA2#$<+Kw*I<-Z%uoQW2P{p=D~((Y3xm*IdkD)sAMRsM-M;=#WmSn6F+tFj?>W58hkLrQ_ z1ahzXDEPr%b4E#Rl)%t3zlF6V@mY~MhEhL(H_ASs zx{2!mQ_j->K(LO5Z@N~lJw7jBj!R#HmLcm(x17k#r12EJG*N`P{psqu>$UvTZO@^a zxd+!p-C<7;3rYT**nNJSQT*_!DUjnm@ zw+I7~Sd*>|k8g7G)Iw-T))fl0s4v4Gzngu3IK#;Ic~nr|<)mb%z(SRXkJv3UU){(P zCmxj|Ht0bf-5em+m5*cYiyBHGh zlU+j_kBT25Rb&E0U$gMvmrTwKo!ekBi#}|qF$;?~o|%4Mw4(95P#!4yx?Sp)Rt&57 zOLwG3mEfXgvG9qNv=!cCBr?}1xEXJs@TWmL3WypAd^#6)Csf}nXO*x)Sji3`6vGCU zqC>s4Ro&AAzi%Djb4GE|iTH@LQNuhg^yxs5x}aJ^*7;$P-J9<(Pbr~t)#D`1=k1q2 zzso;m|Ea*5RU<7UyqWO1cv;-)w*1$rgDJos2k7u!=V9ktoMSNVaz@{~<@ay_5gf*W z2BmEe=Ca$|&hN;(Y9^gL{@W3irOp^_nKG+&w{|1PX>jZLeAA;m+3{k7MTO7s3gn>^ zs6V>C@y}7#Y#`u;ecOWmdif@!R_K-Tt!VxSGHRgeoGm$&WD`yzdiM_!_I7&TKqk9? zBqhDSS7^8m)@(r|MyJ1L%`>*Y>Rv{OSd>SOj(j*NYO7T9-*GLQIHKK!=x{eGGu+W8 zF=~-uSss2qpO9XiK+753>>6x&lYOC*<(g}rb|d-Xf=YaZMaBuzWg8qcz14A)u=8St zy1QH>q}`z3<<*;0Ly(3_f3~^?THkOkl!xOymFlOb-)(MzL&ULcNFCHSeIWms0qCw( zwnOmOLMOMbjz~<~xNgi(-vAAkY#xWzfHsnQ=T7&=qvWKH>zK0hMreFV*Tz(L)D2LJ zJGXJfS#AD8K75`C=-K4w;rwf5I1n=lpJj$!5kprz@WrsynD3}B-t$1-;tp7|>O1*+ z7w1o?KoYW8*`D|J!o;#qjJJcajkU?C)jD&LleKiQSX7Rb5SgZ-#?UVrth!8#^|mu1 z6U}riOf-z{X#OGa#y|Xh%-Bi+e&mmYf8pUGk43IW0(=W|8KaIVrxX#nc{uWJVHu;% zyrA6R;@AlHsV9zIOh`dNWRw+G<_xV@c}WD<4qit;C0_v`0$%m#9Kq<;H6P%43iDq; zq}O>^Ph^j0+{NR}byhC;lvg5M?)5(o!PFb`WCG@k%X{Q$hT{`0?OUbI{)Z9Efd3{2 z%j^)4a{2sG4~B&Qi#M%6og;lEmUu>tZ)N?`$^M{4k{LT{KaN)i!f3Ndh%j1nSBXZb zB?Cb_w9F6fLHTyHW7_dvqDL}6oyyZ|hCgrh4sQ{*q<=bBWV!{*tCN1s#V~r=TnHC~ z{exRuqRylDP01sL@6d|;mug;uZ^fDSKK?smMk0vrt`K;XdnY~qwDPN$R*Y|reO^o& z{3aTOa>1w(Q?0$tafFM1;^y<~%0}VCb*R^L&C+7{#bG_-D|gzP5(B3s10BW)bDZ+;MYkLCgjN^wOLH!yy8 zHOLsPUAHPF`F4#>u+BaCPI_Ak7r%b(qSgBPB_*B4ipCHQo;mogb-Jx$l22KG{p&>( zF>HPRaw}6@nTjA?xn*4b`Vamtrxt7ZPX2UcqLVYDke|ic5^j-G~oSAQxmO74r%cCzpbcwJ zzvQh_@vr!@arwxx4d>tJ_@|ejwBe+fA&rN;2w~FN zToK{CWk}f5u+(JAe2DljTKCtDr0%DBGGVtYBvH#fg^CaSnr`6?#)uQ+RAoSuFW6;_}7qGjUebw3sRHI{3B$7Cs^AYpZ+))f62 zJw4ssEZM(*|5^S&g2Ur~-{ZE6*%M|wGd2mob}wNyX(b8%&!M8z2_Vk=&xW|54Bjo^ z|0u|OhI@>9^T?Go`HXh~aJeod&C#WX=t9`whR{1UN}4oM8ag(_LmDUzfUPdAz2M

uT@XGwKMV=PMTr2V)&AHYnbaf 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�^ptkUWH&$ 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 HYJ&e4C-=I8 diff --git a/misc/DejaVuSerif.woff2 b/misc/DejaVuSerif.woff2 deleted file mode 100644 index 238566d677f916c83ca2f8425e33e96c8be7a285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146864 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

@X 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 diff --git a/misc/javadoc-overwrites.css b/misc/javadoc-overwrites.css new file mode 100644 index 0000000..7eed81f --- /dev/null +++ b/misc/javadoc-overwrites.css @@ -0,0 +1,2 @@ +:root { --body-font-size: 16px;} +:root { --code-font-size: 16px;} diff --git a/misc/stylesheet.css b/misc/stylesheet.css deleted file mode 100644 index 625b5ae..0000000 --- a/misc/stylesheet.css +++ /dev/null @@ -1,904 +0,0 @@ -/* - * Javadoc style sheet - */ - -@font-face { - font-family: 'DejaVu Serif'; - src: local('DejaVu Serif'), url('DejaVuSerif.woff2'); -} - -@font-face { - font-family: 'DejaVu Serif'; - font-weight: bold; - src: local('DejaVu Serif Bold'), url('DejaVuSerif-Bold.woff2'); -} - -@font-face { - font-family: 'DejaVu Sans'; - src: local('DejaVu Sans'), url('DejaVuSans.woff2'); -} - -@font-face { - font-family: 'DejaVu Sans'; - font-weight: bold; - src: local('DejaVu Sans Bold'), url('DejaVuSans-Bold.woff2'); -} - -@font-face { - font-family: 'DejaVu Sans Mono'; - src: local('DejaVu Sans Mono'), url('DejaVuSansMono.woff2'); -} - -@font-face { - font-family: 'DejaVu Sans Mono'; - font-weight: bold; - src: local('DejaVu Sans Mono Bold'), url('DejaVuSansMono-Bold.woff2'); -} - -/* - * Styles for individual HTML elements. - * - * These are styles that are specific to individual HTML elements. Changing them affects the style of a particular - * HTML element throughout the page. - */ - -body { - background-color:#ffffff; - color:#353833; - font: normal 16px/1.5 "DejaVu Sans", Arial, Helvetica, sans-serif; - margin:0; - padding:0; - height:100%; - width:100%; -} -iframe { - margin:0; - padding:0; - height:100%; - width:100%; - overflow-y:scroll; - border:none; -} -a:link, a:visited { - text-decoration:none; - color:#4A6782; -} -a[href]:hover, a[href]:focus { - text-decoration:none; - color:#bb7a2a; -} -a[name] { - color:#353833; -} -pre { - font-family:'DejaVu Sans Mono', monospace; -} -h1 { - font-size:20px; -} -h2 { - font-size:18px; -} -h3 { - font-size:17px; -} -h4 { - font-size:16px; - margin-top: 1rem; - margin-bottom: 1rem; -} -h5 { - font-size:14px; -} -h6 { - font-size:13px; -} -ul { - list-style-type:disc; -} -code, tt { - font-family:'DejaVu Sans Mono', monospace; -} -:not(h1, h2, h3, h4, h5, h6) > code, -:not(h1, h2, h3, h4, h5, h6) > tt { - /* font-size:14px; */ - padding-top:4px; - margin-top:8px; - line-height:1.4em; -} -dt code { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; - padding-top:4px; -} -.summary-table dt code { - font-family:'DejaVu Sans Mono', monospace; - font-size:14px; - vertical-align:top; - padding-top:4px; -} -sup { - font-size:8px; -} -button { - font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif; -} -/* - * Styles for HTML generated by javadoc. - * - * These are style classes that are used by the standard doclet to generate HTML documentation. - */ - -/* - * Styles for document title and copyright. - */ -.clear { - clear:both; - height:0; - overflow:hidden; -} -.about-language { - float:right; - padding:0 21px 8px 8px; - font-size:11px; - margin-top:-9px; - height:2.9em; -} -.legal-copy { - margin-left:.5em; -} -.tab { - background-color:#0066FF; - color:#ffffff; - padding:8px; - width:5em; - font-weight:bold; -} -/* - * Styles for navigation bar. - */ -@media screen { - .flex-box { - position:fixed; - display:flex; - flex-direction:column; - height: 100%; - width: 100%; - } - .flex-header { - flex: 0 0 auto; - } - .flex-content { - flex: 1 1 auto; - overflow-y: auto; - } -} -.top-nav { - background-color:#4D7A97; - color:#FFFFFF; - float:left; - padding:0; - width:100%; - clear:right; - min-height:2.8em; - padding-top:10px; - overflow:hidden; - font-size:80%; -} -.sub-nav { - background-color:#dee3e9; - float:left; - width:100%; - overflow:hidden; - font-size:80%; -} -.sub-nav div { - clear:left; - float:left; - padding:0 0 5px 6px; - text-transform:uppercase; -} -.sub-nav .nav-list { - padding-top:5px; -} -ul.nav-list { - display:block; - margin:0 25px 0 0; - padding:0; -} -ul.sub-nav-list { - float:left; - margin:0 25px 0 0; - padding:0; -} -ul.nav-list li { - list-style:none; - float:left; - padding: 5px 6px; - text-transform:uppercase; -} -.sub-nav .nav-list-search { - float:right; - margin:0 0 0 0; - padding:5px 6px; - clear:none; -} -.nav-list-search label { - position:relative; - right:-16px; -} -ul.sub-nav-list li { - list-style:none; - float:left; - padding-top:10px; -} -.top-nav a:link, .top-nav a:active, .top-nav a:visited { - color:#FFFFFF; - text-decoration:none; - text-transform:uppercase; -} -.top-nav a:hover { - text-decoration:none; - color:#bb7a2a; - text-transform:uppercase; -} -.nav-bar-cell1-rev { - background-color:#F8981D; - color:#253441; - margin: auto 5px; -} -.skip-nav { - position:absolute; - top:auto; - left:-9999px; - overflow:hidden; -} -/* - * Hide navigation links and search box in print layout - */ -@media print { - ul.nav-list, div.sub-nav { - display:none; - } -} -/* - * Styles for page header and footer. - */ -.title { - color:#2c4557; - margin:10px 0; -} -.sub-title { - margin:5px 0 0 0; -} -.header ul { - margin:0 0 15px 0; - padding:0; -} -.header ul li, .footer ul li { - list-style:none; - font-size:80%; -} -/* - * Styles for headings. - */ -body.class-declaration-page .summary h2, -body.class-declaration-page .details h2, -body.class-use-page h2, -body.module-declaration-page .block-list h2 { - font-style: italic; - padding:0; - margin:15px 0; -} -body.class-declaration-page .summary h3, -body.class-declaration-page .details h3, -body.class-declaration-page .summary .inherited-list h2 { - background-color:#dee3e9; - border:1px solid #d0d9e0; - margin:0 0 6px -8px; - padding:7px 5px; -} -/* - * Styles for page layout containers. - */ -main { - clear:both; - padding:10px 20px; - position:relative; -} -dl.notes > dt { - 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 0 0; - /* font-size:14px; */ - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; -} -dl.name-value > dt { - margin-left:1px; - /* font-size:1.1em; */ - display:inline; - font-weight:bold; -} -dl.name-value > dd { - margin:0 0 0 1px; - /* font-size:1.1em; */ - display:inline; -} -/* - * Styles for lists. - */ -li.circle { - list-style:circle; -} -ul.horizontal li { - display:inline; - /* font-size:0.9em; */ -} -div.inheritance { - margin:0; - padding:0; -} -div.inheritance div.inheritance { - margin-left:2em; -} -ul.block-list, -ul.details-list, -ul.member-list, -ul.summary-list { - margin:10px 0 10px 0; - padding:0; -} -ul.block-list > li, -ul.details-list > li, -ul.member-list > li, -ul.summary-list > li { - list-style:none; - margin-bottom:15px; - line-height:1.4; -} -.summary-table dl, .summary-table dl dt, .summary-table dl dd { - margin-top:0; - margin-bottom:1px; -} -ul.see-list, ul.see-list-long { - padding-left: 0; - list-style: none; -} -ul.see-list li { - display: inline; -} -ul.see-list li:not(:last-child):after, -ul.see-list-long li:not(:last-child):after { - content: ", "; - white-space: pre-wrap; -} -/* - * Styles for tables. - */ -.summary-table, .details-table { - width:100%; - border-spacing:0; - border-left:1px solid #EEE; - border-right:1px solid #EEE; - border-bottom:1px solid #EEE; - padding:0; -} - -.summary-table .col-first { - font-family: "DejaVu Sans Mono", monospace; -} - -.caption { - position:relative; - text-align:left; - background-repeat:no-repeat; - color:#253441; - font-weight:bold; - clear:none; - overflow:hidden; - padding:0; - padding-top:10px; - padding-left:1px; - margin:0; - white-space:pre; -} -.caption a:link, .caption a:visited { - color:#1f389c; -} -.caption a:hover, -.caption a:active { - color:#FFFFFF; -} -.caption span { - white-space:nowrap; - padding-top:5px; - padding-left:12px; - padding-right:12px; - padding-bottom:7px; - display:inline-block; - float:left; - background-color:#F8981D; - border: none; - height:16px; -} -div.table-tabs { - padding:10px 0 0 1px; - margin:0; -} -div.table-tabs > button { - border: none; - cursor: pointer; - padding: 5px 12px 7px 12px; - font-weight: bold; - margin-right: 3px; -} -div.table-tabs > button.active-table-tab { - background: #F8981D; - color: #253441; -} -div.table-tabs > button.table-tab { - background: #4D7A97; - color: #FFFFFF; -} -.two-column-summary { - display: grid; - grid-template-columns: minmax(15%, max-content) minmax(15%, auto); -} -.three-column-summary { - display: grid; - grid-template-columns: minmax(10%, max-content) 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); -} -@media screen and (max-width: 600px) { - .two-column-summary { - display: grid; - grid-template-columns: 1fr; - } -} -@media screen and (max-width: 800px) { - .three-column-summary { - display: grid; - grid-template-columns: minmax(10%, max-content) minmax(25%, auto); - } - .three-column-summary .col-last { - grid-column-end: span 2; - } -} -@media screen and (max-width: 1000px) { - .four-column-summary { - display: grid; - grid-template-columns: minmax(15%, max-content) minmax(15%, auto); - } -} -.summary-table > div, .details-table > div { - text-align:left; - padding: 8px 3px 3px 7px; -} -.col-first, .col-second, .col-last, .col-constructor-name, .col-summary-item-name { - vertical-align:top; - padding-right:0; - padding-top:8px; - padding-bottom:3px; -} -.table-header { - background:#dee3e9; - font-weight: bold; -} -/* -.col-first, .col-first { - font-size:13px; -} -.col-second, .col-second, .col-last, .col-constructor-name, .col-summary-item-name, .col-last { - font-size:13px; -} -*/ -.col-first, .col-second, .col-constructor-name { - vertical-align:top; - overflow: auto; -} -.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, -.col-second a:link, .col-second a:visited, -.col-constructor-name a:link, .col-constructor-name a:visited, -.col-summary-item-name a:link, .col-summary-item-name a:visited, -.constant-values-container a:link, .constant-values-container a:visited, -.all-classes-container a:link, .all-classes-container a:visited, -.all-packages-container a:link, .all-packages-container a:visited { - font-weight:bold; -} -.table-sub-heading-color { - background-color:#EEEEFF; -} -.even-row-color, .even-row-color .table-header { - background-color:#FFFFFF; -} -.odd-row-color, .odd-row-color .table-header { - background-color:#EEEEEF; -} -/* - * Styles for contents. - */ -.deprecated-content { - margin:0; - padding:10px 0; -} -div.block { - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; -} -.col-last div { - padding-top:0; -} -.col-last a { - padding-bottom:3px; -} -.module-signature, -.package-signature, -.type-signature, -.member-signature { - font-family:'DejaVu Sans Mono', monospace; - margin:14px 0; - white-space: pre-wrap; -} -.module-signature, -.package-signature, -.type-signature { - margin-top: 0; -} -.member-signature .type-parameters-long, -.member-signature .parameters, -.member-signature .exceptions { - display: inline-block; - vertical-align: top; - white-space: pre; -} -.member-signature .type-parameters { - white-space: normal; -} -/* - * Styles for formatting effect. - */ -.source-line-no { - color:green; - padding:0 30px 0 0; -} -h1.hidden { - visibility:hidden; - overflow:hidden; - /* font-size:10px; */ -} -.block { - display:block; - margin:0 10px 5px 0; - color:#474747; -} -.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-weight:bold; -} -.deprecation-comment, .help-footnote, .preview-comment { - font-style:italic; -} -.deprecation-block { - /* font-size:14px; */ - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; - border-style:solid; - border-width:thin; - border-radius:10px; - padding:10px; - margin-bottom:10px; - margin-right:10px; - display:inline-block; -} -.preview-block { - /* font-size:14px; */ - font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif; - border-style:solid; - border-width:thin; - border-radius:10px; - padding:10px; - margin-bottom:10px; - margin-right:10px; - display:inline-block; -} -div.block div.deprecation-comment { - font-style:normal; -} -/* - * Styles specific to HTML5 elements. - */ -main, nav, header, footer, section { - display:block; -} -/* - * Styles for javadoc search. - */ -.ui-autocomplete-category { - font-weight:bold; - /* font-size:15px; */ - padding:7px 0 7px 3px; - background-color:#4D7A97; - color:#FFFFFF; -} -.result-item { - /* font-size:13px; */ -} -.ui-autocomplete { - max-height:85%; - max-width:65%; - overflow-y:scroll; - overflow-x:scroll; - white-space:nowrap; - box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); -} -ul.ui-autocomplete { - position:fixed; - z-index:999999; - background-color: #FFFFFF; -} -ul.ui-autocomplete li { - float:left; - clear:both; - width:100%; -} -.result-highlight { - font-weight:bold; -} -.ui-autocomplete .result-item { - font-size: inherit; -} -#search-input { - background-image:url('resources/glass.png'); - background-size:13px; - background-repeat:no-repeat; - background-position:2px 3px; - padding-left:20px; - position:relative; - right:-18px; - width:400px; -} -#reset-button { - background-color: rgb(255,255,255); - background-image:url('resources/x.png'); - background-position:center; - background-repeat:no-repeat; - background-size:12px; - border:0 none; - width:16px; - height:16px; - position:relative; - left:-4px; - top:-4px; - font-size:0px; -} -.watermark { - color:#545454; -} -.search-tag-desc-result { - font-style:italic; - /* font-size:11px; */ -} -.search-tag-holder-result { - font-style:italic; - /* font-size:12px; */ -} -.search-tag-result:target { - background-color:yellow; -} -.module-graph span { - display:none; - position:absolute; -} -.module-graph:hover span { - display:block; - margin: -100px 0 0 100px; - z-index: 1; -} -.inherited-list { - margin: 10px 0 10px 0; -} -section.class-description { - line-height: 1.4; -} -.summary section[class$="-summary"], .details section[class$="-details"], -.class-uses .detail, .serialized-class-details { - padding: 0px 20px 5px 10px; - border: 1px solid #ededed; - background-color: #f8f8f8; -} -.inherited-list, section[class$="-details"] .detail { - padding:0 0 5px 8px; - background-color:#ffffff; - border:none; -} -.vertical-separator { - padding: 0 5px; -} -ul.help-section-list { - margin: 0; -} -ul.help-subtoc > li { - display: inline-block; - padding-right: 5px; - /* font-size: smaller; */ -} -ul.help-subtoc > li::before { - content: "\2022" ; - padding-right:2px; -} -span.help-note { - font-style: italic; -} -/* - * Indicator icon for external links. - */ -main a[href*="://"]::after { - content:""; - display:inline-block; - background-image:url('data:image/svg+xml; utf8, \ - \ - \ - '); - background-size:100% 100%; - width:7px; - height:7px; - margin-left:2px; - margin-bottom:4px; -} -main a[href*="://"]:hover::after, -main a[href*="://"]:focus::after { - background-image:url('data:image/svg+xml; utf8, \ - \ - \ - '); -} - -/* - * Styles for user-provided tables. - * - * borderless: - * No borders, vertical margins, styled caption. - * This style is provided for use with existing doc comments. - * In general, borderless tables should not be used for layout purposes. - * - * plain: - * Plain borders around table and cells, vertical margins, styled caption. - * Best for small tables or for complex tables for tables with cells that span - * rows and columns, when the "striped" style does not work well. - * - * striped: - * Borders around the table and vertical borders between cells, striped rows, - * vertical margins, styled caption. - * Best for tables that have a header row, and a body containing a series of simple rows. - */ - -table.borderless, -table.plain, -table.striped { - margin-top: 10px; - margin-bottom: 10px; -} -table.borderless > caption, -table.plain > caption, -table.striped > caption { - font-weight: bold; - /* font-size: smaller; */ -} -table.borderless th, table.borderless td, -table.plain th, table.plain td, -table.striped th, table.striped td { - padding: 2px 5px; -} -table.borderless, -table.borderless > thead > tr > th, table.borderless > tbody > tr > th, table.borderless > tr > th, -table.borderless > thead > tr > td, table.borderless > tbody > tr > td, table.borderless > tr > td { - border: none; -} -table.borderless > thead > tr, table.borderless > tbody > tr, table.borderless > tr { - background-color: transparent; -} -table.plain { - border-collapse: collapse; - border: 1px solid black; -} -table.plain > thead > tr, table.plain > tbody tr, table.plain > tr { - background-color: transparent; -} -table.plain > thead > tr > th, table.plain > tbody > tr > th, table.plain > tr > th, -table.plain > thead > tr > td, table.plain > tbody > tr > td, table.plain > tr > td { - border: 1px solid black; -} -table.striped { - border-collapse: collapse; - border: 1px solid black; -} -table.striped > thead { - background-color: #E3E3E3; -} -table.striped > thead > tr > th, table.striped > thead > tr > td { - border: 1px solid black; -} -table.striped > tbody > tr:nth-child(even) { - background-color: #EEE -} -table.striped > tbody > tr:nth-child(odd) { - background-color: #FFF -} -table.striped > tbody > tr > th, table.striped > tbody > tr > td { - border-left: 1px solid black; - border-right: 1px solid black; -} -table.striped > tbody > tr > th { - font-weight: normal; -} -/** - * Tweak font sizes and paddings for small screens. - */ -@media screen and (max-width: 1050px) { - #search-input { - width: 300px; - } -} -@media screen and (max-width: 800px) { - #search-input { - width: 200px; - } - .top-nav, - .bottom-nav { - font-size: 80%; - padding-top: 6px; - } - .sub-nav { - font-size: 80%; - } - .about-language { - padding-right: 16px; - } - ul.nav-list li, - .sub-nav .nav-list-search { - padding: 6px; - } - ul.sub-nav-list li { - padding-top: 5px; - } - main { - padding: 10px; - } - .summary section[class$="-summary"], .details section[class$="-details"], - .class-uses .detail, .serialized-class-details { - padding: 0 8px 5px 8px; - } - body { - -webkit-text-size-adjust: none; - } -} -@media screen and (max-width: 500px) { - #search-input { - width: 150px; - } - .top-nav, - .bottom-nav { - font-size: 80%; - } - .sub-nav { - font-size: 80%; - } - .about-language { - font-size: 80%; - padding-right: 12px; - } -} diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Containerfile b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Containerfile index c212945..08c4bff 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Containerfile +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Containerfile @@ -1,4 +1,4 @@ -FROM docker.io/eclipse-temurin:17-jre-alpine +FROM docker.io/eclipse-temurin:21-jre-alpine COPY build/install/vm-manager /opt/vmmanager 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 437790b..1984f89 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 @@ -184,12 +184,8 @@ public class Reconciler extends Component { * @param event the event * @param channel the channel * @throws ApiException the api exception - * @throws IOException - * @throws ParseException - * @throws MalformedTemplateNameException - * @throws TemplateNotFoundException - * @throws TemplateException - * @throws KubectlException + * @throws TemplateException the template exception + * @throws IOException Signals that an I/O exception has occurred. */ @Handler @SuppressWarnings("PMD.ConfusingTernary") diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CdMediaController.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CdMediaController.java index 53922f2..0a8971c 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CdMediaController.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CdMediaController.java @@ -27,7 +27,7 @@ import org.jdrupes.vmoperator.runner.qemu.commands.QmpOpenTray; import org.jdrupes.vmoperator.runner.qemu.commands.QmpRemoveMedium; import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu; import org.jdrupes.vmoperator.runner.qemu.events.MonitorCommand; -import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State; +import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jdrupes.vmoperator.runner.qemu.events.TrayMovedEvent; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; @@ -69,7 +69,7 @@ public class CdMediaController extends Component { @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", "PMD.AvoidInstantiatingObjectsInLoops" }) public void onConfigureQemu(ConfigureQemu event) { - if (event.state() == State.TERMINATING) { + if (event.runState() == RunState.TERMINATING) { return; } @@ -82,7 +82,7 @@ public class CdMediaController extends Component { } var driveId = "cd" + cdCounter++; var newFile = Optional.ofNullable(drives[i].file).orElse(""); - if (event.state() == State.STARTING) { + if (event.runState() == RunState.STARTING) { current.put(driveId, newFile); continue; } @@ -116,8 +116,8 @@ public class CdMediaController extends Component { */ @Handler public void onTrayMovedEvent(TrayMovedEvent event) { - trayState.put(event.driveId(), event.state()); - if (event.state() == TrayState.OPEN + trayState.put(event.driveId(), event.trayState()); + if (event.trayState() == TrayState.OPEN && pending.containsKey(event.driveId())) { changeMedium(event.driveId()); } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.alpine b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.alpine index b87049e..d0104f3 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.alpine +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.alpine @@ -2,7 +2,7 @@ FROM docker.io/alpine RUN apk update -RUN apk add qemu-system-x86_64 qemu-modules ovmf swtpm openjdk17 mtools +RUN apk add qemu-system-x86_64 qemu-modules ovmf swtpm openjdk21 mtools RUN mkdir -p /etc/qemu && echo "allow all" > /etc/qemu/bridge.conf diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch index 2ccb2f9..6ba8500 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch @@ -5,7 +5,7 @@ RUN systemd-firstboot RUN pacman-key --init \ && pacman -Sy --noconfirm archlinux-keyring && pacman -Su --noconfirm \ && pacman -S --noconfirm which qemu-full virtiofsd \ - edk2-ovmf swtpm iproute2 bridge-utils jre17-openjdk-headless \ + edk2-ovmf swtpm iproute2 bridge-utils jre21-openjdk-headless \ mtools \ && pacman -Scc --noconfirm diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CpuController.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CpuController.java index 857b14e..b0abfd4 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CpuController.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CpuController.java @@ -33,7 +33,7 @@ import org.jdrupes.vmoperator.runner.qemu.events.CpuAdded; import org.jdrupes.vmoperator.runner.qemu.events.CpuDeleted; import org.jdrupes.vmoperator.runner.qemu.events.HotpluggableCpuStatus; import org.jdrupes.vmoperator.runner.qemu.events.MonitorCommand; -import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State; +import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; import org.jgrapes.core.annotation.Handler; @@ -64,7 +64,7 @@ public class CpuController extends Component { */ @Handler public void onConfigureQemu(ConfigureQemu event) { - if (event.state() == State.TERMINATING) { + if (event.runState() == RunState.TERMINATING) { return; } Optional.ofNullable(event.configuration().vm.currentCpus) 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 dc73cb2..1f9833c 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 @@ -27,7 +27,7 @@ import org.jdrupes.vmoperator.runner.qemu.commands.QmpSetDisplayPassword; import org.jdrupes.vmoperator.runner.qemu.commands.QmpSetPasswordExpiry; import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu; import org.jdrupes.vmoperator.runner.qemu.events.MonitorCommand; -import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State; +import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; import org.jgrapes.core.annotation.Handler; @@ -67,7 +67,7 @@ public class DisplayController extends Component { */ @Handler public void onConfigureQemu(ConfigureQemu event) { - if (event.state() == State.TERMINATING) { + if (event.runState() == RunState.TERMINATING) { return; } protocol 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 4d9f479..c837537 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 @@ -61,7 +61,7 @@ import org.jdrupes.vmoperator.runner.qemu.events.Exit; import org.jdrupes.vmoperator.runner.qemu.events.MonitorCommand; import org.jdrupes.vmoperator.runner.qemu.events.QmpConfigured; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange; -import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State; +import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jdrupes.vmoperator.util.ExtendedObjectWrapper; import org.jdrupes.vmoperator.util.FsdUtils; import org.jgrapes.core.Channel; @@ -217,7 +217,7 @@ public class Runner extends Component { private CommandDefinition qemuDefinition; private final QemuMonitor qemuMonitor; private Integer resetCounter; - private State state = State.INITIALIZING; + private RunState state = RunState.INITIALIZING; /** Preparatory actions for QEMU start */ @SuppressWarnings("PMD.FieldNamingConventions") @@ -467,7 +467,7 @@ public class Runner extends Component { */ @Handler public void onStarted(Started event) { - state = State.STARTING; + state = RunState.STARTING; rep.fire(new RunnerStateChange(state, "RunnerStarted", "Runner has been started")); // Start first process(es) @@ -618,9 +618,9 @@ public class Runner extends Component { */ @Handler(priority = -1000) public void onConfigureQemuFinal(ConfigureQemu event) { - if (state == State.STARTING) { + if (state == RunState.STARTING) { fire(new MonitorCommand(new QmpCont())); - state = State.RUNNING; + state = RunState.RUNNING; rep.fire(new RunnerStateChange(state, "VmStarted", "Qemu has been configured and is continuing")); } @@ -633,7 +633,7 @@ public class Runner extends Component { */ @Handler public void onConfigureQemu(ConfigureQemu event) { - if (state == State.RUNNING) { + if (state == RunState.RUNNING) { if (resetCounter != null && event.configuration().resetCounter != null && event.configuration().resetCounter > resetCounter) { @@ -659,14 +659,14 @@ public class Runner extends Component { return; } // No other process(es) may exit during startup - if (state == State.STARTING) { + if (state == RunState.STARTING) { logger.severe(() -> "Process " + procDef.name + " has exited with value " + event.exitValue() + " during startup."); rep.fire(new Stop()); return; } - if (procDef.equals(qemuDefinition) && state == State.RUNNING) { + if (procDef.equals(qemuDefinition) && state == RunState.RUNNING) { rep.fire(new Exit(event.exitValue())); } logger.info(() -> "Process " + procDef.name @@ -693,7 +693,7 @@ public class Runner extends Component { */ @Handler(priority = 10_000) public void onStopFirst(Stop event) { - state = State.TERMINATING; + state = RunState.TERMINATING; rep.fire(new RunnerStateChange(state, "VmTerminating", "The VM is being shut down", exitStatus != 0)); } @@ -705,14 +705,14 @@ public class Runner extends Component { */ @Handler(priority = -10_000) public void onStopLast(Stop event) { - state = State.STOPPED; + state = RunState.STOPPED; rep.fire(new RunnerStateChange(state, "VmStopped", "The VM has been shut down")); } @SuppressWarnings("PMD.ConfusingArgumentToVarargsMethod") private void shutdown() { - if (!Set.of(State.TERMINATING, State.STOPPED).contains(state)) { + if (!Set.of(RunState.TERMINATING, RunState.STOPPED).contains(state)) { fire(new Stop()); } try { diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index bbcba5e..412681f 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -48,7 +48,7 @@ import org.jdrupes.vmoperator.runner.qemu.events.DisplayPasswordChanged; import org.jdrupes.vmoperator.runner.qemu.events.Exit; import org.jdrupes.vmoperator.runner.qemu.events.HotpluggableCpuStatus; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange; -import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State; +import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jdrupes.vmoperator.runner.qemu.events.ShutdownEvent; import org.jdrupes.vmoperator.util.GsonPtr; import org.jgrapes.core.Channel; @@ -65,8 +65,8 @@ import org.jgrapes.util.events.InitialConfiguration; @SuppressWarnings("PMD.DataflowAnomalyAnalysis") public class StatusUpdater extends Component { - private static final Set RUNNING_STATES - = Set.of(State.RUNNING, State.TERMINATING); + private static final Set RUNNING_STATES + = Set.of(RunState.RUNNING, RunState.TERMINATING); private String namespace; private String vmName; @@ -240,11 +240,11 @@ public class StatusUpdater extends Component { updateRunningCondition(event, from, cond); } }); - if (event.state() == State.STARTING) { + if (event.runState() == RunState.STARTING) { status.addProperty("ram", GsonPtr.to(from.data()) .getAsString("spec", "vm", "maximumRam").orElse("0")); status.addProperty("cpus", 1); - } else if (event.state() == State.STOPPED) { + } else if (event.runState() == RunState.STOPPED) { status.addProperty("ram", "0"); status.addProperty("cpus", 0); } @@ -252,7 +252,7 @@ public class StatusUpdater extends Component { }); // Maybe stop VM - if (event.state() == State.TERMINATING && !event.failed() + if (event.runState() == RunState.TERMINATING && !event.failed() && guestShutdownStops && shutdownByGuest) { logger.info(() -> "Stopping VM because of shutdown by guest."); var res = vmStub.patch(V1Patch.PATCH_FORMAT_JSON_PATCH, @@ -277,13 +277,13 @@ public class StatusUpdater extends Component { K8sDynamicModel from, JsonObject cond) { boolean reportedRunning = "True".equals(cond.get("status").getAsString()); - if (RUNNING_STATES.contains(event.state()) + if (RUNNING_STATES.contains(event.runState()) && !reportedRunning) { cond.addProperty("status", "True"); cond.addProperty("lastTransitionTime", Instant.now().toString()); } - if (!RUNNING_STATES.contains(event.state()) + if (!RUNNING_STATES.contains(event.runState()) && reportedRunning) { cond.addProperty("status", "False"); cond.addProperty("lastTransitionTime", diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/ConfigureQemu.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/ConfigureQemu.java index a8b1e45..7afa738 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/ConfigureQemu.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/ConfigureQemu.java @@ -19,7 +19,7 @@ package org.jdrupes.vmoperator.runner.qemu.events; import org.jdrupes.vmoperator.runner.qemu.Configuration; -import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.State; +import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jgrapes.core.Channel; import org.jgrapes.core.Event; @@ -34,14 +34,14 @@ import org.jgrapes.core.Event; public class ConfigureQemu extends Event { private final Configuration configuration; - private final State state; + private final RunState state; /** * Instantiates a new configuration event. * * @param channels the channels */ - public ConfigureQemu(Configuration configuration, State state, + public ConfigureQemu(Configuration configuration, RunState state, Channel... channels) { super(channels); this.state = state; @@ -62,7 +62,7 @@ public class ConfigureQemu extends Event { * * @return the state */ - public State state() { + public RunState runState() { return state; } } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java index 4a7ef08..bb6ab10 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java @@ -31,11 +31,11 @@ public class RunnerStateChange extends Event { /** * The state. */ - public enum State { + public enum RunState { INITIALIZING, STARTING, RUNNING, TERMINATING, STOPPED } - private final State state; + private final RunState state; private final String reason; private final String message; private final boolean failed; @@ -48,7 +48,7 @@ public class RunnerStateChange extends Event { * @param message the message * @param channels the channels */ - public RunnerStateChange(State state, String reason, String message, + public RunnerStateChange(RunState state, String reason, String message, Channel... channels) { this(state, reason, message, false, channels); } @@ -62,7 +62,7 @@ public class RunnerStateChange extends Event { * @param failed the failed * @param channels the channels */ - public RunnerStateChange(State state, String reason, String message, + public RunnerStateChange(RunState state, String reason, String message, boolean failed, Channel... channels) { super(channels); this.state = state; @@ -76,7 +76,7 @@ public class RunnerStateChange extends Event { * * @return the state */ - public State state() { + public RunState runState() { return state; } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/TrayMovedEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/TrayMovedEvent.java index f5ef725..e2d2286 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/TrayMovedEvent.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/TrayMovedEvent.java @@ -50,7 +50,7 @@ public class TrayMovedEvent extends MonitorEvent { * * @return the tray state */ - public TrayState state() { + public TrayState trayState() { return data().get("tray-open").asBoolean() ? TrayState.OPEN : TrayState.CLOSED; From 7f80f4c6e94c8fe1da1699a082a2e82879885882 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" <1446020+mnlipp@users.noreply.github.com> Date: Tue, 18 Jun 2024 13:51:59 +0200 Subject: [PATCH 027/342] Wip/gitlab ci (#32) Start CI/CD on a gitlab instance. --- .gitlab-ci.yml | 64 +- gradle.properties | 1 + org.jdrupes.vmoperator.manager/build.gradle | 60 +- .../build.gradle | 101 +- .../vmoperator/runner/qemu/Containerfile.arch | 2 +- package-lock.json | 3158 ++++++++--------- package.json | 4 + spice-squid/Containerfile | 2 +- 8 files changed, 1676 insertions(+), 1716 deletions(-) create mode 100644 gradle.properties diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 70654cc..f1e59d7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,25 +1,69 @@ -default: - # Template project: https://gitlab.com/pages/jekyll - # Docs: https://docs.gitlab.com/ee/pages/ - image: ruby:3.2 +stages: + - build + - test + - publish + - deploy + +.any-job: + rules: + - if: $CI_SERVER_HOST == "gitlab.mnl.de" + +.gradle-job: + extends: .any-job + image: registry.mnl.de/org/jgrapes/jdk21-builder:v2 + cache: + - key: dependencies + policy: pull-push + paths: + - .gradle + - node_modules + - key: "$CI_COMMIT_SHA" + policy: pull-push + paths: + - build + - "*/build" + before_script: + - echo -n $CI_REGISTRY_PASSWORD | podman login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY + - git switch $CI_COMMIT_REF_NAME + - git pull + - git reset --hard $CI_COMMIT_SHA + +build-jars: + stage: build + extends: .gradle-job + script: + - ./gradlew -Pdocker.registry=$CI_REGISTRY_IMAGE build apidocs + +publish-images: + stage: publish + extends: .gradle-job + script: + - ./gradlew -Pdocker.registry=$CI_REGISTRY_IMAGE pushImage + +.pages-job: + extends: .any-job + image: ${CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX}/ruby:3.2 + variables: + JEKYLL_ENV: production + LC_ALL: C.UTF-8 before_script: - git fetch origin gh-pages - git checkout gh-pages - gem install bundler - bundle install -variables: - JEKYLL_ENV: production - LC_ALL: C.UTF-8 -test: + +test-pages: stage: test + extends: .pages-job script: - bundle exec jekyll build -d test artifacts: paths: - test -pages: - stage: deploy +publish-pages: + stage: publish + extends: .pages-job script: - bundle exec jekyll build -d public artifacts: diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..f97ebb7 --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +org.gradle.parallel=true diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index c90ad54..a956a00 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -45,45 +45,36 @@ application { mainClass = 'org.jdrupes.vmoperator.manager.Manager' } +project.ext.gitBranch = grgit.branch.current.name.replace('/', '-') + task buildImage(type: Exec) { dependsOn installDist inputs.files 'src/org/jdrupes/vmoperator/manager/Containerfile' commandLine 'podman', 'build', '--pull', - '-t', "${project.name}:${project.version}",\ + '-t', "${project.name}:${project.gitBranch}",\ '-f', 'src/org/jdrupes/vmoperator/manager/Containerfile', '.' } -task tagLatestImage(type: Exec) { - dependsOn buildImage - - enabled = !project.version.contains("SNAPSHOT") - && !project.version.contains("alpha") \ - && !project.version.contains("beta") \ - || project.rootProject.properties['docker.testRegistry'] \ - && project.rootProject.properties['docker.registry'] \ - == project.rootProject.properties['docker.testRegistry'] - - commandLine 'podman', 'tag', "${project.name}:${project.version}",\ - "${project.name}:latest" -} - -task buildLatestImage { - dependsOn buildImage - dependsOn tagLatestImage -} - task pushImage(type: Exec) { dependsOn buildImage + // Don't push without testing first + dependsOn test + def registry = "${project.rootProject.properties['docker.registry']}" commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ - + "/${project.name}:${project.version}" + "localhost/${project.name}:${project.gitBranch}", \ + "${registry}/${project.name}:${project.gitBranch}" + + if (!project.version.contains("SNAPSHOT")) { + commandLine 'podman', 'tag', \ + "${registry}/${project.name}:${project.gitBranch}",\ + "${registry}/${project.name}:${project.version}" + } } -task pushLatestImage(type: Exec) { - dependsOn buildLatestImage +task tagAsLatest(type: Exec) { + dependsOn pushImage enabled = !project.version.contains("SNAPSHOT") && !project.version.contains("alpha") \ @@ -92,28 +83,21 @@ task pushLatestImage(type: Exec) { && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] - commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ - + "/${project.name}:latest" + def registry = "${project.rootProject.properties['docker.registry']}" + commandLine 'podman', 'tag', \ + "${registry}/${project.name}:${project.version}",\ + "${registry}/${project.name}:latest" } task pushForTest(type: Exec) { dependsOn buildImage commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ + "localhost/${project.name}:${project.gitBranch}", \ + "${project.rootProject.properties['docker.testRegistry']}" \ + "/${project.name}:test" } -task pushImages { - // Don't push without testing first - dependsOn test - dependsOn pushImage - dependsOn pushLatestImage -} - test { enabled = project.hasProperty("k8s.testCluster") diff --git a/org.jdrupes.vmoperator.runner.qemu/build.gradle b/org.jdrupes.vmoperator.runner.qemu/build.gradle index 82525c6..00bf7ea 100644 --- a/org.jdrupes.vmoperator.runner.qemu/build.gradle +++ b/org.jdrupes.vmoperator.runner.qemu/build.gradle @@ -31,45 +31,34 @@ application { mainClass = 'org.jdrupes.vmoperator.runner.qemu.Runner' } +project.ext.gitBranch = grgit.branch.current.name.replace('/', '-') + task buildArchImage(type: Exec) { dependsOn installDist inputs.files 'src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch' commandLine 'podman', 'build', '--pull', - '-t', "${project.name}-arch:${project.version}",\ + '-t', "${project.name}-arch:${project.gitBranch}",\ '-f', 'src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch', '.' } -task tagLatestArchImage(type: Exec) { - dependsOn buildArchImage - - enabled = !project.version.contains("SNAPSHOT") - && !project.version.contains("alpha") \ - && !project.version.contains("beta") \ - || project.rootProject.properties['docker.testRegistry'] \ - && project.rootProject.properties['docker.registry'] \ - == project.rootProject.properties['docker.testRegistry'] - - commandLine 'podman', 'tag', "${project.name}-arch:${project.version}",\ - "${project.name}-arch:latest" -} - -task buildLatestArchImage { - dependsOn buildArchImage - dependsOn tagLatestArchImage -} - task pushArchImage(type: Exec) { dependsOn buildArchImage + def registry = "${project.rootProject.properties['docker.registry']}" commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}-arch:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ - + "/${project.name}-arch:${project.version}" + "localhost/${project.name}-arch:${project.gitBranch}", \ + "${registry}/${project.name}-arch:${project.gitBranch}" + + if (!project.version.contains("SNAPSHOT")) { + commandLine 'podman', 'tag', \ + "${registry}/${project.name}-arch:${project.gitBranch}",\ + "${registry}/${project.name}-arch:${project.version}" + } } -task pushArchLatestImage(type: Exec) { - dependsOn buildLatestArchImage +task tagAsLatestArch(type: Exec) { + dependsOn pushArchImage enabled = !project.version.contains("SNAPSHOT") && !project.version.contains("alpha") \ @@ -78,10 +67,10 @@ task pushArchLatestImage(type: Exec) { && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] - commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}-arch:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ - + "/${project.name}-arch:latest" + def registry = "${project.rootProject.properties['docker.registry']}" + commandLine 'podman', 'tag', \ + "${registry}/${project.name}-arch:${project.version}",\ + "${registry}/${project.name}-arch:latest" } task buildAlpineImage(type: Exec) { @@ -89,40 +78,27 @@ task buildAlpineImage(type: Exec) { inputs.files 'src/org/jdrupes/vmoperator/runner/qemu/Containerfile.alpine' commandLine 'podman', 'build', '--pull', - '-t', "${project.name}-alpine:${project.version}",\ + '-t', "${project.name}-alpine:${project.gitBranch}",\ '-f', 'src/org/jdrupes/vmoperator/runner/qemu/Containerfile.alpine', '.' } -task tagLatestAlpineImage(type: Exec) { - dependsOn buildAlpineImage - - enabled = !project.version.contains("SNAPSHOT") - && !project.version.contains("alpha") \ - && !project.version.contains("beta") \ - || project.rootProject.properties['docker.testRegistry'] \ - && project.rootProject.properties['docker.registry'] \ - == project.rootProject.properties['docker.testRegistry'] - - commandLine 'podman', 'tag', "${project.name}-alpine:${project.version}",\ - "${project.name}-alpine:latest" -} - -task buildLatestAlpineImage { - dependsOn buildAlpineImage - dependsOn tagLatestAlpineImage -} - task pushAlpineImage(type: Exec) { dependsOn buildAlpineImage + def registry = "${project.rootProject.properties['docker.registry']}" commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}-alpine:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ - + "/${project.name}-alpine:${project.version}" + "localhost/${project.name}-alpine:${project.gitBranch}", \ + "${registry}/${project.name}-alpine:${project.gitBranch}" + + if (!project.version.contains("SNAPSHOT")) { + commandLine 'podman', 'tag', \ + "${registry}/${project.name}-alpine:${project.gitBranch}",\ + "${registry}/${project.name}-alpine:${project.version}" + } } -task pushAlpineLatestImage(type: Exec) { - dependsOn buildLatestAlpineImage +task tagAsLatestAlpine(type: Exec) { + dependsOn pushAlpineImage enabled = !project.version.contains("SNAPSHOT") && !project.version.contains("alpha") \ @@ -131,16 +107,19 @@ task pushAlpineLatestImage(type: Exec) { && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] - commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}-alpine:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ - + "/${project.name}-alpine:latest" + def registry = "${project.rootProject.properties['docker.registry']}" + commandLine 'podman', 'tag', \ + "${registry}/${project.name}-alpine:${project.version}",\ + "${registry}/${project.name}-alpine:latest" } -task pushImages { +task pushImage { dependsOn pushArchImage - dependsOn pushArchLatestImage dependsOn pushAlpineImage - dependsOn pushAlpineLatestImage +} + +task tagAsLatest { + dependsOn tagAsLatestArch + dependsOn tagAsLatestAlpine } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch index 6ba8500..0c2fd86 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch @@ -1,4 +1,4 @@ -FROM archlinux/archlinux:latest +FROM docker.io/archlinux/archlinux:latest RUN systemd-firstboot diff --git a/package-lock.json b/package-lock.json index 85f62bb..97aaade 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,129 +27,57 @@ "typescript": "^5.2.2" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz", - "integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", + "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", - "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", + "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.2", - "@babel/parser": "^7.23.0", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -164,15 +92,24 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@babel/generator": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", - "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", "dev": true, "dependencies": { - "@babel/types": "^7.23.0", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -180,14 +117,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", + "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -195,63 +132,76 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", - "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", - "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, "dependencies": { - "@babel/template": "^7.22.15", - "@babel/types": "^7.23.0" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz", - "integrity": "sha512-WhDWw1tdrlT0gMgUJSlX0IQvoO1eN279zrAUbVB+KpV2c3Tylz8+GnKOLllCS6Z/iZQEyVYxhZVUdPTqs2YYPw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -261,79 +211,80 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", - "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", + "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", "dev": true, "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.2", - "@babel/types": "^7.23.0" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", - "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -402,9 +353,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -414,34 +365,34 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -449,13 +400,13 @@ } }, "node_modules/@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -478,18 +429,18 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz", + "integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "peer": true, "dependencies": { @@ -522,9 +473,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "peer": true, "dependencies": { @@ -577,9 +528,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.52.0.tgz", - "integrity": "sha512-mjZVbpaeMZludF2fsWLD0Z9gCref1Tk4i9+wddjRvpUNqqcndPkBD09N/Mapey0b3jaXbLm2kICwFv2E64QinA==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", "dev": true, "peer": true, "engines": { @@ -593,14 +544,15 @@ "dev": true }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.13", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", - "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "deprecated": "Use @eslint/config-array instead", "dev": true, "peer": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.1", - "debug": "^4.1.1", + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", "minimatch": "^3.0.5" }, "engines": { @@ -646,52 +598,149 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", - "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", "dev": true, "peer": true }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/source-map": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", - "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" } }, "node_modules/@jridgewell/sourcemap-codec": { @@ -701,9 +750,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -711,9 +760,9 @@ } }, "node_modules/@jsdoc/salty": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.5.tgz", - "integrity": "sha512-TfRP53RqunNe2HBobVBJ0VLhK1HbfvBYeTC1ahnN64PWvyYyGebmMiPkuwvD9fpw2ZbkoPb8Q7mwy0aR8Z9rvw==", + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@jsdoc/salty/-/salty-0.2.8.tgz", + "integrity": "sha512-5e+SFVavj1ORKlKaKr2BmTOekmXbelU7dC0cDkQLqag7xfuTPuGMUFx7KWJuv4bYZrTsoL2Z18VVCOKYxzoHcg==", "dev": true, "dependencies": { "lodash": "^4.17.21" @@ -757,6 +806,83 @@ "node": ">= 8" } }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@npmcli/agent/node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@npmcli/agent/node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/agent/node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@npmcli/fs": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", @@ -770,39 +896,6 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/@npmcli/fs/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/fs/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@npmcli/fs/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@npmcli/move-file": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", @@ -817,6 +910,16 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@rollup/plugin-node-resolve": { "version": "15.2.3", "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", @@ -843,9 +946,9 @@ } }, "node_modules/@rollup/plugin-replace": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", - "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", + "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -886,9 +989,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", - "integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", "dev": true, "dependencies": { "@types/estree": "^1.0.0", @@ -908,9 +1011,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.1.5.tgz", - "integrity": "sha512-/fwx6GS8cIbM2rTNyLMxjSCOegHywOdXO+kN9yFy018iCULcKZCyA3xvzw4bxyKbYfdSxQgdhbsl0egNcxerQw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", "cpu": [ "arm" ], @@ -921,9 +1024,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.1.5.tgz", - "integrity": "sha512-tmXh7dyEt+JEz/NgDJlB1UeL/1gFV0v8qYzUAU42WZH4lmUJ5rp6/HkR2qUNC5jCgYEwd8/EfbHKtGIEfS4CUg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", "cpu": [ "arm64" ], @@ -934,9 +1037,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.1.5.tgz", - "integrity": "sha512-lTDmLxdEVhzI3KCesZUrNbl3icBvPrDv/85JasY5gh4P2eAuDFmM4uj9HC5DdH0anLC0fwJ+1Uzasr4qOXcjRQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", "cpu": [ "arm64" ], @@ -947,9 +1050,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.1.5.tgz", - "integrity": "sha512-v6qEHZyjWnIgcc4oiy8AIeFsUJAx+Kg0sLj+RE7ICwv3u7YC/+bSClxAiBASRjMzqsq0Z+I/pfxj+OD8mjBYxg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", "cpu": [ "x64" ], @@ -960,9 +1063,22 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.1.5.tgz", - "integrity": "sha512-WngCfwPEDUNbZR1FNO2TCROYUwJvRlbvPi3AS85bDUkkoRDBcjUIz42cuB1j4PKilmnZascL5xTMF/yU8YFayA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", "cpu": [ "arm" ], @@ -973,9 +1089,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.1.5.tgz", - "integrity": "sha512-Q2A/PEP/UTPTOBwgar3mmCaApahoezai/8e/7f4GCLV6XWCpnU4YwkQQtla7d7nUnc792Ps7g1G0WMovzIknrA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", "cpu": [ "arm64" ], @@ -986,9 +1102,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.1.5.tgz", - "integrity": "sha512-84aBKNAVzTU/eG3tb2+kR4NGRAtm2YVW/KHwkGGDR4z1k4hyrDbuImsfs/6J74t6y0YLOe9HOSu7ejRjzUBGVQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", "cpu": [ "arm64" ], @@ -998,10 +1114,49 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.1.5.tgz", - "integrity": "sha512-mldtP9UEBurIq2+GYMdNeiqCLW1fdgf4KdkMR/QegAeXk4jFHkKQl7p0NITrKFVyVqzISGXH5gR6GSTBH4wszw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", "cpu": [ "x64" ], @@ -1012,9 +1167,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.1.5.tgz", - "integrity": "sha512-36p+nMcSxjAEzfU47+by102HolUtf/EfgBAidocTKAofJMTqG5QD50qzaFLk4QO+z7Qvg4qd0wr99jGAwnKOig==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", "cpu": [ "x64" ], @@ -1025,9 +1180,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.1.5.tgz", - "integrity": "sha512-5oxhubo0A3J8aF/tG+6jHBg785HF8/88kl1YnfbDKmnqMxz/EFiAQDH9cq6lbnxofjn8tlq5KiTf0crJGOGThg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", "cpu": [ "arm64" ], @@ -1038,9 +1193,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.1.5.tgz", - "integrity": "sha512-uVQyBREKX9ErofL8KAZ4iVlqzSZOXSIG+BOLYuz5FD+Cg6jh1eLIeUa3Q4SgX0QaTRFeeAgSNqCC+8kZrZBpSw==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", "cpu": [ "ia32" ], @@ -1051,9 +1206,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.1.5.tgz", - "integrity": "sha512-FQ5qYqRJ2vUBSom3Fos8o/6UvAMOvlus4+HGCAifH1TagbbwVnVVe0o01J1V52EWnQ8kmfpJDJ0FMrfM5yzcSA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", "cpu": [ "x64" ], @@ -1082,88 +1237,88 @@ } }, "node_modules/@types/debug": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.9.tgz", - "integrity": "sha512-8Hz50m2eoS56ldRlepxSBa6PWEVCtzUo/92HgLc2qTMnotJNIm7xP+UZhyWoYsyOdd5dxZ+NZLb24rsKyFs2ow==", + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "dev": true, "dependencies": { "@types/ms": "*" } }, "node_modules/@types/estree": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", - "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", "dev": true }, "node_modules/@types/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-CqDQhn7jxaN9zw7zAu926zIx51ZzMaX8U8Wa4jGpKI6jeBr9ejFE68AQ+h+ztfrNJD+leo7K1cLbvMjpHfZSRg==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/extend/-/extend-3.0.4.tgz", + "integrity": "sha512-ArMouDUTJEz1SQRpFsT2rIw7DeqICFv5aaVzLSIYMYQSLcwcGOfT3VyglQs/p7K3F7fT4zxr0NWxYZIdifD6dA==", "dev": true }, "node_modules/@types/hast": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.6.tgz", - "integrity": "sha512-47rJE80oqPmFdVDCD7IheXBrVdwuBgsYwoczFvKmwfo2Mzsnt+V9OONsYauFmICb6lQPpCuXYJWejBNs4pDJRg==", + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", "dev": true, "dependencies": { "@types/unist": "^2" } }, "node_modules/@types/json-schema": { - "version": "7.0.14", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz", - "integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-pTjcqY9E4nOI55Wgpz7eiI8+LzdYnw3qxXCfHyBDdPbYvbyLgWLJGh8EdPvqawwMK1Uo1794AUkkR38Fr0g+2g==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", "dev": true }, "node_modules/@types/markdown-it": { - "version": "12.2.3", - "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", - "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-14.1.1.tgz", + "integrity": "sha512-4NpsnpYl2Gt1ljyBGrKMxFYAYvpqbnnkgP/i/g+NLpjEUa3obn1XJCur9YbEXKDAkaXqsR1LbDnGEJ0MmKFxfg==", "dev": true, "dependencies": { - "@types/linkify-it": "*", - "@types/mdurl": "*" + "@types/linkify-it": "^5", + "@types/mdurl": "^2" } }, "node_modules/@types/mdast": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.13.tgz", - "integrity": "sha512-HjiGiWedR0DVFkeNljpa6Lv4/IZU1+30VY5d747K7lBudFc3R0Ibr6yJ9lN3BE28VnZyDfLF/VB1Ql1ZIbKrmg==", + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", "dev": true, "dependencies": { "@types/unist": "^2" } }, "node_modules/@types/mdurl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.3.tgz", - "integrity": "sha512-T5k6kTXak79gwmIOaDF2UUQXFbnBE0zBUzF20pz7wDYu0RQMzWg+Ml/Pz50214NsFHBITkoi5VtdjFZnJ2ijjA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", "dev": true }, "node_modules/@types/minimist": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.3.tgz", - "integrity": "sha512-ZYFzrvyWUNhaPomn80dsMNgMeXxNWZBdkuG/hWlUvXvbdUH8ZERNBGXnU87McuGcWDsyzX2aChCv/SVN348k3A==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", "dev": true }, "node_modules/@types/ms": { - "version": "0.7.32", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.32.tgz", - "integrity": "sha512-xPSg0jm4mqgEkNhowKgZFBNtwoEwF6gJ4Dhww+GFpm3IgtNseHQZ5IqdNwnquZEoANxyDAKDRAdVo4Z72VvD/g==", + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==", "dev": true }, "node_modules/@types/normalize-package-data": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.2.tgz", - "integrity": "sha512-lqa4UEhhv/2sjjIQgjX8B+RBjj47eo0mzGasklVJ78UKGQY1r0VpB9XHDaZZO9qzEFDdy4MrXLuEaSmPrPSe/A==", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", "dev": true }, "node_modules/@types/parse5": { @@ -1179,34 +1334,34 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@types/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-dPWnWsf+kzIG140B8z2w3fr5D03TLWbOAFQl45xUpI3vcizeXriNR5VYkWZ+WTMsUHqZ9Xlt3hrxGNANFyNQfw==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@types/supports-color/-/supports-color-8.1.3.tgz", + "integrity": "sha512-Hy6UMpxhE3j1tLpl27exp1XqHD7n8chAiNPzWfz16LPZoMMoSc4dzLl6w9qijkEb/r5O1ozdu1CWGA2L83ZeZg==", "dev": true }, "node_modules/@types/unist": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.8.tgz", - "integrity": "sha512-d0XxK3YTObnWVp6rZuev3c49+j4Lo8g4L1ZRm9z5L0xpoZycUPshHgczK5gsUMaZOstjVYYi09p5gYvUtfChYw==", + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.1.tgz", - "integrity": "sha512-w0tiiRc9I4S5XSXXrMHOWgHgxbrBn1Ro+PmiYhSg2ZVdxrAJtQgzU5o2m1BfP6UOn7Vxcc6152vFjQfmZR4xEg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/type-utils": "6.9.1", - "@typescript-eslint/utils": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -1231,50 +1386,17 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/parser": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.9.1.tgz", - "integrity": "sha512-C7AK2wn43GSaCUZ9do6Ksgi2g3mwFkMO3Cis96kzmgudoVaKyt62yNzJOktP0HDLb/iO2O0n2lBOzJgr6Q/cyg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "peer": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/typescript-estree": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4" }, "engines": { @@ -1294,13 +1416,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.1.tgz", - "integrity": "sha512-38IxvKB6NAne3g/+MyXMs2Cda/Sz+CEpmm+KLGEM8hx/CvnSRuw51i8ukfwB/B/sESdeTGet1NH1Wj7I0YXswg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1" + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1311,13 +1433,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.1.tgz", - "integrity": "sha512-eh2oHaUKCK58qIeYp19F5V5TbpM52680sB4zNSz29VBQPTWIlE/hCj5P5B1AChxECe/fmZlspAWFuRniep1Skg==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.9.1", - "@typescript-eslint/utils": "6.9.1", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1338,9 +1460,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.1.tgz", - "integrity": "sha512-BUGslGOb14zUHOUmDB2FfT6SI1CcZEJYfF3qFwBeUrU6srJfzANonwRYHDpLBuzbq3HaoF2XL2hcr01c8f8OaQ==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1351,16 +1473,17 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.1.tgz", - "integrity": "sha512-U+mUylTHfcqeO7mLWVQ5W/tMLXqVpRv61wm9ZtfE5egz7gtnmqVIw9ryh0mgIlkKk9rZLY3UHygsBSdB9/ftyw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/visitor-keys": "6.9.1", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, @@ -1377,51 +1500,18 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/utils": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.1.tgz", - "integrity": "sha512-L1T0A5nFdQrMVunpZgzqPL6y2wVreSyHhKGZryS6jrEN7bD9NplVAyMryUhXsQ4TWLnZmxc2ekar/lSGIlprCA==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.9.1", - "@typescript-eslint/types": "6.9.1", - "@typescript-eslint/typescript-estree": "6.9.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", "semver": "^7.5.4" }, "engines": { @@ -1435,46 +1525,13 @@ "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@typescript-eslint/utils/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.1.tgz", - "integrity": "sha512-MUaPUe/QRLEffARsmNfmpghuQkW436DvESW+h+M52w0coICHRfD6Np9/K6PdACwnrq1HmuLl+cSPZaJmeVPkSw==", + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.9.1", + "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1493,84 +1550,74 @@ "peer": true }, "node_modules/@vue/compiler-core": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.4.tgz", - "integrity": "sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g==", + "version": "3.4.29", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.4.29.tgz", + "integrity": "sha512-TFKiRkKKsRCKvg/jTSSKK7mYLJEQdUiUfykbG49rubC9SfDyvT2JrzTReopWlz2MxqeLyxh9UZhvxEIBgAhtrg==", "dev": true, "dependencies": { - "@babel/parser": "^7.21.3", - "@vue/shared": "3.3.4", + "@babel/parser": "^7.24.7", + "@vue/shared": "3.4.29", + "entities": "^4.5.0", "estree-walker": "^2.0.2", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-dom": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz", - "integrity": "sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w==", + "version": "3.4.29", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.4.29.tgz", + "integrity": "sha512-A6+iZ2fKIEGnfPJejdB7b1FlJzgiD+Y/sxxKwJWg1EbJu6ZPgzaPQQ51ESGNv0CP6jm6Z7/pO6Ia8Ze6IKrX7w==", "dev": true, "dependencies": { - "@vue/compiler-core": "3.3.4", - "@vue/shared": "3.3.4" + "@vue/compiler-core": "3.4.29", + "@vue/shared": "3.4.29" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz", - "integrity": "sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ==", + "version": "3.4.29", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.4.29.tgz", + "integrity": "sha512-zygDcEtn8ZimDlrEQyLUovoWgKQic6aEQqRXce2WXBvSeHbEbcAsXyCk9oG33ZkyWH4sl9D3tkYc1idoOkdqZQ==", "dev": true, "dependencies": { - "@babel/parser": "^7.20.15", - "@vue/compiler-core": "3.3.4", - "@vue/compiler-dom": "3.3.4", - "@vue/compiler-ssr": "3.3.4", - "@vue/reactivity-transform": "3.3.4", - "@vue/shared": "3.3.4", + "@babel/parser": "^7.24.7", + "@vue/compiler-core": "3.4.29", + "@vue/compiler-dom": "3.4.29", + "@vue/compiler-ssr": "3.4.29", + "@vue/shared": "3.4.29", "estree-walker": "^2.0.2", - "magic-string": "^0.30.0", - "postcss": "^8.1.10", - "source-map-js": "^1.0.2" + "magic-string": "^0.30.10", + "postcss": "^8.4.38", + "source-map-js": "^1.2.0" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz", - "integrity": "sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ==", + "version": "3.4.29", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.4.29.tgz", + "integrity": "sha512-rFbwCmxJ16tDp3N8XCx5xSQzjhidYjXllvEcqX/lopkoznlNPz3jyy0WGJCyhAaVQK677WWFt3YO/WUEkMMUFQ==", "dev": true, "dependencies": { - "@vue/compiler-dom": "3.3.4", - "@vue/shared": "3.3.4" - } - }, - "node_modules/@vue/reactivity-transform": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz", - "integrity": "sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw==", - "dev": true, - "dependencies": { - "@babel/parser": "^7.20.15", - "@vue/compiler-core": "3.3.4", - "@vue/shared": "3.3.4", - "estree-walker": "^2.0.2", - "magic-string": "^0.30.0" + "@vue/compiler-dom": "3.4.29", + "@vue/shared": "3.4.29" } }, "node_modules/@vue/shared": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.4.tgz", - "integrity": "sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ==", + "version": "3.4.29", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.4.29.tgz", + "integrity": "sha512-hQ2gAQcBO/CDpC82DCrinJNgOHI2v+FA7BDW4lMSPeBpQ7sRe2OLHWe5cph1s7D8DUQAwRt18dBDfJJ220APEA==", "dev": true }, "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz", + "integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1686,25 +1733,6 @@ "node": ">= 8" } }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true - }, - "node_modules/are-we-there-yet": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", - "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1755,12 +1783,15 @@ "dev": true }, "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/bluebird": { @@ -1785,21 +1816,21 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/browserslist": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz", - "integrity": "sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==", + "version": "4.23.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz", + "integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==", "dev": true, "funding": [ { @@ -1816,10 +1847,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001541", - "electron-to-chromium": "^1.4.535", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001629", + "electron-to-chromium": "^1.4.796", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.16" }, "bin": { "browserslist": "cli.js" @@ -1933,9 +1964,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001547", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001547.tgz", - "integrity": "sha512-W7CrtIModMAxobGhz8iXmDfuJiiKg1WADMO/9x7/CLNin5cpSbuBjooyoIUVB5eyCc36QuTVlkVa1iB2S5+/eA==", + "version": "1.0.30001634", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz", + "integrity": "sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA==", "dev": true, "funding": [ { @@ -2017,16 +2048,10 @@ } }, "node_modules/chokidar": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", - "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "funding": [ - { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - ], "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2039,6 +2064,9 @@ "engines": { "node": ">= 8.10.0" }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, "optionalDependencies": { "fsevents": "~2.3.2" } @@ -2093,15 +2121,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, - "bin": { - "color-support": "bin.js" - } - }, "node_modules/colord": { "version": "2.9.3", "resolved": "https://registry.npmjs.org/colord/-/colord-2.9.3.tgz", @@ -2148,12 +2167,6 @@ "source-map": "^0.6.1" } }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true - }, "node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -2341,9 +2354,9 @@ "optional": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, "dependencies": { "ms": "2.1.2" @@ -2420,12 +2433,6 @@ "node": ">=0.10.0" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -2436,9 +2443,9 @@ } }, "node_modules/diff": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", - "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, "engines": { "node": ">=0.3.1" @@ -2482,9 +2489,9 @@ } }, "node_modules/documentation": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.2.tgz", - "integrity": "sha512-hWoTf8/u4pOjib02L7w94hwmhPfcSwyJNGtlPdGVe8GFyq8HkzcFzQQltaaikKunHEp0YSwDAbwBAO7nxrWIfA==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/documentation/-/documentation-14.0.3.tgz", + "integrity": "sha512-B7cAviVKN9Rw7Ofd+9grhVuxiHwly6Ieh+d/ceMw8UdBOv/irkuwnDEJP8tq0wgdLJDUVuIkovV+AX9mTrZFxg==", "dev": true, "dependencies": { "@babel/core": "^7.18.10", @@ -2550,6 +2557,15 @@ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" } }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/domelementtype": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", @@ -2598,9 +2614,9 @@ "dev": true }, "node_modules/electron-to-chromium": { - "version": "1.4.553", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.553.tgz", - "integrity": "sha512-HiRdtyKS2+VhiXvjhMvvxiMC33FJJqTA5EB2YHgFZW6v7HkK4Q9Ahv2V7O2ZPgAjw+MyCJVMQvigj13H8t+wvA==", + "version": "1.4.803", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.803.tgz", + "integrity": "sha512-61H9mLzGOCLLVsnLiRzCbc63uldP0AniRYPV3hbGVtONA1pI7qSGILdbofR7A8TMbOypDocEAjH/e+9k1QIe3g==", "dev": true }, "node_modules/emoji-regex": { @@ -2620,10 +2636,13 @@ } }, "node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "engines": { + "node": ">=0.12" + }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" } @@ -2653,35 +2672,39 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "peer": true, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/eslint": { - "version": "8.52.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.52.0.tgz", - "integrity": "sha512-zh/JHnaixqHZsolRB/w9/02akBk9EPrOs9JwcTP2ek7yL5bVvXuRariiaAjjoJ5DvuwQ1WAE/HsMz+w17YgBCg==", + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", "dev": true, "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.52.0", - "@humanwhocodes/config-array": "^0.11.13", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", "@ungap/structured-clone": "^1.2.0", @@ -2783,36 +2806,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/eslint/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "peer": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2827,9 +2820,9 @@ } }, "node_modules/eslint/node_modules/globals": { - "version": "13.23.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.23.0.tgz", - "integrity": "sha512-XAmF0RjlrjY23MA51q3HltdlGxUpXPvg0GioKiD9X6HD28iMjo2dKC8Vqwm7lne4GNr78+RHTfliktR6ZH09wA==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "peer": true, "dependencies": { @@ -2852,22 +2845,6 @@ "node": ">=8" } }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "peer": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2881,48 +2858,6 @@ "node": "*" } }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "peer": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "peer": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "peer": true, - "engines": { - "node": ">=8" - } - }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2949,19 +2884,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -3037,6 +2959,12 @@ "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -3051,9 +2979,9 @@ "peer": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -3081,9 +3009,9 @@ "peer": true }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -3103,9 +3031,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -3132,25 +3060,26 @@ } }, "node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "peer": true, "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/flat-cache": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.1.tgz", - "integrity": "sha512-/qM2b3LUIaIgviBQovTLvijfyOQXPtSRnRK26ksj2J7rzPIecePUIpJsZ4T02Qg+xiAEKIs5K8dsHEd+VaKa/Q==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "peer": true, "dependencies": { @@ -3159,16 +3088,32 @@ "rimraf": "^3.0.2" }, "engines": { - "node": ">=12.0.0" + "node": "^10.12.0 || >=12.0.0" } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true, "peer": true }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -3215,23 +3160,13 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/gauge": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", - "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/gaze": { @@ -3293,9 +3228,9 @@ } }, "node_modules/git-url-parse": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.0.tgz", - "integrity": "sha512-5FvPJP/70WkIprlUZ33bm4UAaFdjcLkJLpWft1BeZKqwR0uhhNGoKwlUaPtVb4LxCSQ++erHapRak9kWGj+FCA==", + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-13.1.1.tgz", + "integrity": "sha512-PCFJyeSSdtnbfhSNRw9Wk96dDCNx+sogTe4YNXeXSJxt7xz5hvXekuRn9JX7m+Mf4OscCu8h+mtAl3+h5Fo8lQ==", "dev": true, "dependencies": { "git-up": "^7.0.0" @@ -3308,19 +3243,18 @@ "dev": true }, "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -3338,6 +3272,30 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -3397,26 +3355,6 @@ "concat-map": "0.0.1" } }, - "node_modules/globule/node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globule/node_modules/minimatch": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", @@ -3450,15 +3388,6 @@ "node": ">=6" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -3468,18 +3397,24 @@ "node": ">=4" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true - }, "node_modules/hash-sum": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", "dev": true }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hast-util-from-parse5": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz", @@ -3749,18 +3684,18 @@ } }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", "dev": true, "engines": { "node": ">= 4" } }, "node_modules/immutable": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", - "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==", + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz", + "integrity": "sha512-Ju0+lEMyzMVZarkTn/gqRpdqd5dOPaz1mCZ0SH3JV6iFw81PldE/PEB1hWVEA288HPt4WXW8O7AWxB10M+03QQ==", "dev": true }, "node_modules/import-cwd": { @@ -3792,16 +3727,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-fresh/node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/import-from": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz", @@ -3814,6 +3739,15 @@ "node": ">=8" } }, + "node_modules/import-from/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3838,16 +3772,6 @@ "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", "dev": true }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -3872,11 +3796,18 @@ "node": ">= 0.10" } }, - "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } }, "node_modules/is-absolute": { "version": "1.0.0", @@ -3948,12 +3879,12 @@ } }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -4083,6 +4014,24 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true }, + "node_modules/jackspeak": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -4116,22 +4065,28 @@ "xmlcreate": "^2.0.4" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/jsdoc": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.2.tgz", - "integrity": "sha512-e8cIg2z62InH7azBBi3EsSEqrKx+nUtAS5bBcYTSpZFA+vhNPyhv8PTFZ0WsjOPDj04/dOLlm08EDcQJDqaGQg==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/jsdoc/-/jsdoc-4.0.3.tgz", + "integrity": "sha512-Nu7Sf35kXJ1MWDZIMAuATRQTg1iIPdzh7tqJ6jjvaU/GfDf+qi5UV8zJR3Mo+/pYFvm8mzay4+6O5EWigaQBQw==", "dev": true, "dependencies": { "@babel/parser": "^7.20.15", "@jsdoc/salty": "^0.2.1", - "@types/markdown-it": "^12.2.3", + "@types/markdown-it": "^14.1.1", "bluebird": "^3.7.2", "catharsis": "^0.9.0", "escape-string-regexp": "^2.0.0", "js2xmlparser": "^4.0.2", "klaw": "^3.0.0", - "markdown-it": "^12.3.2", - "markdown-it-anchor": "^8.4.1", + "markdown-it": "^14.1.0", + "markdown-it-anchor": "^8.6.7", "marked": "^4.0.10", "mkdirp": "^1.0.4", "requizzle": "^0.2.3", @@ -4145,6 +4100,15 @@ "node": ">=12.0.0" } }, + "node_modules/jsdoc/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/jsdoc/node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -4209,9 +4173,9 @@ } }, "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==", "dev": true }, "node_modules/jsonfile": { @@ -4303,33 +4267,34 @@ "dev": true }, "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", + "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "dev": true, "dependencies": { - "uc.micro": "^1.0.1" + "uc.micro": "^2.0.0" } }, "node_modules/loader-utils": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", - "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.3.1.tgz", + "integrity": "sha512-FMJTLMXfCLMLfJxcX9PFqX5qD88Z5MRGaZCVzfuqeZSPsyiBzs+pahDQjbIWz2QIzPZz0NX9Zy4FX3lmK6YHIg==", "dev": true, "engines": { "node": ">= 12.13.0" } }, "node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "peer": true, "dependencies": { - "p-locate": "^6.0.0" + "p-locate": "^5.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -4392,15 +4357,12 @@ "dev": true }, "node_modules/magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", "dev": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" - }, - "engines": { - "node": ">=12" } }, "node_modules/make-dir": { @@ -4418,6 +4380,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/make-fetch-happen": { "version": "10.2.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", @@ -4476,19 +4447,20 @@ } }, "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", + "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "dependencies": { "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" + "entities": "^4.4.0", + "linkify-it": "^5.0.0", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" }, "bin": { - "markdown-it": "bin/markdown-it.js" + "markdown-it": "bin/markdown-it.mjs" } }, "node_modules/markdown-it-anchor": { @@ -4828,9 +4800,9 @@ "dev": true }, "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", "dev": true }, "node_modules/meow": { @@ -4917,15 +4889,6 @@ "node": ">=8" } }, - "node_modules/meow/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/meow/node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -5570,12 +5533,12 @@ ] }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -5592,15 +5555,18 @@ } }, "node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist-options": { @@ -5747,15 +5713,15 @@ "dev": true }, "node_modules/nan": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.18.0.tgz", - "integrity": "sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w==", + "version": "2.20.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz", + "integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==", "dev": true }, "node_modules/nanoid": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", - "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", "dev": true, "funding": [ { @@ -5786,152 +5752,359 @@ } }, "node_modules/node-gyp": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", - "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", "dev": true, "dependencies": { "env-paths": "^2.2.0", - "glob": "^7.1.4", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", "graceful-fs": "^4.2.6", - "make-fetch-happen": "^9.1.0", - "nopt": "^5.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", "semver": "^7.3.5", "tar": "^6.1.2", - "which": "^2.0.2" + "which": "^4.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": ">= 10.12.0" + "node": "^16.14.0 || >=18.0.0" } }, "node_modules/node-gyp/node_modules/@npmcli/fs": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", - "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dev": true, "dependencies": { - "@gar/promisify": "^1.0.1", "semver": "^7.3.5" - } - }, - "node_modules/node-gyp/node_modules/@npmcli/move-file": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", - "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" }, "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/node-gyp/node_modules/cacache": { - "version": "15.3.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", - "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", "dev": true, "dependencies": { - "@npmcli/fs": "^1.0.0", - "@npmcli/move-file": "^1.0.1", - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "glob": "^7.1.4", - "infer-owner": "^1.0.4", - "lru-cache": "^6.0.0", - "minipass": "^3.1.1", - "minipass-collect": "^1.0.2", + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.2", - "mkdirp": "^1.0.3", + "minipass-pipeline": "^1.2.4", "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^8.0.1", - "tar": "^6.0.2", - "unique-filename": "^1.1.1" + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" }, "engines": { - "node": ">= 10" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/node-gyp/node_modules/cacache/node_modules/glob": { + "version": "9.3.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz", + "integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^8.0.2", + "minipass": "^4.2.4", + "path-scurry": "^1.6.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/node-gyp/node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "node_modules/node-gyp/node_modules/cacache/node_modules/glob/node_modules/minipass": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz", + "integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-gyp/node_modules/cacache/node_modules/minimatch": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz", + "integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==", "dev": true, "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">= 6" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "engines": { + "node": ">=16" } }, "node_modules/node-gyp/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": "14 || >=16.14" } }, "node_modules/node-gyp/node_modules/make-fetch-happen": { + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", + "dev": true, + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "proc-log": "^4.2.0", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/make-fetch-happen/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/node-gyp/node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/node-gyp/node_modules/minipass-fetch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/node-gyp/node_modules/ssri": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", + "dev": true, + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dev": true, + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/node-sass": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-9.0.0.tgz", + "integrity": "sha512-yltEuuLrfH6M7Pq2gAj5B6Zm7m+gdZoG66wTqG6mIZV/zijq3M2OO2HswtT6oBspPyFhHDcaxWpsBm0fRNDHPg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "async-foreach": "^0.1.3", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "lodash": "^4.17.15", + "make-fetch-happen": "^10.0.4", + "meow": "^9.0.0", + "nan": "^2.17.0", + "node-gyp": "^10.1.0", + "sass-graph": "^4.0.1", + "stdout-stream": "^1.4.0", + "true-case-path": "^2.2.1" + }, + "bin": { + "node-sass": "bin/node-sass" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/node-sass/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/node-sass/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-sass/node_modules/node-gyp/node_modules/make-fetch-happen": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dev": true, + "extraneous": true, "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -5954,202 +6127,6 @@ "node": ">= 10" } }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/node-gyp/node_modules/minipass-fetch": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", - "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, - "dependencies": { - "minipass": "^3.1.0", - "minipass-sized": "^1.0.3", - "minizlib": "^2.0.0" - }, - "engines": { - "node": ">=8" - }, - "optionalDependencies": { - "encoding": "^0.1.12" - } - }, - "node_modules/node-gyp/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-gyp/node_modules/socks-proxy-agent": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", - "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "dev": true, - "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/node-gyp/node_modules/ssri": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", - "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "dev": true, - "dependencies": { - "minipass": "^3.1.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/node-gyp/node_modules/unique-filename": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", - "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, - "dependencies": { - "unique-slug": "^2.0.0" - } - }, - "node_modules/node-gyp/node_modules/unique-slug": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", - "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, - "dependencies": { - "imurmurhash": "^0.1.4" - } - }, - "node_modules/node-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true - }, - "node_modules/node-sass": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-9.0.0.tgz", - "integrity": "sha512-yltEuuLrfH6M7Pq2gAj5B6Zm7m+gdZoG66wTqG6mIZV/zijq3M2OO2HswtT6oBspPyFhHDcaxWpsBm0fRNDHPg==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "async-foreach": "^0.1.3", - "chalk": "^4.1.2", - "cross-spawn": "^7.0.3", - "gaze": "^1.0.0", - "get-stdin": "^4.0.1", - "glob": "^7.0.3", - "lodash": "^4.17.15", - "make-fetch-happen": "^10.0.4", - "meow": "^9.0.0", - "nan": "^2.17.0", - "node-gyp": "^8.4.1", - "sass-graph": "^4.0.1", - "stdout-stream": "^1.4.0", - "true-case-path": "^2.2.1" - }, - "bin": { - "node-sass": "bin/node-sass" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/node-sass/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/node-sass/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/node-sass/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-sass/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/node-sass/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/node-sass/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -6163,18 +6140,18 @@ } }, "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dev": true, "dependencies": { - "abbrev": "1" + "abbrev": "^2.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": ">=6" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/normalize-package-data": { @@ -6192,39 +6169,6 @@ "node": ">=10" } }, - "node_modules/normalize-package-data/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/normalize-package-data/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -6326,6 +6270,11 @@ "write-file-atomic" ], "dev": true, + "workspaces": [ + "docs", + "smoke-tests", + "workspaces/*" + ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/arborist": "^5.6.3", @@ -6370,7 +6319,7 @@ "mkdirp": "^1.0.4", "mkdirp-infer-owner": "^2.0.0", "ms": "^2.1.2", - "node-gyp": "^9.1.0", + "node-gyp": "^10.1.0", "nopt": "^6.0.0", "npm-audit-report": "^3.0.0", "npm-install-checks": "^5.0.0", @@ -8812,21 +8761,6 @@ "inBundle": true, "license": "ISC" }, - "node_modules/npmlog": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", - "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, - "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -8839,28 +8773,19 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "peer": true, "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { "node": ">= 0.8.0" @@ -8876,30 +8801,32 @@ } }, "node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "peer": true, "dependencies": { - "yocto-queue": "^1.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "peer": true, "dependencies": { - "p-limit": "^4.0.0" + "p-limit": "^3.0.2" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -9027,21 +8954,12 @@ "dev": true }, "node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/path-key": { @@ -9080,6 +8998,40 @@ "node": ">=0.10.0" } }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", @@ -9090,9 +9042,9 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", "dev": true }, "node_modules/picomatch": { @@ -9183,19 +9135,10 @@ "node": ">=8" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "version": "8.4.38", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz", + "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==", "dev": true, "funding": [ { @@ -9212,9 +9155,9 @@ } ], "dependencies": { - "nanoid": "^3.3.6", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "source-map-js": "^1.2.0" }, "engines": { "node": "^10 || ^12 || >=14" @@ -9462,9 +9405,9 @@ } }, "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz", + "integrity": "sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==", "dev": true, "engines": { "node": "^10 || ^12 || >= 14" @@ -9474,9 +9417,9 @@ } }, "node_modules/postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.5.tgz", + "integrity": "sha512-6MieY7sIfTK0hYfafw1OMEG+2bg8Q1ocHCpoWLqOKj3JXlKu4G7btkmM/B7lFubYkYWmRSPLZi5chid63ZaZYw==", "dev": true, "dependencies": { "icss-utils": "^5.0.0", @@ -9491,9 +9434,9 @@ } }, "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.2.0.tgz", + "integrity": "sha512-oq+g1ssrsZOsx9M96c5w8laRmvEu9C3adDSjI8oTcbfkrTE8hx/zfyobUoWIxaKPO8bt6S62kxpw5GqypEw1QQ==", "dev": true, "dependencies": { "postcss-selector-parser": "^6.0.4" @@ -9702,9 +9645,9 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.13", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz", - "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", "dev": true, "dependencies": { "cssesc": "^3.0.0", @@ -9761,6 +9704,15 @@ "node": ">= 0.8.0" } }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -9796,9 +9748,9 @@ } }, "node_modules/property-information": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.3.0.tgz", - "integrity": "sha512-gVNZ74nqhRMiIUYWGQdosYetaKc83x8oT41a0LlV3AAFCAZwCpg4vmGkq8t34+cUhp3cnM4XDiU/7xlgK7HGrg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz", + "integrity": "sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==", "dev": true, "funding": { "type": "github", @@ -9821,6 +9773,15 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9894,6 +9855,76 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/read-pkg-up/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -9906,6 +9937,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/read-pkg-up/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/read-pkg/node_modules/type-fest": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", @@ -9918,20 +9961,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -10102,12 +10131,13 @@ } }, "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "peer": true, "engines": { - "node": ">=8" + "node": ">=4" } }, "node_modules/retry": { @@ -10133,6 +10163,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -10144,53 +10175,14 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/rollup": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.1.5.tgz", - "integrity": "sha512-AEw14/q4NHYQkQlngoSae2yi7hDBeT9w84aEzdgCr39+2RL+iTG84lGTkgC1Wp5igtquN64cNzuzZKVz+U6jOg==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, "bin": { "rollup": "dist/bin/rollup" }, @@ -10199,18 +10191,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.1.5", - "@rollup/rollup-android-arm64": "4.1.5", - "@rollup/rollup-darwin-arm64": "4.1.5", - "@rollup/rollup-darwin-x64": "4.1.5", - "@rollup/rollup-linux-arm-gnueabihf": "4.1.5", - "@rollup/rollup-linux-arm64-gnu": "4.1.5", - "@rollup/rollup-linux-arm64-musl": "4.1.5", - "@rollup/rollup-linux-x64-gnu": "4.1.5", - "@rollup/rollup-linux-x64-musl": "4.1.5", - "@rollup/rollup-win32-arm64-msvc": "4.1.5", - "@rollup/rollup-win32-ia32-msvc": "4.1.5", - "@rollup/rollup-win32-x64-msvc": "4.1.5", + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", "fsevents": "~2.3.2" } }, @@ -10329,39 +10325,6 @@ "node": ">= 8.0.0" } }, - "node_modules/rollup-plugin-typescript2/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/rollup-plugin-typescript2/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/rollup-plugin-typescript2/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/rollup-plugin-vue": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/rollup-plugin-vue/-/rollup-plugin-vue-6.0.0.tgz", @@ -10460,9 +10423,9 @@ "optional": true }, "node_modules/sass": { - "version": "1.69.5", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", - "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==", + "version": "1.77.5", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.77.5.tgz", + "integrity": "sha512-oDfX1mukIlxacPdQqNb6mV2tVCrnE+P3nVYioy72V5tlk56CPNcO4TCuFcaCRKKfJ1M3lH95CleRS+dVKL2qMg==", "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", @@ -10494,48 +10457,6 @@ "node": ">=12" } }, - "node_modules/sass-graph/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/sass-graph/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sass-graph/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, "node_modules/scss-tokenizer": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.4.3.tgz", @@ -10556,29 +10477,26 @@ } }, "node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "dev": true, "bin": { "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/serialize-javascript": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", - "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "dependencies": { "randombytes": "^2.1.0" } }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -10601,9 +10519,9 @@ } }, "node_modules/shiki": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.5.tgz", - "integrity": "sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==", + "version": "0.14.7", + "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", + "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", "dev": true, "dependencies": { "ansi-sequence-parser": "^1.1.0", @@ -10613,10 +10531,16 @@ } }, "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, "node_modules/slash": { "version": "3.0.0", @@ -10638,22 +10562,22 @@ } }, "node_modules/smob": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", - "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.5.0.tgz", + "integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==", "dev": true }, "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dev": true, "dependencies": { - "ip": "^2.0.0", + "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, @@ -10681,9 +10605,9 @@ } }, "node_modules/source-map-js": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", - "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", "dev": true, "engines": { "node": ">=0.10.0" @@ -10720,9 +10644,9 @@ } }, "node_modules/spdx-exceptions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true }, "node_modules/spdx-expression-parse": { @@ -10736,9 +10660,15 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.16", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", + "version": "3.0.18", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz", + "integrity": "sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", "dev": true }, "node_modules/ssri": { @@ -10799,15 +10729,6 @@ "safe-buffer": "~5.1.0" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-hash": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", @@ -10828,10 +10749,25 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/stringify-entities": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz", - "integrity": "sha512-BP9nNHMhhfcMbiuQKCqMjhDP5yBCAxsPu4pHFFzJ6Alo9dZgY4VLDPutXqIjpRiMoKdp7Av85Gr73Q5uH9k7+g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", "dev": true, "dependencies": { "character-entities-html4": "^2.0.0", @@ -10854,6 +10790,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-indent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", @@ -10946,9 +10895,9 @@ } }, "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, "dependencies": { "chownr": "^2.0.0", @@ -10978,9 +10927,9 @@ "dev": true }, "node_modules/terser": { - "version": "5.23.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.23.0.tgz", - "integrity": "sha512-Iyy83LN0uX9ZZLCX4Qbu5JiHiWjOCTwrmM9InWOzVeM++KNWEsqV4YgN9U9E8AlohQ6Gs42ztczlWOG/lwDAMA==", + "version": "5.31.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.31.1.tgz", + "integrity": "sha512-37upzU1+viGvuFtBo9NPufCb9dwM0+l9hMxYyWfBA+fbwrPqNJAhbZ6W47bBFnZHKHTUBnMvi87434qq+qnxOg==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -11049,9 +10998,9 @@ } }, "node_modules/trough": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/trough/-/trough-2.1.0.tgz", - "integrity": "sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", "dev": true, "funding": { "type": "github", @@ -11065,21 +11014,21 @@ "dev": true }, "node_modules/ts-api-utils": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", - "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { - "node": ">=16.13.0" + "node": ">=16" }, "peerDependencies": { "typescript": ">=4.2.0" } }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", + "integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==", "dev": true }, "node_modules/type-check": { @@ -11108,15 +11057,15 @@ } }, "node_modules/typedoc": { - "version": "0.25.3", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.3.tgz", - "integrity": "sha512-Ow8Bo7uY1Lwy7GTmphRIMEo6IOZ+yYUyrc8n5KXIZg1svpqhZSWgni2ZrDhe+wLosFS8yswowUzljTAV/3jmWw==", + "version": "0.25.13", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.25.13.tgz", + "integrity": "sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ==", "dev": true, "dependencies": { "lunr": "^2.3.9", "marked": "^4.3.0", "minimatch": "^9.0.3", - "shiki": "^0.14.1" + "shiki": "^0.14.7" }, "bin": { "typedoc": "bin/typedoc" @@ -11125,37 +11074,22 @@ "node": ">= 16" }, "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x" + "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x" } }, "node_modules/typedoc-plugin-missing-exports": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-2.1.0.tgz", - "integrity": "sha512-+1DhqZCEu7Vu5APnrqpPwl31D+hXpt1fV0Le9ycCRL1eLVdatdl6KVt4SEVwPxnEpKwgOn2dNX6I9+0F1aO2aA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-2.3.0.tgz", + "integrity": "sha512-iI9ITNNLlbsLCBBeYDyu0Qqp3GN/9AGyWNKg8bctRXuZEPT7G1L+0+MNWG9MsHcf/BFmNbXL0nQ8mC/tXRicog==", "dev": true, "peerDependencies": { "typedoc": "0.24.x || 0.25.x" } }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -11166,9 +11100,9 @@ } }, "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", "dev": true }, "node_modules/unc-path-regex": { @@ -11333,18 +11267,18 @@ } }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "engines": { "node": ">= 10.0.0" } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", "dev": true, "funding": [ { @@ -11361,8 +11295,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -11570,9 +11504,9 @@ "dev": true }, "node_modules/vue-template-compiler": { - "version": "2.7.14", - "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz", - "integrity": "sha512-zyA5Y3ArvVG0NacJDkkzJuPQDF8RFeRlzV2vLeSnhSpieO6LK2OVbdLPi5MPPs09Ii+gMO8nY4S3iKQxBxDmWQ==", + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.7.16.tgz", + "integrity": "sha512-AYbUWAJHLGGQM7+cNTELw+KsOG9nl2CnSv467WobS5Cv9uk3wFcnr1Etsz2sEIHEZvw1U+o9mRlEO6QbZvUPGQ==", "dev": true, "optional": true, "dependencies": { @@ -11605,13 +11539,14 @@ "node": ">= 8" } }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" + "peer": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/wrap-ansi": { @@ -11631,11 +11566,23 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } }, "node_modules/xmlcreate": { "version": "2.0.4", @@ -11704,12 +11651,13 @@ } }, "node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "peer": true, "engines": { - "node": ">=12.20" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" diff --git a/package.json b/package.json index 5d4c1f3..329bcd5 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,10 @@ "typedoc-plugin-missing-exports": "^2.1.0", "typescript": "^5.2.2" }, + "overrides": { + "node-gyp": "^10.1.0", + "glob": "^9.0.0" + }, "eslintConfig": { "root": true, "extends": "eslint:recommended", diff --git a/spice-squid/Containerfile b/spice-squid/Containerfile index b65b631..5c94829 100644 --- a/spice-squid/Containerfile +++ b/spice-squid/Containerfile @@ -1,4 +1,4 @@ -FROM alpine:3.19 +FROM docker.io/alpine:3.19 RUN apk update &&\ apk add --no-cache inotify-tools &&\ From 92f4b3aaf83327f78743511a08d5cd5b5bb99409 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 18 Jun 2024 18:03:14 +0200 Subject: [PATCH 028/342] Avoid unnecessary pages runs. --- .gitlab-ci.yml | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f1e59d7..a8673aa 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -55,18 +55,22 @@ publish-images: test-pages: stage: test extends: .pages-job + rules: + - if: $CI_COMMIT_BRANCH == "gh-pages" script: - bundle exec jekyll build -d test artifacts: paths: - test -publish-pages: - stage: publish - extends: .pages-job - script: - - bundle exec jekyll build -d public - artifacts: - paths: - - public - environment: production +#publish-pages: +# stage: publish +# extends: .pages-job +# rules: +# - if: $CI_COMMIT_BRANCH == "gh-pages" +# script: +# - bundle exec jekyll build -d public +# artifacts: +# paths: +# - public +# environment: production From 98ce74f42b30795edc9c33de2c1e6072865c83db Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 18 Jun 2024 21:32:01 +0200 Subject: [PATCH 029/342] Adjust link. --- buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle index 081b7d9..8e8413e 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle @@ -67,7 +67,7 @@ task apidocs (type: JavaExec) { '-use', '-linksource', '-link', 'https://docs.oracle.com/en/java/javase/21/docs/api/', - '-link', 'https://mnlipp.github.io/jgrapes/latest-release/javadoc/', + '-link', 'https://jgrapes.org/latest-release/javadoc/', '-link', 'https://freemarker.apache.org/docs/api/', '--add-exports', 'jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED', '--add-exports', 'jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', From f0ccb83b39fb23ae743bafb34be66bb518ed5784 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 20 Jun 2024 20:41:33 +0200 Subject: [PATCH 030/342] Move pages. --- webpages/.gitignore | 4 + webpages/Gemfile | 5 + webpages/_config.yml | 10 + webpages/_includes/matomo.html | 23 ++ webpages/_includes/toc.html | 96 +++++++ webpages/_layouts/vm-operator.html | 71 +++++ webpages/stylesheets/pygment_trac.css | 69 +++++ webpages/stylesheets/styles.css | 244 ++++++++++++++++++ webpages/vm-operator/02_2_operator.png | Bin 0 -> 109024 bytes .../vm-operator/VM-Operator-GUI-preview.png | Bin 0 -> 40113 bytes webpages/vm-operator/VM-Operator-GUI-view.png | Bin 0 -> 42919 bytes .../vm-operator/VM-Operator-with-font.svg | 173 +++++++++++++ webpages/vm-operator/VM-Operator.svg | 184 +++++++++++++ webpages/vm-operator/VmViewer-preview.png | Bin 0 -> 13757 bytes webpages/vm-operator/admin-gui.md | 18 ++ webpages/vm-operator/controller.md | 226 ++++++++++++++++ webpages/vm-operator/favicon.svg | 88 +++++++ webpages/vm-operator/index.md | 60 +++++ webpages/vm-operator/manager.md | 150 +++++++++++ webpages/vm-operator/runner.md | 108 ++++++++ webpages/vm-operator/upgrading.md | 29 +++ webpages/vm-operator/user-gui.md | 143 ++++++++++ webpages/vm-operator/webgui.md | 117 +++++++++ 23 files changed, 1818 insertions(+) create mode 100644 webpages/.gitignore create mode 100644 webpages/Gemfile create mode 100644 webpages/_config.yml create mode 100644 webpages/_includes/matomo.html create mode 100644 webpages/_includes/toc.html create mode 100644 webpages/_layouts/vm-operator.html create mode 100644 webpages/stylesheets/pygment_trac.css create mode 100644 webpages/stylesheets/styles.css create mode 100644 webpages/vm-operator/02_2_operator.png create mode 100644 webpages/vm-operator/VM-Operator-GUI-preview.png create mode 100644 webpages/vm-operator/VM-Operator-GUI-view.png create mode 100644 webpages/vm-operator/VM-Operator-with-font.svg create mode 100644 webpages/vm-operator/VM-Operator.svg create mode 100644 webpages/vm-operator/VmViewer-preview.png create mode 100644 webpages/vm-operator/admin-gui.md create mode 100644 webpages/vm-operator/controller.md create mode 100644 webpages/vm-operator/favicon.svg create mode 100644 webpages/vm-operator/index.md create mode 100644 webpages/vm-operator/manager.md create mode 100644 webpages/vm-operator/runner.md create mode 100644 webpages/vm-operator/upgrading.md create mode 100644 webpages/vm-operator/user-gui.md create mode 100644 webpages/vm-operator/webgui.md diff --git a/webpages/.gitignore b/webpages/.gitignore new file mode 100644 index 0000000..7615a9d --- /dev/null +++ b/webpages/.gitignore @@ -0,0 +1,4 @@ +_site +Gemfile.lock +.bundle +.jekyll-cache \ No newline at end of file diff --git a/webpages/Gemfile b/webpages/Gemfile new file mode 100644 index 0000000..ecbbb7d --- /dev/null +++ b/webpages/Gemfile @@ -0,0 +1,5 @@ +source 'https://rubygems.org' +# gem 'github-pages', group: :jekyll_plugins +gem "jekyll", "~> 4.0" +gem "jekyll-seo-tag" +gem 'webrick', '~> 1.3', '>= 1.3.1' diff --git a/webpages/_config.yml b/webpages/_config.yml new file mode 100644 index 0000000..39ca339 --- /dev/null +++ b/webpages/_config.yml @@ -0,0 +1,10 @@ +plugins: + - jekyll-seo-tag + +author: Michael N. Lipp + +logo: VM-Operator.svg + +tagline: VM-Operator by mnlipp + +description: A Kubernetes operator for running virtual machines (notably Qemu VMs) as pods. diff --git a/webpages/_includes/matomo.html b/webpages/_includes/matomo.html new file mode 100644 index 0000000..3a93186 --- /dev/null +++ b/webpages/_includes/matomo.html @@ -0,0 +1,23 @@ + + + + + diff --git a/webpages/_includes/toc.html b/webpages/_includes/toc.html new file mode 100644 index 0000000..56ac8e4 --- /dev/null +++ b/webpages/_includes/toc.html @@ -0,0 +1,96 @@ +{% capture tocWorkspace %} + {% comment %} + Version 1.0.10 + https://github.com/allejo/jekyll-toc + + "...like all things liquid - where there's a will, and ~36 hours to spare, there's usually a/some way" ~jaybe + + Usage: + {% include toc.html html=content sanitize=true class="inline_toc" id="my_toc" h_min=2 h_max=3 %} + + Parameters: + * html (string) - the HTML of compiled markdown generated by kramdown in Jekyll + + Optional Parameters: + * sanitize (bool) : false - when set to true, the headers will be stripped of any HTML in the TOC + * class (string) : '' - a CSS class assigned to the TOC + * id (string) : '' - an ID to assigned to the TOC + * h_min (int) : 1 - the minimum TOC header level to use; any header lower than this value will be ignored + * h_max (int) : 6 - the maximum TOC header level to use; any header greater than this value will be ignored + * ordered (bool) : false - when set to true, an ordered list will be outputted instead of an unordered list + * item_class (string) : '' - add custom class(es) for each list item; has support for '%level%' placeholder, which is the current heading level + * baseurl (string) : '' - add a base url to the TOC links for when your TOC is on another page than the actual content + * anchor_class (string) : '' - add custom class(es) for each anchor element + + Output: + An ordered or unordered list representing the table of contents of a markdown block. This snippet will only + generate the table of contents and will NOT output the markdown given to it + {% endcomment %} + + {% capture my_toc %}{% endcapture %} + {% assign orderedList = include.ordered | default: false %} + {% assign minHeader = include.h_min | default: 1 %} + {% assign maxHeader = include.h_max | default: 6 %} + {% assign nodes = include.html | split: ' maxHeader %} + {% continue %} + {% endif %} + + {% if firstHeader %} + {% assign firstHeader = false %} + {% assign minHeader = headerLevel %} + {% endif %} + + {% assign indentAmount = headerLevel | minus: minHeader %} + {% assign _workspace = node | split: '' | first }}>{% endcapture %} + {% assign header = _workspace[0] | replace: _hAttrToStrip, '' %} + + {% assign space = '' %} + {% for i in (1..indentAmount) %} + {% assign space = space | prepend: ' ' %} + {% endfor %} + + {% if include.item_class and include.item_class != blank %} + {% capture listItemClass %}{:.{{ include.item_class | replace: '%level%', headerLevel }}}{% endcapture %} + {% endif %} + + {% capture heading_body %}{% if include.sanitize %}{{ header | strip_html }}{% else %}{{ header }}{% endif %}{% endcapture %} + {% capture my_toc %}{{ my_toc }} +{{ space }}{{ listModifier }} {{ listItemClass }} [{{ heading_body | replace: "|", "\|" }}]({% if include.baseurl %}{{ include.baseurl }}{% endif %}#{{ html_id }}){% if include.anchor_class %}{:.{{ include.anchor_class }}}{% endif %}{% endcapture %} + {% endfor %} + + {% if include.class and include.class != blank %} + {% capture my_toc %}{:.{{ include.class }}} +{{ my_toc | lstrip }}{% endcapture %} + {% endif %} + + {% if include.id %} + {% capture my_toc %}{: #{{ include.id }}} +{{ my_toc | lstrip }}{% endcapture %} + {% endif %} +{% endcapture %}{% assign tocWorkspace = '' %}{{ my_toc | markdownify | strip }} diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html new file mode 100644 index 0000000..dfe4220 --- /dev/null +++ b/webpages/_layouts/vm-operator.html @@ -0,0 +1,71 @@ + + + + + + + + + + + + {% seo %} + + +

+ + {% include matomo.html %} + + + diff --git a/webpages/stylesheets/pygment_trac.css b/webpages/stylesheets/pygment_trac.css new file mode 100644 index 0000000..c6a6452 --- /dev/null +++ b/webpages/stylesheets/pygment_trac.css @@ -0,0 +1,69 @@ +.highlight { background: #ffffff; } +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #d14 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #0086B3 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #d14 } /* Literal.String.Backtick */ +.highlight .sc { color: #d14 } /* Literal.String.Char */ +.highlight .sd { color: #d14 } /* Literal.String.Doc */ +.highlight .s2 { color: #d14 } /* Literal.String.Double */ +.highlight .se { color: #d14 } /* Literal.String.Escape */ +.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ +.highlight .si { color: #d14 } /* Literal.String.Interpol */ +.highlight .sx { color: #d14 } /* Literal.String.Other */ +.highlight .sr { color: #009926 } /* Literal.String.Regex */ +.highlight .s1 { color: #d14 } /* Literal.String.Single */ +.highlight .ss { color: #990073 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ + +.type-csharp .highlight .k { color: #0000FF } +.type-csharp .highlight .kt { color: #0000FF } +.type-csharp .highlight .nf { color: #000000; font-weight: normal } +.type-csharp .highlight .nc { color: #2B91AF } +.type-csharp .highlight .nn { color: #000000 } +.type-csharp .highlight .s { color: #A31515 } +.type-csharp .highlight .sc { color: #A31515 } diff --git a/webpages/stylesheets/styles.css b/webpages/stylesheets/styles.css new file mode 100644 index 0000000..748ffcb --- /dev/null +++ b/webpages/stylesheets/styles.css @@ -0,0 +1,244 @@ +body { + background-color: #fff; + padding:50px; + font: normal 16px/1.5 Verdana, Arial, Helvetica, sans-serif; + color:#595959; +} + +h1, h2, h3, h4, h5, h6 { + color:#222; + margin:0 0 20px; +} + +p, ul, ol, table, pre, dl { + margin:0 0 20px; +} + +h1, h2, h3 { + line-height:1.1; +} + +h1 { + font-size:28px; + font-weight: 500; +} + +h2 { + color:#393939; + font-weight: 500; +} + +h3, h4, h5, h6 { + color:#494949; + font-weight: 500; +} + +a { + color:#39c; + text-decoration:none; +} + +a:hover { + color:#069; +} + +a small { + font-size:11px; + color:#777; + margin-top:-0.3em; + display:block; +} + +a:hover small { + color:#777; +} + +.wrapper { + /* width:860px; */ + width: 100%; + margin:0 auto; +} + +blockquote { + border-left:1px solid #e5e5e5; + margin:0; + padding:0 0 0 20px; + font-style:italic; +} + +code, pre { + font-family:Monaco, Bitstream Vera Sans Mono, Lucida Console, Terminal, Consolas, Liberation Mono, DejaVu Sans Mono, Courier New, monospace; + color:#333; +} + +pre { + font-size: 15px; + padding:8px 15px; + background: #f8f8f8; + border-radius:5px; + border:1px solid #e5e5e5; + overflow-x: auto; +} + +a code { + color: inherit; +} + +table { + width:100%; + border-collapse:collapse; +} + +th, td { + text-align:left; + padding:5px 10px; + border-bottom:1px solid #e5e5e5; +} + +dt { + color:#444; + font-weight:500; +} + +th { + color:#444; +} + +img { + max-width:100%; +} + +header { + /* width:270px; */ + width:calc(29% - 50px); + height:calc(100% - 160px); + overflow: auto; + float:left; + position:fixed; + -webkit-font-smoothing:subpixel-antialiased; +} + +header li { + list-style-type: disc; +} + +header ul { + padding-left: 1rem; +} + +header ul > li { + margin-left: 1rem; +} + +ul.no-bullets { + padding-left: 0; +} + +ul.no-bullets > li { + list-style: none; +} + +strong { + color:#222; + font-weight:500; +} + +section { + width:70%; + max-width:54em; + float:right; + padding-bottom:50px; +} + +small { + font-size:11px; +} + +hr { + border:0; + background:#e5e5e5; + height:1px; + margin:0 0 20px; +} + +footer { + /* width:270px; */ + width:calc(24% - 50px); + height:40px; + float:left; + position:fixed; + padding:30px 0; + bottom:0px; + background-color:white; + -webkit-font-smoothing:subpixel-antialiased; +} + +.post-date { + float: right; +} + +.part-list-title { + margin-bottom:5px; +} + +.part-entry { + margin-bottom:5px; +} + +@media print, screen and (max-width: 960px) { + + div.wrapper { + width:auto; + margin:0; + } + + header, section, footer { + float:none; + position:static; + width:auto; + } + + header { + padding-right:320px; + } + + section { + border:1px solid #e5e5e5; + border-width:1px 0; + padding:20px 0; + margin:0 0 20px; + } + + header a small { + display:inline; + } +} + +@media print, screen and (max-width: 720px) { + body { + word-wrap:break-word; + } + + header { + padding:0; + } + + pre, code { + word-wrap:normal; + } +} + +@media print, screen and (max-width: 480px) { + body { + padding:15px; + } + +} + +@media print { + body { + padding:0.4in; + font-size:12pt; + color:#444; + } +} diff --git a/webpages/vm-operator/02_2_operator.png b/webpages/vm-operator/02_2_operator.png new file mode 100644 index 0000000000000000000000000000000000000000..d3909d43d24e3c4fddb5b5c5e172beda44bf573a GIT binary patch literal 109024 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 literal 0 HcmV?d00001 diff --git a/webpages/vm-operator/VM-Operator-GUI-preview.png b/webpages/vm-operator/VM-Operator-GUI-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..b5293d710d1b95511c37a0f9b25ab9148f6a40af GIT binary patch literal 40113 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 + + + + \ No newline at end of file From 63c03dae81eb4975a3c3ece02b72d653324d35ff Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Jun 2024 14:40:14 +0200 Subject: [PATCH 035/342] Publish javadoc with JDK-21. --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 1a11881..d0ebc71 100644 --- a/build.gradle +++ b/build.gradle @@ -27,7 +27,7 @@ task stage { tc -> tc.findByName("build") }.flatten() } - if (JavaVersion.current() == JavaVersion.VERSION_17) { + if (JavaVersion.current() == JavaVersion.VERSION_21) { // Publish JavaDoc dependsOn gitPublishPush } From a50809211d8a09868c3d9660d3e8224649afa130 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Jun 2024 14:46:54 +0200 Subject: [PATCH 036/342] Fix name. --- misc/javadoc.bottom.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/javadoc.bottom.txt b/misc/javadoc.bottom.txt index 42d0ccd..abf54f3 100644 --- a/misc/javadoc.bottom.txt +++ b/misc/javadoc.bottom.txt @@ -4,7 +4,7 @@ TermsPrivacy

From 86837bc81b4dbf371884da16e97f399c0f3cd24c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Jun 2024 15:11:01 +0200 Subject: [PATCH 037/342] Fix token. --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a9b5d98..161b7c8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,4 +37,4 @@ jobs: java-version: '21' distribution: 'temurin' - name: Push with Gradle - run: ./gradlew -Prepo.access.token=${{ secrets.REPO_ACCESS_TOKEN }} -Pdocker.registry=ghcr.io/${{ github.actor }} stage pushImages + run: ./gradlew -Pwebsite.push.token=${{ secrets.WEBSITE_PUSH_TOKEN }} -Pdocker.registry=ghcr.io/${{ github.actor }} stage pushImages From 28691b64439588de1201f460760b1428e2c19399 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Jun 2024 16:06:31 +0200 Subject: [PATCH 038/342] Make dependencies branch specific. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a8673aa..740fd8f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,7 @@ stages: extends: .any-job image: registry.mnl.de/org/jgrapes/jdk21-builder:v2 cache: - - key: dependencies + - key: dependencies-CI_COMMIT_BRANCH policy: pull-push paths: - .gradle From e830815400fbff6ab0e6558eaaf813b9ff41fd0f Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Jun 2024 23:03:28 +0200 Subject: [PATCH 039/342] Add dependency. --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 740fd8f..62a51fb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -37,6 +37,8 @@ build-jars: publish-images: stage: publish extends: .gradle-job + dependencies: + - build-jars script: - ./gradlew -Pdocker.registry=$CI_REGISTRY_IMAGE pushImage From 12ca211fdba91a625cbc69402672864cef8cb1e2 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 23 Jun 2024 11:25:19 +0200 Subject: [PATCH 040/342] Fix env reference. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 62a51fb..13b12fd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,7 +12,7 @@ stages: extends: .any-job image: registry.mnl.de/org/jgrapes/jdk21-builder:v2 cache: - - key: dependencies-CI_COMMIT_BRANCH + - key: dependencies-${CI_COMMIT_BRANCH} policy: pull-push paths: - .gradle From 7df0cc386ccdc0960e55ca5782bfbe98b722685c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 23 Jun 2024 12:52:18 +0200 Subject: [PATCH 041/342] Fix image building. --- .github/workflows/release.yml | 2 +- .gitlab-ci.yml | 2 +- org.jdrupes.vmoperator.manager/build.gradle | 35 +++++---- .../build.gradle | 75 ++++++++++--------- spice-squid/build.gradle | 56 ++++++-------- 5 files changed, 86 insertions(+), 84 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 161b7c8..beab0c4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,4 +37,4 @@ jobs: java-version: '21' distribution: 'temurin' - name: Push with Gradle - run: ./gradlew -Pwebsite.push.token=${{ secrets.WEBSITE_PUSH_TOKEN }} -Pdocker.registry=ghcr.io/${{ github.actor }} stage pushImages + run: ./gradlew -Pwebsite.push.token=${{ secrets.WEBSITE_PUSH_TOKEN }} -Pdocker.registry=ghcr.io/${{ github.actor }} stage publishImage diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 13b12fd..04acdec 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -40,7 +40,7 @@ publish-images: dependencies: - build-jars script: - - ./gradlew -Pdocker.registry=$CI_REGISTRY_IMAGE pushImage + - ./gradlew -Pdocker.registry=$CI_REGISTRY_IMAGE publishImage .pages-job: extends: .any-job diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index a956a00..45d9494 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -46,6 +46,7 @@ application { } project.ext.gitBranch = grgit.branch.current.name.replace('/', '-') +def registry = "${project.rootProject.properties['docker.registry']}" task buildImage(type: Exec) { dependsOn installDist @@ -61,20 +62,23 @@ task pushImage(type: Exec) { // Don't push without testing first dependsOn test - def registry = "${project.rootProject.properties['docker.registry']}" commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}:${project.gitBranch}", \ + "${project.name}:${project.gitBranch}", \ "${registry}/${project.name}:${project.gitBranch}" - - if (!project.version.contains("SNAPSHOT")) { - commandLine 'podman', 'tag', \ - "${registry}/${project.name}:${project.gitBranch}",\ - "${registry}/${project.name}:${project.version}" - } +} + +task tagWithVersion(type: Exec) { + dependsOn pushImage + + enabled = !project.version.contains("SNAPSHOT") + + commandLine 'podman', 'push', \ + "${project.name}:${project.gitBranch}",\ + "${registry}/${project.name}:${project.version}" } task tagAsLatest(type: Exec) { - dependsOn pushImage + dependsOn tagWithVersion enabled = !project.version.contains("SNAPSHOT") && !project.version.contains("alpha") \ @@ -83,17 +87,22 @@ task tagAsLatest(type: Exec) { && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] - def registry = "${project.rootProject.properties['docker.registry']}" - commandLine 'podman', 'tag', \ - "${registry}/${project.name}:${project.version}",\ + commandLine 'podman', 'push', \ + "${project.name}:${project.gitBranch}",\ "${registry}/${project.name}:latest" } +task publishImage { + dependsOn pushImage + dependsOn tagWithVersion + dependsOn tagAsLatest +} + task pushForTest(type: Exec) { dependsOn buildImage commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}:${project.gitBranch}", \ + "${project.name}:${project.gitBranch}", \ "${project.rootProject.properties['docker.testRegistry']}" \ + "/${project.name}:test" } diff --git a/org.jdrupes.vmoperator.runner.qemu/build.gradle b/org.jdrupes.vmoperator.runner.qemu/build.gradle index 00bf7ea..8cea1ae 100644 --- a/org.jdrupes.vmoperator.runner.qemu/build.gradle +++ b/org.jdrupes.vmoperator.runner.qemu/build.gradle @@ -32,8 +32,9 @@ application { } project.ext.gitBranch = grgit.branch.current.name.replace('/', '-') +def registry = "${project.rootProject.properties['docker.registry']}" -task buildArchImage(type: Exec) { +task buildImageArch(type: Exec) { dependsOn installDist inputs.files 'src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch' @@ -42,23 +43,26 @@ task buildArchImage(type: Exec) { '-f', 'src/org/jdrupes/vmoperator/runner/qemu/Containerfile.arch', '.' } -task pushArchImage(type: Exec) { - dependsOn buildArchImage +task pushImageArch(type: Exec) { + dependsOn buildImageArch - def registry = "${project.rootProject.properties['docker.registry']}" commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}-arch:${project.gitBranch}", \ + "${project.name}-arch:${project.gitBranch}", \ "${registry}/${project.name}-arch:${project.gitBranch}" - - if (!project.version.contains("SNAPSHOT")) { - commandLine 'podman', 'tag', \ - "${registry}/${project.name}-arch:${project.gitBranch}",\ - "${registry}/${project.name}-arch:${project.version}" - } +} + +task tagWithVersionArch(type: Exec) { + dependsOn pushImageArch + + enabled = !project.version.contains("SNAPSHOT") + + commandLine 'podman', 'push', \ + "${project.name}-arch:${project.gitBranch}",\ + "${registry}/${project.name}-arch:${project.version}" } task tagAsLatestArch(type: Exec) { - dependsOn pushArchImage + dependsOn tagWithVersionArch enabled = !project.version.contains("SNAPSHOT") && !project.version.contains("alpha") \ @@ -67,13 +71,12 @@ task tagAsLatestArch(type: Exec) { && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] - def registry = "${project.rootProject.properties['docker.registry']}" - commandLine 'podman', 'tag', \ - "${registry}/${project.name}-arch:${project.version}",\ + commandLine 'podman', 'push', \ + "${project.name}-arch:${project.gitBranch}",\ "${registry}/${project.name}-arch:latest" } -task buildAlpineImage(type: Exec) { +task buildImageAlpine(type: Exec) { dependsOn installDist inputs.files 'src/org/jdrupes/vmoperator/runner/qemu/Containerfile.alpine' @@ -82,23 +85,26 @@ task buildAlpineImage(type: Exec) { '-f', 'src/org/jdrupes/vmoperator/runner/qemu/Containerfile.alpine', '.' } -task pushAlpineImage(type: Exec) { - dependsOn buildAlpineImage +task pushImageAlpine(type: Exec) { + dependsOn buildImageAlpine - def registry = "${project.rootProject.properties['docker.registry']}" commandLine 'podman', 'push', '--tls-verify=false', \ "localhost/${project.name}-alpine:${project.gitBranch}", \ "${registry}/${project.name}-alpine:${project.gitBranch}" - - if (!project.version.contains("SNAPSHOT")) { - commandLine 'podman', 'tag', \ - "${registry}/${project.name}-alpine:${project.gitBranch}",\ - "${registry}/${project.name}-alpine:${project.version}" - } +} + +task tagWithVersionAlpine(type: Exec) { + dependsOn pushImageAlpine + + enabled = !project.version.contains("SNAPSHOT") + + commandLine 'podman', 'push', \ + "${project.name}-alpine:${project.gitBranch}",\ + "${registry}/${project.name}-alpine:${project.version}" } task tagAsLatestAlpine(type: Exec) { - dependsOn pushAlpineImage + dependsOn tagWithVersionAlpine enabled = !project.version.contains("SNAPSHOT") && !project.version.contains("alpha") \ @@ -107,19 +113,16 @@ task tagAsLatestAlpine(type: Exec) { && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] - def registry = "${project.rootProject.properties['docker.registry']}" - commandLine 'podman', 'tag', \ - "${registry}/${project.name}-alpine:${project.version}",\ + commandLine 'podman', 'push', \ + "${project.name}-alpine:${project.gitBranch}",\ "${registry}/${project.name}-alpine:latest" } -task pushImage { - dependsOn pushArchImage - dependsOn pushAlpineImage -} - -task tagAsLatest { +task publishImage { + dependsOn pushImageArch + dependsOn tagWithVersionArch dependsOn tagAsLatestArch + dependsOn pushImageAlpine + dependsOn tagWithVersionAlpine dependsOn tagAsLatestAlpine } - diff --git a/spice-squid/build.gradle b/spice-squid/build.gradle index 2cb7183..e7ccd00 100644 --- a/spice-squid/build.gradle +++ b/spice-squid/build.gradle @@ -5,44 +5,36 @@ plugins { dependencies { } +project.ext.gitBranch = grgit.branch.current.name.replace('/', '-') +def registry = "${project.rootProject.properties['docker.registry']}" + task buildImage(type: Exec) { inputs.files 'Containerfile' commandLine 'podman', 'build', '--pull', - '-t', "${project.name}:${project.version}",\ + '-t', "${project.name}:${project.gitBranch}",\ '-f', 'Containerfile', '.' } -task tagLatestImage(type: Exec) { - dependsOn buildImage - - enabled = !project.version.contains("SNAPSHOT") - && !project.version.contains("alpha") \ - && !project.version.contains("beta") \ - || project.rootProject.properties['docker.testRegistry'] \ - && project.rootProject.properties['docker.registry'] \ - == project.rootProject.properties['docker.testRegistry'] - - commandLine 'podman', 'tag', "${project.name}:${project.version}",\ - "${project.name}:latest" -} - -task buildLatestImage { - dependsOn buildImage - dependsOn tagLatestImage -} - task pushImage(type: Exec) { dependsOn buildImage commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ - + "/${project.name}:${project.version}" + "${project.name}:${project.gitBranch}", \ + "${registry}/${project.name}:${project.gitBranch}" +} +task tagWithVersion(type: Exec) { + dependsOn pushImage + + enabled = !project.version.contains("SNAPSHOT") + + commandLine 'podman', 'push', \ + "${project.name}:${project.gitBranch}",\ + "${registry}/${project.name}:${project.version}" } -task pushLatestImage(type: Exec) { - dependsOn buildLatestImage +task tagAsLatest(type: Exec) { + dependsOn tagWithVersion enabled = !project.version.contains("SNAPSHOT") && !project.version.contains("alpha") \ @@ -51,18 +43,16 @@ task pushLatestImage(type: Exec) { && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] - commandLine 'podman', 'push', '--tls-verify=false', \ - "localhost/${project.name}:${project.version}", \ - "${project.rootProject.properties['docker.registry']}" \ - + "/${project.name}:latest" + commandLine 'podman', 'push', \ + "${project.name}:${project.gitBranch}",\ + "${registry}/${project.name}:latest" } -task pushImages { - // Don't push without testing first +task publishImage { dependsOn pushImage - dependsOn pushLatestImage + dependsOn tagWithVersion + dependsOn tagAsLatest } - test { enabled = project.hasProperty("k8s.testCluster") From 8b83a0cbc8bb5001ea3755f6dc3e5d5ed4886d01 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 23 Jun 2024 17:02:44 +0200 Subject: [PATCH 042/342] Make sure to switch to branch. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 04acdec..84d99d7 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ stages: - "*/build" before_script: - echo -n $CI_REGISTRY_PASSWORD | podman login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY - - git switch $CI_COMMIT_REF_NAME + - git switch $CI_COMMIT_BRANCH - git pull - git reset --hard $CI_COMMIT_SHA From e994fa154333af1d27f951e339d77ce2a6fcf690 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 23 Jun 2024 21:41:00 +0200 Subject: [PATCH 043/342] Another attempt to find the branch. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 84d99d7..9a07e7c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ stages: - "*/build" before_script: - echo -n $CI_REGISTRY_PASSWORD | podman login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY - - git switch $CI_COMMIT_BRANCH + - git switch $(git branch -r --contains $CI_COMMIT_SHA | sed -e 's#[^/]*/##') - git pull - git reset --hard $CI_COMMIT_SHA From 8a434d8410e096d6efeee6b4dc083003224e14a7 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 24 Jun 2024 10:04:09 +0200 Subject: [PATCH 044/342] Use newest branch if we have multiple matches. --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9a07e7c..7dff899 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,7 @@ stages: - "*/build" before_script: - echo -n $CI_REGISTRY_PASSWORD | podman login -u "$CI_REGISTRY_USER" --password-stdin $CI_REGISTRY - - git switch $(git branch -r --contains $CI_COMMIT_SHA | sed -e 's#[^/]*/##') + - git switch $(git branch -r --sort="authordate" --contains $CI_COMMIT_SHA | head -1 | sed -e 's#[^/]*/##') - git pull - git reset --hard $CI_COMMIT_SHA From fc29786afe6d0234e08350597563604fa6fc3316 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 24 Jun 2024 11:18:35 +0200 Subject: [PATCH 045/342] Fix links. --- webpages/vm-operator/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webpages/vm-operator/index.md b/webpages/vm-operator/index.md index 04134d5..232a9ce 100644 --- a/webpages/vm-operator/index.md +++ b/webpages/vm-operator/index.md @@ -11,15 +11,15 @@ based VMs in Kubernetes pods. The image used for the VM pods combines Qemu and a control program for starting and managing the Qemu process. This application is called -"[the runner](runner.md)". +"[the runner](runner.html)". While you can deploy a runner manually (or with the help of some -helm templates), the preferred way is to deploy "[the manager](manager.md)" +helm templates), the preferred way is to deploy "[the manager](manager.html)" application which acts as a Kubernetes operator for runners and thus the VMs. If you just want to try out things, you can skip the remainder of this -page and proceed to "[the manager](manager.md)". +page and proceed to "[the manager](manager.html)". ## Motivation The project was triggered by a remark in the discussion about RedHat From 1fe7960d24cc1397fc8147d1317f3a70cb516247 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 26 Jun 2024 14:14:45 +0200 Subject: [PATCH 046/342] Update. --- webpages/vm-operator/favicon.svg | 196 +++++++++++++++++++++++-------- 1 file changed, 146 insertions(+), 50 deletions(-) diff --git a/webpages/vm-operator/favicon.svg b/webpages/vm-operator/favicon.svg index e216c44..c8616d5 100644 --- a/webpages/vm-operator/favicon.svg +++ b/webpages/vm-operator/favicon.svg @@ -2,23 +2,20 @@ + inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + sodipodi:docname="VM-Operator.svg" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + inkscape:window-y="32" + inkscape:window-maximized="1" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:showpageshadow="2" + inkscape:pagecheckerboard="0" + inkscape:deskcolor="#d1d1d1" /> @@ -51,7 +51,6 @@ image/svg+xml - @@ -59,30 +58,127 @@ inkscape:label="Ebene 1" inkscape:groupmode="layer" id="layer1" - transform="translate(-175.34341,-117.71255)"> - M - L + transform="translate(799.83239,410.74206)"> + + + + + + + + + + + + + + + + + + + + + + + + + +

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 literal 0 HcmV?d00001 diff --git a/webpages/vm-operator/VM-Operator-GUI-view.png b/webpages/vm-operator/VM-Operator-GUI-view.png new file mode 100644 index 0000000000000000000000000000000000000000..0463cc58f2e4739353d8fa5505920254691db7ba GIT binary patch literal 42919 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%0D{rnnqehKW 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 + + + + + + + + + image/svg+xml + + + + + + + + + VM + + + + + + + + + + + + + + + + + diff --git a/webpages/vm-operator/VM-Operator.svg b/webpages/vm-operator/VM-Operator.svg new file mode 100644 index 0000000..c8616d5 --- /dev/null +++ b/webpages/vm-operator/VM-Operator.svg @@ -0,0 +1,184 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/webpages/vm-operator/VmViewer-preview.png b/webpages/vm-operator/VmViewer-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..d13387f723813849a9bbd485f17f3b9d4abbf7d7 GIT binary patch literal 13757 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 + + + + + + + + + image/svg+xml + + + + + + + M + L + + diff --git a/webpages/vm-operator/index.md b/webpages/vm-operator/index.md new file mode 100644 index 0000000..04134d5 --- /dev/null +++ b/webpages/vm-operator/index.md @@ -0,0 +1,60 @@ +--- +title: VM-Operator by mnlipp +description: A Kubernetes operator for running virtual machines (notably Qemu VMs) in pods on Kubernetes +layout: vm-operator +--- + +# Welcome to VM-Operator + +The goal of this project is to provide the means for running Qemu +based VMs in Kubernetes pods. + +The image used for the VM pods combines Qemu and a control program +for starting and managing the Qemu process. This application is called +"[the runner](runner.md)". + +While you can deploy a runner manually (or with the help of some +helm templates), the preferred way is to deploy "[the manager](manager.md)" +application which acts as a Kubernetes operator for runners +and thus the VMs. + +If you just want to try out things, you can skip the remainder of this +page and proceed to "[the manager](manager.md)". + +## Motivation +The project was triggered by a remark in the discussion about RedHat +[dropping SPICE support](https://bugzilla.redhat.com/show_bug.cgi?id=2030592) +from the RHEL packages. Which means that you have to run Qemu in a +container on RHEL and derivatives if you want to continue using Spice. +So KubeVirt comes to mind. But +[one comment](https://bugzilla.redhat.com/show_bug.cgi?id=2030592#c4) +mentioned that the [KubeVirt](https://kubevirt.io/) project isn't +interested in supporting SPICE either. + +Time to have a look at alternatives. Libvirt has become a common +tool to configure and run Qemu. But some of its functionality, notably +the management of storage for the VMs and networking is already provided +by Kubernetes. Therefore this project takes a fresh approach of +running Qemu in a pod using a simple, lightweight manager called "runner". +Providing resources to the VM is left to Kubernetes mechanisms as +much as possible. + +## VMs and Pods + +VMs are not the typical workload managed by Kubernetes. You can neither +have replicas nor can the containers simply be restarted without a major +impact on the "application". So there are many features for managing +pods that we cannot make use of. Qemu in its container can only be +deployed as a pod or using a stateful set with replica 1, which is rather +close to simply deploying the pod (you get the restart and some PVC +management "for free"). + +A second look, however, reveals that Kubernetes has more to offer. +* It has a well defined API for managing resources. +* It provides access to different kinds of managed storage for the VMs. +* Its managing features *are* useful for running the component that +manages the pods with the VMs. + +And if you use Kubernetes anyway, well then the VMs within Kubernetes +provide you with a unified view of all (or most of) your workloads, +which simplifies the maintenance of your platform. diff --git a/webpages/vm-operator/manager.md b/webpages/vm-operator/manager.md new file mode 100644 index 0000000..4613201 --- /dev/null +++ b/webpages/vm-operator/manager.md @@ -0,0 +1,150 @@ +--- +title: VM-Operator Manager +layout: vm-operator +--- + +# The Manager + +The Manager is the program that provides the controller from the +[operator pattern](https://github.com/cncf/tag-app-delivery/blob/eece8f7307f2970f46f100f51932db106db46968/operator-wg/whitepaper/Operator-WhitePaper_v1-0.md#operator-components-in-kubernetes) +together with a Web-GUI. It should be run in a container in the cluster. + +## Installation + +A manager instance manages the VMs in its own namespace. The only +common (and therefore cluster scoped) resource used by all instances +is the CRD. It is available +[here](https://github.com/mnlipp/VM-Operator/raw/main/deploy/crds/vms-crd.yaml) +and must be created first. + +```sh +kubectl apply -f https://github.com/mnlipp/VM-Operator/raw/main/deploy/crds/vms-crd.yaml +``` + +The example above uses the CRD from the main branch. This is okay if +you apply it once. If you want to preserve the link for automatic +upgrades, you should use a link that points to one of the release branches. + +The next step is to create a namespace for the manager and the VMs, e.g. +`vmop-demo`. + +```sh +kubectl create namespace vmop-demo +``` + +Finally you have to create an account, the role, the binding etc. The +default files for creating these resources using the default namespace +can be found in the +[deploy](https://github.com/mnlipp/VM-Operator/tree/main/deploy) +directory. I recommend to use +[kustomize](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/) to create your own configuration. + +## Initial Configuration + +Use one of the `kustomize.yaml` files from the +[example](https://github.com/mnlipp/VM-Operator/tree/main/example) directory +as a starting point. The directory contains two examples. Here's the file +from subdirectory `local-path`: + +```yaml +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: +# Again, I recommend to use the deploy directory from a +# release branch for anything but test environments. +- https://github.com/mnlipp/VM-Operator/deploy + +namespace: vmop-demo + +patches: +- patch: |- + kind: PersistentVolumeClaim + apiVersion: v1 + metadata: + name: vmop-image-repository + spec: + # Default is ReadOnlyMany + accessModes: + - ReadWriteOnce + resources: + requests: + # Default is 100Gi + storage: 10Gi + # Default is to use the default storage class + storageClassName: local-path + +- patch: |- + kind: ConfigMap + apiVersion: v1 + metadata: + name: vm-operator + data: + config.yaml: | + "/Manager": + # "/GuiHttpServer": + # See section about the GUI + "/Controller": + "/Reconciler": + runnerDataPvc: + # Default is to use the default storage class + storageClassName: local-path +``` + +The sample file adds a namespace (`vmop-demo`) to all resource +definitions and patches the PVC `vmop-image-repository`. This is a volume +that is mounted into all pods that run a VM. The volume is intended +to be used as a common repository for CDROM images. The PVC must exist +and it must be bound before any pods can run. + +The second patch affects the small volume that is created for each +runner and contains the VM's configuration data such as the EFI vars. +The manager's default configuration causes the PVC for this volume +to be created with no storage class (which causes the default storage +class to be used). The patch provides a new configuration file for +the manager that makes the reconciler use local-path as storage +class for this PVC. Details about the manager configuration can be +found in the next section. + +Note that you need none of the patches if you are fine with using your +cluster's default storage class and this class supports ReadOnlyMany as +access mode. + +Check that the pod with the manager is running: + +```sh +kubectl -n vmop-demo get pods -l app.kubernetes.io/name=vm-operator +``` + +Proceed to the description of [the controller](controller.html) +for creating your first VM. + +## Configuration Details + +The [config map](https://github.com/mnlipp/VM-Operator/blob/main/deploy/vmop-config-map.yaml) +for the manager may provide a configuration file (`config.yaml`) and +a file with logging properties (`logging.properties`). Both files are mounted +into the container that runs the manager and are evaluated by the manager +on startup. If no files are provided, the manager uses built-in defaults. + +The configuration file for the Manager follows the conventions of +the [JGrapes](https://jgrapes.org/) component framework. +The keys that start with a slash select the component within the +application's component hierarchy. The mapping associated with the +selected component configures this component's properties. + +The available configuration options for the components can be found +in their respective JavaDocs (e.g. +[here](latest-release/javadoc/org/jdrupes/vmoperator/manager/Reconciler.html) +for the Reconciler). + +## Development Configuration + +The [dev-example](https://github.com/mnlipp/VM-Operator/tree/main/dev-example) +directory contains a `kustomize.yaml` that uses the development namespace +`vmop-dev` and creates a deployment for the manager with 0 replicas. + +This environment can be used for running the manager in the IDE. As the +namespace to manage cannot be detected from the environment, you must use + `-c ../dev-example/config.yaml` as argument when starting the manager. This +configures it to use the namespace `vmop-dev`. diff --git a/webpages/vm-operator/runner.md b/webpages/vm-operator/runner.md new file mode 100644 index 0000000..d580530 --- /dev/null +++ b/webpages/vm-operator/runner.md @@ -0,0 +1,108 @@ +--- +title: VM-Operator Runner +layout: vm-operator +--- + +# The Runner + +For most use cases, Qemu needs to be started and controlled by another +program that manages the Qemu process. This program is called the +runner in this context. + +The most prominent reason for this second program is that it allows +a VM to be shutdown cleanly in response to a TERM signal. Qemu handles +the TERM signal by flushing all buffers and stopping, leaving the disks in +a [crash consistent state](https://gitlab.com/qemu-project/qemu/-/issues/148). +For a graceful shutdown, a parent process must handle the TERM signal, send +the `system_powerdown` command to the qemu process and wait for its completion. + +Another reason for having the runner is that another process needs to be started +before qemu if the VM is supposed to include a TPM (software TPM). + +Finally, we want some kind of higher level interface for applying runtime +changes to the VM such as changing the CD or configuring the number of +CPUs and the memory. + +The runner takes care of all these issues. Although it is intended to +run in a container (which runs in a Kubernetes pod) it does not require +a container. You can start and use it as an ordinary program on any +system, provided that you have the required commands (qemu, swtpm) +installed. + +## Stand-alone Configuration + +Upon startup, the runner reads its main configuration file +which defaults to `/etc/opt/vmrunner/config.yaml` and may be changed +using the `-c` (or `--config`) command line option. + +A sample configuration file with annotated options can be found +[here](https://github.com/mnlipp/VM-Operator/blob/main/org.jdrupes.vmoperator.runner.qemu/config-sample.yaml). +As the runner implementation uses the +[JGrapes](https://jgrapes.org/) framework, the file +follows the framework's +[conventions](https://jgrapes.org/latest-release/javadoc/org/jgrapes/util/YamlConfigurationStore.html). The top level "`/Runner`" selects +the component to be configured. Nested within is the information +to be applied to the component. + +The main entries in the configuration file are the "template" and +the "vm" information. The runner processes the +[freemarker template](https://freemarker.apache.org/), using the +"vm" information to derive the qemu command. The idea is that +the "vm" section provides high level information such as the boot +mode, the number of CPUs, the RAM size and the disks. The template +defines a particular VM type, i.e. it contains the "nasty details" +that do not need to be modified for some given set of VM instances. + +The templates provided with the runner can be found +[here](https://github.com/mnlipp/VM-Operator/tree/main/org.jdrupes.vmoperator.runner.qemu/templates). When details +of the VM configuration need modification, a new VM type +(i.e. a new template) has to be defined. Authoring a new +template requires some knowledge about the +[qemu invocation](https://www.qemu.org/docs/master/system/invocation.html). +Despite many "warnings" that you find in the web, configuring the +invocation arguments of qemu is only a bit (but not much) more +challenging than editing libvirt's XML. + +## Running in a Pod + +The real purpose of the runner is to run a VM on Kubernetes in a pod. +When running in a Kubernetes pod, `/etc/opt/vmrunner/config.yaml` should be +provided by a +[ConfigMap](https://kubernetes.io/docs/concepts/configuration/configmap/). + +If additional templates are required, some ReadOnlyMany PV should +be mounted in `/opt/vmrunner/templates`. The PV should contain copies +of the standard templates as well as the additional templates. Of course, +a ConfigMap can be used for this purpose again. + +Networking options are rather limited. The assumption is that in general +the VM wants full network connectivity. To achieve this, the pod must +run with host networking and the host's networking must provide a +bridge that the VM can attach to. The only currently supported +alternative is the less performant +"[user networking](https://wiki.qemu.org/Documentation/Networking#User_Networking_(SLIRP))", +which may be used in a stand-alone development configuration. + +## Runtime changes + +The runner supports adaption to changes of the RAM size (using the +balloon device) and to changes of the number of CPUs. Note that +in order to get new CPUs online on Linux guests, you need a +[udev rule](https://docs.kernel.org/core-api/cpu_hotplug.html#user-space-notification) which is not installed by default[^simplest]. + +The runner also changes the images loaded in CDROM drives. If the +drive is locked, i.e. if it doesn't respond to the "open tray" command +the change will be suspended until the VM opens the tray. + +Finally, `powerdownTimeout` can be changed while the qemu process runs. + +[^simplest]: The simplest form of the rule is probably: + ``` + ACTION=="add", SUBSYSTEM=="cpu", ATTR{online}="1" + ``` + +## Testing with Helm + +There is a +[Helm Chart](https://github.com/mnlipp/VM-Operator/tree/main/org.jdrupes.vmoperator.runner.qemu/helm-test) +for testing the runner. diff --git a/webpages/vm-operator/upgrading.md b/webpages/vm-operator/upgrading.md new file mode 100644 index 0000000..41d04ad --- /dev/null +++ b/webpages/vm-operator/upgrading.md @@ -0,0 +1,29 @@ +--- +title: Upgrading +layout: vm-operator +--- + +# Upgrading + +## To version 3.0.0 + +All configuration files are backward compatible to version 2.3.0. +Note that in order to make use of the new viewer component, +[permissions](https://mnlipp.github.io/VM-Operator/user-gui.html#control-access-to-vms) +must be configured in the CR definition. Also note that +[display secrets](https://mnlipp.github.io/VM-Operator/user-gui.html#securing-access) +are automatically created unless explicitly disabled. + +## To version 2.3.0 + +Starting with version 2.3.0, the web GUI uses a login conlet that +supports OIDC providers. This effects the configuration of the +web GUI components. + +## To version 2.2.0 + +Version 2.2.0 sets the stateful set's `.spec.updateStrategy.type` to +"OnDelete". This fails for no apparent reason if a definition of +the stateful set with the default value "RollingUpdate" already exists. +In order to fix this, either the stateful set or the complete VM definition +must be deleted and the manager must be restarted. diff --git a/webpages/vm-operator/user-gui.md b/webpages/vm-operator/user-gui.md new file mode 100644 index 0000000..394c28f --- /dev/null +++ b/webpages/vm-operator/user-gui.md @@ -0,0 +1,143 @@ +--- +title: VM-Operator Web-GUI for Users +layout: vm-operator +--- + +# User view + +*Since 3.0.0* + +The idea of the user view is to provide an intuitive widget that +allows the users to access their own VMs and to optionally start +and stop them. + +![VM-Viewer](VmViewer-preview.png) + +The configuration options resulting from this seemingly simple +requirement are unexpectedly complex. + +## Control access to VMs + +First of all, we have to define which VMs a user can access. This +is done using the optional property `spec.permissions` of the +VM definition (CRD). + +```yaml +spec: + permissions: + - role: admin + may: + - "*" + - user: test + may: + - start + - stop + - accessConsole +``` + +Permissions can be granted to individual users or to roles. There +is a permission for each possible action. "*" grants them all. + +## Simple usage vs. expert usage + +Next, there are two ways to create the VM widgets (preview conlets +in the framework's terms). They can be created on demand or +automatically for each VM that a logged in user has permission to +access. The former is the preferred way for an administrator who +has access to all VMs and needs to open a particular VM's console +for trouble shooting only. The latter is the preferred way +for a regular user who has access to a limited number of VMs. +In this case, creating the widgets automatically has the additional +benefit that regular users don't need to know how to create and +configure the widgets using the menu and the properties dialog. + +Automatic synchronization of widgets and accessible VMs is controlled +by the property `syncPreviewsFor` of the VM viewer. It's an array with +objects that either specify a role or a user. + +```yaml +"/Manager": + # This configures the GUI + "/GuiHttpServer": + "/ConsoleWeblet": + "/WebConsole": + "/ComponentCollector": + "/VmViewer": + syncPreviewsFor: + - role: user + - user: test + displayResource: + preferredIpVersion: ipv4 +``` + +## Console access + +Access to the VM's console is implemented by generating a +[connection file](https://manpages.debian.org/testing/virt-viewer/remote-viewer.1.en.html#CONNECTION_FILE) for virt-viewer when the user clicks on +the console icon. If automatic open is enabled for this kind of +files in the browser, the console opens without further user action. + +The file contains all required and optional information to start the +remote viewer. + + * The "host" is by default the IP address of the node that the + VM's pod is running on (remember that the runner uses host + networking). + * The "port" is simply taken from the VM definition. + +In more complex scenarios, an administrator may have set up a load +balancer that hides the worker node's IP addresses or the worker +nodes use an internal network and can only be accessed through a +proxy. For both cases, the values to include in the connection file +can be specified as properties of `spec.vm.display.spice` in the +VM definition. + +```yaml +spec: + vm: + display: + spice: + port: 5930 + server: 192.168.19.32 + proxyUrl: http://lgpe-spice.some.host:1234 + generateSecret: true +``` + +The value of `server` is used as value for key "host" in the +connection file, thus overriding the default value. The +value of `proxyUrl` is used as value for key "proxy". + +## Securing access + +As described [previously](./controller.html#display-secretpassword), +access to a VM's display can be secured with a password. If a secret +with a password exists for a VM, the password is +included in the connection file. + +While this approach is very convenient for the user, it is not +secure, because this leaves the password as plain text in a file on +the user's computer (the downloaded connection file). To work around +this, the display secret is updated with a random password with +limited validity, unless the display secret defines a `password-expiry` +in the future or with value "never" or doesn't define a +`password-expiry` at all. + +The automatically generated password is the base64 encoded value +of 16 (strong) random bytes (128 random bits). It is valid for +10 seconds only. This may be challenging on a slower computer +or if users may not enable automatic open for connection files +in the browser. The validity can therefore be adjusted in the +configuration. + +```yaml +"/Manager": + "/Controller": + "/DisplaySecretMonitor": + # Validity of generated password in seconds + passwordValidity: 10 +``` + +Taking into account that the controller generates a display +secret automatically by default, this approach to securing +console access should be sufficient in all cases. (Any feedback +if something has been missed is appreciated.) diff --git a/webpages/vm-operator/webgui.md b/webpages/vm-operator/webgui.md new file mode 100644 index 0000000..38b9faa --- /dev/null +++ b/webpages/vm-operator/webgui.md @@ -0,0 +1,117 @@ +--- +title: VM-Operator Web-GUI +layout: vm-operator +--- + +# The Web-GUI + +The manager component provides a GUI via a web server. The web GUI is +implemented using components from the +[JGrapes WebConsole](https://jgrapes.org/WebConsole.html) +project. Configuration of the GUI therefore follows the conventions +of that framework. + +The structure of the configuration information should be easy to +understand from the examples provided. In general, configuration values +are applied to the individual components that make up an application. +The hierarchy of the components is reflected in the configuration +information because components are "addressed" by their position in +that hierarchy. (See +[the package description](latest-release/javadoc/org/jdrupes/vmoperator/manager/package-summary.html) +for information about the complete component structure.) + +## Network access + +By default, the service is made available at port 8080 of the manager +pod. Of course, a kubernetes service and an ingress configuration must +be added as required by the environment. (See the +[definition](https://github.com/mnlipp/VM-Operator/blob/main/deploy/vmop-service.yaml) +from the +[sample deployment](https://github.com/mnlipp/VM-Operator/tree/main/deploy)). + +## User Access + +Access to the web GUI is controlled by the login conlet. The framework +does not include sophisticated components for user management. Rather, +it assumes that an OIDC provider is responsible for user authentication +and role management. + +```yaml +"/Manager": + # "/GuiSocketServer": + # port: 8080 + "/GuiHttpServer": + # This configures the GUI + "/ConsoleWeblet": + "/WebConsole": + "/LoginConlet": + # Starting with version 2.3.0 the preferred approach is to + # configure an OIDC provider for user management and + # authorization. See the text for details. + oidcProviders: {} + + # Support for "local" users is provided as a fallback mechanism. + # Note that up to Version 2.2.x "users" was an object with user names + # as its properties. Starting with 2.3.0 it is a list as shown. + users: + - name: admin + fullName: Administrator + password: "Generate hash with bcrypt" + - name: test + fullName: Test Account + password: "Generate hash with bcrypt" + + # Required for using OIDC, see the text for details. + "/OidcClient": + redirectUri: https://my.server.here/oauth/callback" + + # May be used for assigning roles to both local users and users from + # the OIDC provider. Not needed if roles are managed by the OIDC provider. + "/RoleConfigurator": + rolesByUser: + # User admin has role admin + admin: + - admin + # Non-privileged users are users + test: + - user + # All users have role other + "*": + - other + replace: false + + # Manages the permissions for the roles. + "/RoleConletFilter": + conletTypesByRole: + # Admins can use all conlets + admin: + - "*" + # Users can use the viewer conlet + user: + - org.jdrupes.vmoperator.vmviewer.VmViewer + # Others cannot use any conlet (except login conlet to log out) + other: + # Up to version 2.2.x + # - org.jgrapes.webconlet.locallogin.LoginConlet + # Starting with version 2.3.0 + - org.jgrapes.webconlet.oidclogin.LoginConlet +``` + +How local users can be configured should be obvious from the example. +The configuration of OIDC providers for user authentication (and +optionally for role assignment) is explained in the documentation of the +[login conlet](https://jgrapes.org/javadoc-webconsole/org/jgrapes/webconlet/oidclogin/LoginConlet.html). +Details about the `RoleConfigurator` and `RoleConletFilter` can also be found +in the documentation of the +[JGrapes WebConsole](https://jgrapes.org/WebConsole.html) +project. + +The configuration above allows all users with role "admin" to use all +GUI components and users with role "user" to only use the viewer conlet, +i.e. the [User view](user-gui.html). The fallback role "other" allows +all users to use the login conlet to log out. + +## Views + +The configuration of the components that provide the manager and +users views is explained in the respective sections. From 6a2d71164319de722c2ced7d7218dcf7406d95af Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 20 Jun 2024 22:42:26 +0200 Subject: [PATCH 031/342] New publishing style. --- .github/workflows/gradle.yml | 2 +- ....jdrupes.vmoperator.java-doc-conventions.gradle | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index afb5aab..f47366a 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -28,4 +28,4 @@ jobs: java-version: '21' distribution: 'temurin' - name: Build with Gradle - run: ./gradlew -Prepo.access.token=${{ secrets.REPO_ACCESS_TOKEN }} stage + run: ./gradlew -Pwebsite.push.token=${{ secrets.WEBSITE_PUSH_TOKEN }} stage diff --git a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle index 8e8413e..5eed550 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle @@ -116,20 +116,24 @@ task testJavadoc(type: Javadoc) { // Prepare github authentication for plugins if (System.properties['org.ajoberstar.grgit.auth.username'] == null) { System.setProperty('org.ajoberstar.grgit.auth.username', - project.rootProject.properties['repo.access.token'] ?: "nouser") + project.rootProject.properties['website.push.token'] ?: "nouser") } gitPublish { - repoUri = 'https://github.com/mnlipp/VM-Operator.git' - branch = 'gh-pages' + repoUri = 'https://github.com/mnlipp/jdrupes.org.git' + branch = 'main' contents { + from("${rootProject.projectDir}/webpages") { + include '_layouts/vm-operator.html' + include 'vm-operator/**' + } from("${rootProject.buildDir}/javadoc") { - into 'javadoc' + into 'vm-operator/javadoc' } if (!findProject(':org.jdrupes.vmoperator.runner.qemu').isSnapshot && !findProject(':org.jdrupes.vmoperator.manager').isSnapshot) { from("${rootProject.buildDir}/javadoc") { - into 'latest-release/javadoc' + into 'vm-operator/latest-release/javadoc' } } } From 9d5f3cf702aaca143425f068ecd42400266b94bd Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 20 Jun 2024 23:11:01 +0200 Subject: [PATCH 032/342] Update link. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 176437a..52a2fa8 100644 --- a/README.md +++ b/README.md @@ -8,5 +8,5 @@ The goal of this project is to provide the means for running Qemu based VMs in Kubernetes pods. -See the [project's home page](https://mnlipp.github.io/VM-Operator/) +See the [project's home page](https://jdrupes.org/vm-operator/) for details. From 128ffbc2ad3fab16e5702f0d86a4a95725baeaa6 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Jun 2024 11:52:32 +0200 Subject: [PATCH 033/342] Update. --- misc/javadoc.bottom.txt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/misc/javadoc.bottom.txt b/misc/javadoc.bottom.txt index bf7dd56..a630b6f 100644 --- a/misc/javadoc.bottom.txt +++ b/misc/javadoc.bottom.txt @@ -9,15 +9,14 @@ var _paq = _paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDocumentTitle", document.domain + "/" + document.title]); - _paq.push(["setCookieDomain", "*.mnlipp.github.io"]); - _paq.push(["setDomains", ["*.mnlipp.github.io"]]); + _paq.push(["setCookieDomain", "*.jdrupes.org"]); _paq.push(['disableCookies']); _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { - var u="//piwik.mnl.de/"; + var u="//jdrupes.org/"; _paq.push(['setTrackerUrl', u+'piwik.php']); - _paq.push(['setSiteId', '14']); + _paq.push(['setSiteId', '15']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); })(); From 7dea95660cadaa45ca3850a42daf69649ced947c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Jun 2024 14:32:11 +0200 Subject: [PATCH 034/342] Update. --- misc/javadoc.bottom.txt | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/misc/javadoc.bottom.txt b/misc/javadoc.bottom.txt index a630b6f..42d0ccd 100644 --- a/misc/javadoc.bottom.txt +++ b/misc/javadoc.bottom.txt @@ -4,25 +4,30 @@ TermsPrivacy

From 6852c575ae4a08f42da68f99f550f6726da73900 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 26 Jun 2024 21:43:28 +0200 Subject: [PATCH 047/342] Fix hover. --- .../org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss | 1 + 1 file changed, 1 insertion(+) 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 6d0654f..3ee432a 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 @@ -72,6 +72,7 @@ position: absolute; animation: spin 2s linear infinite; z-index: 100; + pointer-events: none; } } From b74de67c6d6f61daa60d30cc4b4853288228bc10 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 27 Jun 2024 14:56:06 +0200 Subject: [PATCH 048/342] Update icon. --- webpages/vm-operator/VM-Operator.svg | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/webpages/vm-operator/VM-Operator.svg b/webpages/vm-operator/VM-Operator.svg index c8616d5..30c1ed2 100644 --- a/webpages/vm-operator/VM-Operator.svg +++ b/webpages/vm-operator/VM-Operator.svg @@ -7,7 +7,7 @@ viewBox="0 0 331.50461 323.22329" id="svg2" version="1.1" - inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" + inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)" sodipodi:docname="VM-Operator.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" @@ -25,9 +25,9 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.7" - inkscape:cx="245" - inkscape:cy="145.71429" + inkscape:zoom="1.4" + inkscape:cx="190.35714" + inkscape:cy="178.57143" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" @@ -171,12 +171,12 @@ cy="-109.05605" r="9.2055216" /> + transform="matrix(0.32800241,0,0,0.32572486,-723.34527,-233.01684)"> From e3da87d94fd5415f2c83f5ae0f3e334da6689487 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 27 Jun 2024 16:50:49 +0200 Subject: [PATCH 049/342] Version tag may only be applied when all projects are "clean". --- build.gradle | 3 ++- org.jdrupes.vmoperator.manager/build.gradle | 9 +++++---- org.jdrupes.vmoperator.runner.qemu/build.gradle | 17 +++++++++-------- spice-squid/build.gradle | 9 +++++---- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/build.gradle b/build.gradle index d0ebc71..df173d8 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,8 @@ buildscript { plugins { id 'org.ajoberstar.grgit' version '5.2.0' apply false id 'org.ajoberstar.git-publish' version '4.2.0' apply false - id 'pl.allegro.tech.build.axion-release' version '1.15.0' apply false + id 'pl.allegro.tech.build.axion-release' version '1.17.2' apply false + id 'org.jdrupes.vmoperator.versioning-conventions' id 'org.jdrupes.vmoperator.java-doc-conventions' id 'eclipse' id "com.github.node-gradle.node" version "7.0.1" diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index 45d9494..202c6f8 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -47,6 +47,7 @@ application { project.ext.gitBranch = grgit.branch.current.name.replace('/', '-') def registry = "${project.rootProject.properties['docker.registry']}" +def rootVersion = rootProject.version task buildImage(type: Exec) { dependsOn installDist @@ -70,7 +71,7 @@ task pushImage(type: Exec) { task tagWithVersion(type: Exec) { dependsOn pushImage - enabled = !project.version.contains("SNAPSHOT") + enabled = !rootVersion.contains("SNAPSHOT") commandLine 'podman', 'push', \ "${project.name}:${project.gitBranch}",\ @@ -80,9 +81,9 @@ task tagWithVersion(type: Exec) { task tagAsLatest(type: Exec) { dependsOn tagWithVersion - enabled = !project.version.contains("SNAPSHOT") - && !project.version.contains("alpha") \ - && !project.version.contains("beta") \ + enabled = !rootVersion.contains("SNAPSHOT") + && !rootVersion.contains("alpha") \ + && !rootVersion.contains("beta") \ || project.rootProject.properties['docker.testRegistry'] \ && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] diff --git a/org.jdrupes.vmoperator.runner.qemu/build.gradle b/org.jdrupes.vmoperator.runner.qemu/build.gradle index 8cea1ae..b2cd8d4 100644 --- a/org.jdrupes.vmoperator.runner.qemu/build.gradle +++ b/org.jdrupes.vmoperator.runner.qemu/build.gradle @@ -33,6 +33,7 @@ application { project.ext.gitBranch = grgit.branch.current.name.replace('/', '-') def registry = "${project.rootProject.properties['docker.registry']}" +def rootVersion = rootProject.version task buildImageArch(type: Exec) { dependsOn installDist @@ -54,7 +55,7 @@ task pushImageArch(type: Exec) { task tagWithVersionArch(type: Exec) { dependsOn pushImageArch - enabled = !project.version.contains("SNAPSHOT") + enabled = !rootVersion.contains("SNAPSHOT") commandLine 'podman', 'push', \ "${project.name}-arch:${project.gitBranch}",\ @@ -64,9 +65,9 @@ task tagWithVersionArch(type: Exec) { task tagAsLatestArch(type: Exec) { dependsOn tagWithVersionArch - enabled = !project.version.contains("SNAPSHOT") - && !project.version.contains("alpha") \ - && !project.version.contains("beta") \ + enabled = !rootVersion.contains("SNAPSHOT") + && !rootVersion.contains("alpha") \ + && !rootVersion.contains("beta") \ || project.rootProject.properties['docker.testRegistry'] \ && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] @@ -96,7 +97,7 @@ task pushImageAlpine(type: Exec) { task tagWithVersionAlpine(type: Exec) { dependsOn pushImageAlpine - enabled = !project.version.contains("SNAPSHOT") + enabled = !rootVersion.contains("SNAPSHOT") commandLine 'podman', 'push', \ "${project.name}-alpine:${project.gitBranch}",\ @@ -106,9 +107,9 @@ task tagWithVersionAlpine(type: Exec) { task tagAsLatestAlpine(type: Exec) { dependsOn tagWithVersionAlpine - enabled = !project.version.contains("SNAPSHOT") - && !project.version.contains("alpha") \ - && !project.version.contains("beta") \ + enabled = !rootVersion.contains("SNAPSHOT") + && !rootVersion.contains("alpha") \ + && !rootVersion.contains("beta") \ || project.rootProject.properties['docker.testRegistry'] \ && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] diff --git a/spice-squid/build.gradle b/spice-squid/build.gradle index e7ccd00..5278098 100644 --- a/spice-squid/build.gradle +++ b/spice-squid/build.gradle @@ -7,6 +7,7 @@ dependencies { project.ext.gitBranch = grgit.branch.current.name.replace('/', '-') def registry = "${project.rootProject.properties['docker.registry']}" +def rootVersion = rootProject.version task buildImage(type: Exec) { inputs.files 'Containerfile' @@ -26,7 +27,7 @@ task pushImage(type: Exec) { task tagWithVersion(type: Exec) { dependsOn pushImage - enabled = !project.version.contains("SNAPSHOT") + enabled = !rootVersion.contains("SNAPSHOT") commandLine 'podman', 'push', \ "${project.name}:${project.gitBranch}",\ @@ -36,9 +37,9 @@ task tagWithVersion(type: Exec) { task tagAsLatest(type: Exec) { dependsOn tagWithVersion - enabled = !project.version.contains("SNAPSHOT") - && !project.version.contains("alpha") \ - && !project.version.contains("beta") \ + enabled = !rootVersion.contains("SNAPSHOT") + && !rootVersion.contains("alpha") \ + && !rootVersion.contains("beta") \ || project.rootProject.properties['docker.testRegistry'] \ && project.rootProject.properties['docker.registry'] \ == project.rootProject.properties['docker.testRegistry'] From 63e77c0a8afaf5e00702e35eabf5b77767485199 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 30 Jun 2024 15:09:20 +0200 Subject: [PATCH 050/342] Fix HTML error. --- webpages/_layouts/vm-operator.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index dfe4220..282dde0 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -44,7 +44,7 @@

Upgrading

Javadoc

From 88026669442533898c439422e1e5c5efab190c1e Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 2 Jul 2024 13:39:20 +0200 Subject: [PATCH 051/342] Fix link. --- webpages/_layouts/vm-operator.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 282dde0..d4b4f0c 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -18,7 +18,7 @@
-

VM-Operator

+

VM-Operator

By Michael N. Lipp

Mastodon Follow

From 9a5e1800ffff1bee8e84636b7b89558b5cd4e407 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 4 Jul 2024 09:38:02 +0200 Subject: [PATCH 052/342] Remove duplicate h1. --- webpages/_layouts/vm-operator.html | 4 ++-- webpages/stylesheets/styles.css | 12 ++++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index d4b4f0c..b6172f3 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -18,8 +18,8 @@
diff --git a/webpages/stylesheets/styles.css b/webpages/stylesheets/styles.css index 748ffcb..8d6b803 100644 --- a/webpages/stylesheets/styles.css +++ b/webpages/stylesheets/styles.css @@ -5,7 +5,7 @@ body { color:#595959; } -h1, h2, h3, h4, h5, h6 { +h1, h2, h3, h4, h5, h6, .index-title, .index-subtitle { color:#222; margin:0 0 20px; } @@ -14,11 +14,11 @@ p, ul, ol, table, pre, dl { margin:0 0 20px; } -h1, h2, h3 { +h1, h2, h3, .index-title, .index-subtitle { line-height:1.1; } -h1 { +h1, .index-title { font-size:28px; font-weight: 500; } @@ -28,11 +28,15 @@ h2 { font-weight: 500; } -h3, h4, h5, h6 { +h3, h4, h5, h6, .index-subtitle { color:#494949; font-weight: 500; } +.index-subtitle { + font-size: 1.17em; +} + a { color:#39c; text-decoration:none; From 299bded9de8974a79aeb25125f2d0394bb4523e2 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 6 Jul 2024 10:35:26 +0200 Subject: [PATCH 053/342] Add backlink. --- overview.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/overview.md b/overview.md index 0677d51..447a33c 100644 --- a/overview.md +++ b/overview.md @@ -3,5 +3,8 @@ A Kubernetes operator for running VMs as pods. VM-Operator =========== -The VM-operator is built on the [JGrapes](https://mnlipp.github.io/jgrapes/) -event driven framework. +The VM-operator enables you to easily run Qemu based VMs as pods +in Kubernetes. It is built on the +[JGrapes](https://mnlipp.github.io/jgrapes/) event driven framework. + +See the project's [home page](https://jdrupes.org/vm-operator/) for details. From f45c5698d1d0b89217b5e90c1b02fc9e4a87c3cc Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 9 Jul 2024 11:21:14 +0200 Subject: [PATCH 054/342] Update. --- README.md | 4 +- webpages/vm-operator/index-pic.svg | 7329 ++++++++++++++++++++++++++++ webpages/vm-operator/index.md | 6 +- 3 files changed, 7335 insertions(+), 4 deletions(-) create mode 100644 webpages/vm-operator/index-pic.svg diff --git a/README.md b/README.md index 52a2fa8..9118f9d 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ # Run Qemu in Kubernetes Pods -The goal of this project is to provide the means for running Qemu -based VMs in Kubernetes pods. +The goal of this project is to provide easy to use and flexible components +for running Qemu based VMs in Kubernetes pods. See the [project's home page](https://jdrupes.org/vm-operator/) for details. diff --git a/webpages/vm-operator/index-pic.svg b/webpages/vm-operator/index-pic.svg new file mode 100644 index 0000000..e912900 --- /dev/null +++ b/webpages/vm-operator/index-pic.svg @@ -0,0 +1,7329 @@ + + + + diff --git a/webpages/vm-operator/index.md b/webpages/vm-operator/index.md index 232a9ce..b5e18ca 100644 --- a/webpages/vm-operator/index.md +++ b/webpages/vm-operator/index.md @@ -6,8 +6,10 @@ layout: vm-operator # Welcome to VM-Operator -The goal of this project is to provide the means for running Qemu -based VMs in Kubernetes pods. +![Overview picture](index-pic.svg) + +The goal of this project is to provide easy to use and flexible components +for running Qemu based VMs in Kubernetes pods. The image used for the VM pods combines Qemu and a control program for starting and managing the Qemu process. This application is called From 8f8a38771ec9d1cac0b1a0d3013f6a8b71430f60 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 9 Jul 2024 17:09:52 +0200 Subject: [PATCH 055/342] Use longer titles. --- webpages/vm-operator/admin-gui.md | 2 +- webpages/vm-operator/manager.md | 2 +- webpages/vm-operator/runner.md | 2 +- webpages/vm-operator/user-gui.md | 2 +- webpages/vm-operator/webgui.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/webpages/vm-operator/admin-gui.md b/webpages/vm-operator/admin-gui.md index 15a6dec..f7ce987 100644 --- a/webpages/vm-operator/admin-gui.md +++ b/webpages/vm-operator/admin-gui.md @@ -1,5 +1,5 @@ --- -title: VM-Operator Web-GUI for Admins +title: VM-Operator: Administrator View — Provides an overview of running VMs layout: vm-operator --- diff --git a/webpages/vm-operator/manager.md b/webpages/vm-operator/manager.md index 4613201..7f3f8e3 100644 --- a/webpages/vm-operator/manager.md +++ b/webpages/vm-operator/manager.md @@ -1,5 +1,5 @@ --- -title: VM-Operator Manager +title: VM-Operator: The Manager — Reconciles CRDs and provides a Web-GUI layout: vm-operator --- diff --git a/webpages/vm-operator/runner.md b/webpages/vm-operator/runner.md index d580530..260007b 100644 --- a/webpages/vm-operator/runner.md +++ b/webpages/vm-operator/runner.md @@ -1,5 +1,5 @@ --- -title: VM-Operator Runner +title: VM-Operator: The Runner — Starts and monitors a VM layout: vm-operator --- diff --git a/webpages/vm-operator/user-gui.md b/webpages/vm-operator/user-gui.md index 394c28f..a084e3b 100644 --- a/webpages/vm-operator/user-gui.md +++ b/webpages/vm-operator/user-gui.md @@ -1,5 +1,5 @@ --- -title: VM-Operator Web-GUI for Users +title: VM-Operator: User View — Allows users to manage their own VMs layout: vm-operator --- diff --git a/webpages/vm-operator/webgui.md b/webpages/vm-operator/webgui.md index 38b9faa..9621101 100644 --- a/webpages/vm-operator/webgui.md +++ b/webpages/vm-operator/webgui.md @@ -1,5 +1,5 @@ --- -title: VM-Operator Web-GUI +title: VM-Operator: Web-GUI — Provides easy access to VM management layout: vm-operator --- From fcf0c1d1af45889c66f10c54639969a90a613c1e Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 9 Jul 2024 17:19:15 +0200 Subject: [PATCH 056/342] Fix syntax. --- webpages/vm-operator/admin-gui.md | 2 +- webpages/vm-operator/controller.md | 2 +- webpages/vm-operator/manager.md | 2 +- webpages/vm-operator/runner.md | 2 +- webpages/vm-operator/user-gui.md | 2 +- webpages/vm-operator/webgui.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/webpages/vm-operator/admin-gui.md b/webpages/vm-operator/admin-gui.md index f7ce987..4bfa3d3 100644 --- a/webpages/vm-operator/admin-gui.md +++ b/webpages/vm-operator/admin-gui.md @@ -1,5 +1,5 @@ --- -title: VM-Operator: Administrator View — Provides an overview of running VMs +title: "VM-Operator: Administrator View — Provides an overview of running VMs" layout: vm-operator --- diff --git a/webpages/vm-operator/controller.md b/webpages/vm-operator/controller.md index 2a00b16..ce94228 100644 --- a/webpages/vm-operator/controller.md +++ b/webpages/vm-operator/controller.md @@ -1,5 +1,5 @@ --- -title: VM-Operator Controller +title: "VM-Operator Controller — Reconciles the VM CRs" layout: vm-operator --- diff --git a/webpages/vm-operator/manager.md b/webpages/vm-operator/manager.md index 7f3f8e3..a4ed202 100644 --- a/webpages/vm-operator/manager.md +++ b/webpages/vm-operator/manager.md @@ -1,5 +1,5 @@ --- -title: VM-Operator: The Manager — Reconciles CRDs and provides a Web-GUI +title: "VM-Operator: The Manager — Reconciles CRDs and provides a Web-GUI" layout: vm-operator --- diff --git a/webpages/vm-operator/runner.md b/webpages/vm-operator/runner.md index 260007b..319a5dc 100644 --- a/webpages/vm-operator/runner.md +++ b/webpages/vm-operator/runner.md @@ -1,5 +1,5 @@ --- -title: VM-Operator: The Runner — Starts and monitors a VM +title: "VM-Operator: The Runner — Starts and monitors a VM" layout: vm-operator --- diff --git a/webpages/vm-operator/user-gui.md b/webpages/vm-operator/user-gui.md index a084e3b..03e7bdf 100644 --- a/webpages/vm-operator/user-gui.md +++ b/webpages/vm-operator/user-gui.md @@ -1,5 +1,5 @@ --- -title: VM-Operator: User View — Allows users to manage their own VMs +title: "VM-Operator: User View — Allows users to manage their own VMs" layout: vm-operator --- diff --git a/webpages/vm-operator/webgui.md b/webpages/vm-operator/webgui.md index 9621101..f354770 100644 --- a/webpages/vm-operator/webgui.md +++ b/webpages/vm-operator/webgui.md @@ -1,5 +1,5 @@ --- -title: VM-Operator: Web-GUI — Provides easy access to VM management +title: "VM-Operator: Web-GUI — Provides easy access to VM management" layout: vm-operator --- From e3fc4747e490a375d0c22990f36251ea3f61dcb2 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 9 Jul 2024 17:31:58 +0200 Subject: [PATCH 057/342] Minor edits. --- webpages/vm-operator/controller.md | 2 +- webpages/vm-operator/manager.md | 2 +- webpages/vm-operator/upgrading.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/webpages/vm-operator/controller.md b/webpages/vm-operator/controller.md index ce94228..a24943d 100644 --- a/webpages/vm-operator/controller.md +++ b/webpages/vm-operator/controller.md @@ -1,5 +1,5 @@ --- -title: "VM-Operator Controller — Reconciles the VM CRs" +title: "VM-Operator: Controller — Reconciles the VM CRs" layout: vm-operator --- diff --git a/webpages/vm-operator/manager.md b/webpages/vm-operator/manager.md index a4ed202..e4e5442 100644 --- a/webpages/vm-operator/manager.md +++ b/webpages/vm-operator/manager.md @@ -1,5 +1,5 @@ --- -title: "VM-Operator: The Manager — Reconciles CRDs and provides a Web-GUI" +title: "VM-Operator: The Manager — Provides the controller and a Web-GUI" layout: vm-operator --- diff --git a/webpages/vm-operator/upgrading.md b/webpages/vm-operator/upgrading.md index 41d04ad..7b69716 100644 --- a/webpages/vm-operator/upgrading.md +++ b/webpages/vm-operator/upgrading.md @@ -1,5 +1,5 @@ --- -title: Upgrading +title: "VM-Operator: Upgrading — Issues to watch out for" layout: vm-operator --- From 33856fffc28b6c19f58a6522d84520be9df328ce Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 11 Jul 2024 12:52:28 +0200 Subject: [PATCH 058/342] Fix link. --- webpages/_layouts/vm-operator.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index b6172f3..9e9cbb4 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -18,7 +18,7 @@
- +

Mastodon Follow

From e7cdaea205e900dbfebc7616ac2849a8f02e5183 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 11 Jul 2024 12:54:12 +0200 Subject: [PATCH 059/342] Minor edit. --- webpages/vm-operator/user-gui.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/vm-operator/user-gui.md b/webpages/vm-operator/user-gui.md index 03e7bdf..ce46e8f 100644 --- a/webpages/vm-operator/user-gui.md +++ b/webpages/vm-operator/user-gui.md @@ -99,7 +99,7 @@ spec: spice: port: 5930 server: 192.168.19.32 - proxyUrl: http://lgpe-spice.some.host:1234 + proxyUrl: http://vms-spice.some.host:1234 generateSecret: true ``` From 1b2d7ec330e60282c5d7b7b4ea4458ed98413b62 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 11 Jul 2024 13:21:46 +0200 Subject: [PATCH 060/342] Fix link. --- webpages/_layouts/vm-operator.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 9e9cbb4..7ea1bc5 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -18,8 +18,8 @@
From a62b8c2899ac04d2960957902478c23188c77191 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" <1446020+mnlipp@users.noreply.github.com> Date: Mon, 15 Jul 2024 08:46:23 +0200 Subject: [PATCH 061/342] Update index.md --- webpages/vm-operator/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webpages/vm-operator/index.md b/webpages/vm-operator/index.md index b5e18ca..32d2cd5 100644 --- a/webpages/vm-operator/index.md +++ b/webpages/vm-operator/index.md @@ -1,6 +1,6 @@ --- -title: VM-Operator by mnlipp -description: A Kubernetes operator for running virtual machines (notably Qemu VMs) in pods on Kubernetes +title: Run Qemu based VMs on Kubernetes +description: A Kubernetes operator for running virtual machines (notably Qemu VMs) in pods on Kubernetes with a web interface for admins and users. layout: vm-operator --- From 959a35ca9e729a1778376eeca8b26beeabd7d6af Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" <1446020+mnlipp@users.noreply.github.com> Date: Wed, 17 Jul 2024 07:52:03 +0200 Subject: [PATCH 062/342] Update manager.md --- webpages/vm-operator/manager.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/webpages/vm-operator/manager.md b/webpages/vm-operator/manager.md index e4e5442..8e6ebb4 100644 --- a/webpages/vm-operator/manager.md +++ b/webpages/vm-operator/manager.md @@ -1,5 +1,5 @@ --- -title: "VM-Operator: The Manager — Provides the controller and a Web-GUI" +title: "VM-Operator: The Manager — Provides the controller and a web user interface" layout: vm-operator --- @@ -7,7 +7,7 @@ layout: vm-operator The Manager is the program that provides the controller from the [operator pattern](https://github.com/cncf/tag-app-delivery/blob/eece8f7307f2970f46f100f51932db106db46968/operator-wg/whitepaper/Operator-WhitePaper_v1-0.md#operator-components-in-kubernetes) -together with a Web-GUI. It should be run in a container in the cluster. +together with a web user interface. It should be run in a container in the cluster. ## Installation From 45e271e6d0b482ab5a994b2eadcc6f1a1c35d86b Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" <1446020+mnlipp@users.noreply.github.com> Date: Wed, 17 Jul 2024 07:55:16 +0200 Subject: [PATCH 063/342] Update webgui.md --- webpages/vm-operator/webgui.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/webpages/vm-operator/webgui.md b/webpages/vm-operator/webgui.md index f354770..ef24245 100644 --- a/webpages/vm-operator/webgui.md +++ b/webpages/vm-operator/webgui.md @@ -1,11 +1,11 @@ --- -title: "VM-Operator: Web-GUI — Provides easy access to VM management" +title: "VM-Operator: Web user interface — Provides easy access to VM management" layout: vm-operator --- # The Web-GUI -The manager component provides a GUI via a web server. The web GUI is +The manager component provides a GUI via a web server. This web user interface is implemented using components from the [JGrapes WebConsole](https://jgrapes.org/WebConsole.html) project. Configuration of the GUI therefore follows the conventions @@ -31,7 +31,7 @@ from the ## User Access -Access to the web GUI is controlled by the login conlet. The framework +Access to the web user interface is controlled by the login conlet. The framework does not include sophisticated components for user management. Rather, it assumes that an OIDC provider is responsible for user authentication and role management. From 4c04bb0e0ace6a6a4e8cab7803c34261344c1d1a Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 17 Jul 2024 22:26:29 +0200 Subject: [PATCH 064/342] Minor edit. --- webpages/_layouts/vm-operator.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 7ea1bc5..30e6407 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -40,7 +40,7 @@ -

The Web-GUI

+

Web interface

+
+ +

+ +

View GitHub Project

+ +

+ +

Overview

+

The Runner

+

The Manager

+ +

The Web-GUI

+
+
+ + {% if page.tocTitle %} +

{{ page.tocTitle }}

+ {% include toc.html html=content %} + {% endif %} + + {{ content }} +
+ +
+ + + + + + - - +

${_("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 c06cc1a..fe48d3b 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 @@ -20,6 +20,7 @@ package org.jdrupes.vmoperator.vmviewer; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.google.gson.JsonObject; @@ -54,6 +55,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; @@ -90,10 +92,10 @@ 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" }) + "PMD.CouplingBetweenObjects", "PMD.GodClass", "PMD.TooManyMethods" }) public class VmViewer extends FreeMarkerConlet { private static final String VM_NAME_PROPERTY = "vmName"; @@ -465,12 +467,19 @@ public class VmViewer extends FreeMarkerConlet { @Override @SuppressWarnings({ "PMD.AvoidDecimalLiteralsInBigDecimalConstructor", - "PMD.ConfusingArgumentToVarargsMethod" }) + "PMD.ConfusingArgumentToVarargsMethod", "PMD.NcssCount", + "PMD.AvoidLiteralsInIfCondition" }) protected void doUpdateConletState(NotifyConletModel event, ConsoleConnection channel, ViewerModel model) throws Exception { event.stop(); - var both = Optional.ofNullable(event.params().asString(0)) + if ("selectedVm".equals(event.method())) { + selectVm(event, channel, model); + return; + } + + // Handle command for selected VM + var both = Optional.ofNullable(model.vmName()) .flatMap(vm -> channelManager.both(vm)); if (both.isEmpty()) { return; @@ -479,14 +488,8 @@ 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)); - String jsonState = objectMapper.writeValueAsString(model); - channel.respond(new KeyValueStoreUpdate().update(storagePath( - channel.session(), model.getConletId()), jsonState)); - updateConfig(channel, model); - break; case "start": if (perms.contains(Permission.START)) { fire(new ModifyVm(vmName, "state", "Running", vmChannel)); @@ -497,6 +500,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), @@ -510,6 +523,15 @@ public class VmViewer extends FreeMarkerConlet { } } + private void selectVm(NotifyConletModel event, ConsoleConnection channel, + ViewerModel model) throws JsonProcessingException { + model.setVmName(event.params().asString(0)); + String jsonState = objectMapper.writeValueAsString(model); + channel.respond(new KeyValueStoreUpdate().update(storagePath( + channel.session(), model.getConletId()), jsonState)); + updateConfig(channel, model); + } + private void openConsole(String vmName, ConsoleConnection connection, ViewerModel model, String password) { var vmDef = channelManager.associated(vmName).orElse(null); @@ -577,6 +599,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 ca3b246..a14e83c 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 } } } @@ -63,7 +64,16 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, vmName: "", vmDefinition: {} }); - const vmDef = computed(() => previewApi.vmDefinition); + const configured = computed(() => previewApi.vmDefinition.spec); + const startable = computed(() => previewApi.vmDefinition.spec && + previewApi.vmDefinition.spec.vm.state !== 'Running' + && !previewApi.vmDefinition.running); + const stoppable = computed(() => previewApi.vmDefinition.spec && + previewApi.vmDefinition.spec.vm.state !== 'Stopped' + && previewApi.vmDefinition.running); + const running = computed(() => previewApi.vmDefinition.running); + const permissions = computed(() => previewApi.vmDefinition.spec + ? previewApi.vmDefinition.userPermissions : []); watch(() => previewApi.vmName, (name: string) => { if (name !== "") { @@ -73,41 +83,51 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, provideApi(previewDom, previewApi); - const vmAction = (vmName: string, action: string) => { - JGConsole.notifyConletModel(conletId, action, vmName); + const vmAction = (action: string) => { + JGConsole.notifyConletModel(conletId, action); }; - return { localize, resourceBase, vmDef, vmAction }; + return { localize, resourceBase, vmAction, configured, + startable, stoppable, running, permissions }; }, template: ` - - + - + + +
- + - - + - - + v-on:click="vmAction('stop')"> + + + + + +
` }); @@ -209,3 +229,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 83e92a5..6d0654f 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,9 +57,42 @@ opacity: 0.4; } } + + .jdrupes-vmoperator-vmviewer-preview-action-list { + white-space: nowrap; + } + + span.busy::before { + font: normal normal normal 14px/1 ForkAwesome; + font-size: 1.125em; + content: "\f1ce"; + left: 1.45em; + top: 0.7em; + color: var(--info); + position: absolute; + animation: spin 2s linear infinite; + z-index: 100; + } } -.jdrupes-vmoperator-vmviewer-preview-action-list { - white-space: nowrap; +.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-edit { + select { + width: 15em; + } } +.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; + } + } + +} From bbd9d3baff5e77f0b31b4a64873db205f77ccf21 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 10 Jun 2024 15:15:00 +0200 Subject: [PATCH 022/342] Upgrade OIDC login library. --- org.jdrupes.vmoperator.manager/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index 1887108..49fbf3f 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -21,7 +21,7 @@ dependencies { 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.4.0,2)' + implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.5.0,2)' implementation 'org.jgrapes:org.jgrapes.webconlet.markdowndisplay:[1.2.0,2)' runtimeOnly 'org.jgrapes:org.jgrapes.webconlet.sysinfo:[1.4.0,2)' From 6213aa5970085ef782906bf554b60bfa9cebdd61 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 10 Jun 2024 23:09:48 +0200 Subject: [PATCH 023/342] Use better version descriptors. --- ....vmoperator.java-common-conventions.gradle | 10 +++++-- ...s.vmoperator.versioning-conventions.gradle | 28 ++++++++++--------- 2 files changed, 22 insertions(+), 16 deletions(-) diff --git a/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle index 5185041..c7419fa 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle @@ -61,15 +61,19 @@ java { jar { manifest { - inputs.property("gitDescriptor", { grgit.describe(always: true) }) + def matchExpr = [ project.tagName + "*" ] + + inputs.property("gitDescriptor", + { grgit.describe(always: true, match: matchExpr) }) // Set Git revision information in the manifests of built bundles + def gitDesc = grgit.describe(always: true, match: matchExpr) attributes([ "Implementation-Title": project.name, - "Implementation-Version": "$project.version (built from ${grgit.describe(always: true)})", + "Implementation-Version": "$project.version (built from ${gitDesc})", "Implementation-Vendor": grgit.repository.jgit.repository.config.getString("user", null, "name") + " (" + grgit.repository.jgit.repository.config.getString("user", null, "email") + ")", - "Git-Descriptor": grgit.describe(always: true), + "Git-Descriptor": gitDesc, "Git-SHA": grgit.head().id, ]) } diff --git a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle index 40ced48..a9e8dfe 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.versioning-conventions.gradle @@ -11,22 +11,24 @@ plugins { id 'pl.allegro.tech.build.axion-release' } +def shortened = project.name.startsWith(project.group + ".") ? + project.name.substring(project.group.length() + 1) : project.name +if (shortened == "manager") { + shortened = "manager-app"; +} +var tagName = 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")) { + tagName = tagName + grgit.branch.current.name.replace('/', '-') + "-" +} +project.ext.tagName = tagName + scmVersion { versionIncrementer 'incrementMinor' tag { - def shortened = project.name.startsWith(project.group + ".") ? - project.name.substring(project.group.length() + 1) : project.name - if (shortened == "manager") { - shortened = "manager-app"; - } - 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('/', '-') + "-" - } - prefix = p + prefix = project.tagName } } project.version = scmVersion.version From d5c9a0c30219c97033e651b5a635eb80214e93c1 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 10 Jun 2024 23:10:11 +0200 Subject: [PATCH 024/342] Upgrade base library. --- org.jdrupes.vmoperator.manager/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index 49fbf3f..c90ad54 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -21,7 +21,7 @@ dependencies { 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.5.0,2)' + implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.6.0,2)' implementation 'org.jgrapes:org.jgrapes.webconlet.markdowndisplay:[1.2.0,2)' runtimeOnly 'org.jgrapes:org.jgrapes.webconlet.sysinfo:[1.4.0,2)' From 9c31f574b83ea42773c8341991a7acf5150f5781 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 12 Jun 2024 20:53:18 +0200 Subject: [PATCH 025/342] Fix accessing console without password. --- .../src/org/jdrupes/vmoperator/vmviewer/VmViewer.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 fe48d3b..cae53b0 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 @@ -513,8 +513,8 @@ public class VmViewer extends FreeMarkerConlet { case "openConsole": if (perms.contains(Permission.ACCESS_CONSOLE)) { var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef), - e -> e.password().ifPresent( - pw -> openConsole(vmName, channel, model, pw))); + e -> openConsole(vmName, channel, model, + e.password().orElse(null))); fire(pwQuery, vmChannel); } break; @@ -555,7 +555,10 @@ public class VmViewer extends FreeMarkerConlet { .append("[virt-viewer]\ntype=spice\nhost=") .append(addr.get().getHostAddress()).append("\nport=") .append(Integer.toString(port.get().getAsInt())) - .append("\npassword=").append(password).append('\n'); + .append('\n'); + if (password != null) { + data.append("password=").append(password).append('\n'); + } proxyUrl.map(JsonPrimitive::getAsString).ifPresent(u -> { if (!Strings.isNullOrEmpty(u)) { data.append("proxy=").append(u).append('\n'); From 10182efea16f2a8885874be00fd10e0981fa055e Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" <1446020+mnlipp@users.noreply.github.com> Date: Thu, 13 Jun 2024 22:15:33 +0200 Subject: [PATCH 026/342] Feature/use java21 (#31) Switch to using Java-21. --- .github/workflows/gradle.yml | 4 +- .github/workflows/release.yml | 4 +- ....vmoperator.java-common-conventions.gradle | 2 +- ...pes.vmoperator.java-doc-conventions.gradle | 52 +- gradle/wrapper/gradle-wrapper.jar | Bin 61608 -> 43453 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 31 +- gradlew.bat | 20 +- misc/DejaVuSans-Bold.woff2 | Bin 236792 -> 0 bytes misc/DejaVuSans.woff2 | Bin 257460 -> 0 bytes misc/DejaVuSansMono-Bold.woff2 | Bin 143796 -> 0 bytes misc/DejaVuSansMono.woff2 | Bin 145192 -> 0 bytes misc/DejaVuSerif-Bold.woff2 | Bin 132740 -> 0 bytes misc/DejaVuSerif.woff2 | Bin 146864 -> 0 bytes misc/javadoc-overwrites.css | 2 + misc/stylesheet.css | 904 ------------------ .../jdrupes/vmoperator/manager/Containerfile | 2 +- .../vmoperator/manager/Reconciler.java | 8 +- .../runner/qemu/CdMediaController.java | 10 +- .../runner/qemu/Containerfile.alpine | 2 +- .../vmoperator/runner/qemu/Containerfile.arch | 2 +- .../vmoperator/runner/qemu/CpuController.java | 4 +- .../runner/qemu/DisplayController.java | 4 +- .../vmoperator/runner/qemu/Runner.java | 22 +- .../vmoperator/runner/qemu/StatusUpdater.java | 16 +- .../runner/qemu/events/ConfigureQemu.java | 8 +- .../runner/qemu/events/RunnerStateChange.java | 10 +- .../runner/qemu/events/TrayMovedEvent.java | 2 +- 28 files changed, 114 insertions(+), 998 deletions(-) delete mode 100644 misc/DejaVuSans-Bold.woff2 delete mode 100644 misc/DejaVuSans.woff2 delete mode 100644 misc/DejaVuSansMono-Bold.woff2 delete mode 100644 misc/DejaVuSansMono.woff2 delete mode 100644 misc/DejaVuSerif-Bold.woff2 delete mode 100644 misc/DejaVuSerif.woff2 create mode 100644 misc/javadoc-overwrites.css delete mode 100644 misc/stylesheet.css diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 547c1a4..afb5aab 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -22,10 +22,10 @@ jobs: fetch-depth: 0 - name: Install graphviz run: sudo apt-get install graphviz - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - java-version: '17' + java-version: '21' distribution: 'temurin' - name: Build with Gradle run: ./gradlew -Prepo.access.token=${{ secrets.REPO_ACCESS_TOKEN }} stage diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e99ee03..a9b5d98 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,10 +31,10 @@ jobs: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Set up JDK 17 + - name: Set up JDK 21 uses: actions/setup-java@v3 with: - java-version: '17' + java-version: '21' distribution: 'temurin' - name: Push with Gradle run: ./gradlew -Prepo.access.token=${{ secrets.REPO_ACCESS_TOKEN }} -Pdocker.registry=ghcr.io/${{ github.actor }} stage pushImages diff --git a/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle index c7419fa..605dc09 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.java-common-conventions.gradle @@ -55,7 +55,7 @@ sourceSets { java { toolchain { - languageVersion = JavaLanguageVersion.of(17) + languageVersion = JavaLanguageVersion.of(21) } } diff --git a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle index 95d7eff..081b7d9 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle @@ -22,31 +22,28 @@ configurations { } dependencies { - markdownDoclet "org.jdrupes.mdoclet:doclet:3.1.0" - javadocTaglets "org.jdrupes.taglets:plantuml-taglet:2.1.0" -} - -task javadocResources(type: Copy) { - into file(docDestinationDir) - from ("${rootProject.rootDir}/misc") { - include '*.woff2' - } + markdownDoclet "org.jdrupes.mdoclet:doclet:4.0.0" + javadocTaglets "org.jdrupes.taglets:plantuml-taglet:3.0.0" } task apidocs (type: JavaExec) { // Does not work on JitPack, no /usr/bin/dot - enabled = JavaVersion.current() == JavaVersion.VERSION_17 - - dependsOn javadocResources + enabled = JavaVersion.current() == JavaVersion.VERSION_21 outputs.dir(docDestinationDir) inputs.file rootProject.file('overview.md') - inputs.file "${rootProject.rootDir}/misc/stylesheet.css" + inputs.file "${rootProject.rootDir}/misc/javadoc-overwrites.css" - jvmArgs = ['--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED', - '--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED'] - main = 'jdk.javadoc.internal.tool.Main' + jvmArgs = ['--add-exports=jdk.compiler/com.sun.tools.doclint=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + '--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED', + '--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.toolkit=ALL-UNNAMED', + '--add-opens=jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.resources.releases=ALL-UNNAMED', + '-Duser.language=en', '-Duser.region=US'] + mainClass = 'jdk.javadoc.internal.tool.Main' gradle.projectsEvaluated { // Make sure that other projects' compileClasspaths are resolved @@ -69,7 +66,7 @@ task apidocs (type: JavaExec) { '-package', '-use', '-linksource', - '-link', 'https://docs.oracle.com/en/java/javase/17/docs/api/', + '-link', 'https://docs.oracle.com/en/java/javase/21/docs/api/', '-link', 'https://mnlipp.github.io/jgrapes/latest-release/javadoc/', '-link', 'https://freemarker.apache.org/docs/api/', '--add-exports', 'jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED', @@ -88,7 +85,7 @@ task apidocs (type: JavaExec) { '-bottom', rootProject.file("misc/javadoc.bottom.txt").text, '--allow-script-in-comments', '-Xdoclint:-html', - '--main-stylesheet', "${rootProject.rootDir}/misc/stylesheet.css", + '--add-stylesheet', "${rootProject.rootDir}/misc/javadoc-overwrites.css", '--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.formats.html=ALL-UNNAMED', '-quiet' ] @@ -97,6 +94,25 @@ task apidocs (type: JavaExec) { ignoreExitValue true } +task testJavadoc(type: Javadoc) { + enabled = JavaVersion.current() == JavaVersion.VERSION_21 + + source = fileTree(dir: 'testfiles', include: '**/*.java') + destinationDir = project.file("build/testfiles-gradle") + options.docletpath = configurations.markdownDoclet.files.asType(List) + options.doclet = 'org.jdrupes.mdoclet.MDoclet' + options.overview = 'testfiles/overview.md' + options.addStringOption('Xdoclint:-html', '-quiet') + + options.setJFlags([ + '--add-exports=jdk.compiler/com.sun.tools.doclint=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED', + '--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED', + '--add-exports=jdk.javadoc/jdk.javadoc.internal.tool=ALL-UNNAMED', + '--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.toolkit=ALL-UNNAMED', + '--add-opens=jdk.javadoc/jdk.javadoc.internal.doclets.toolkit.resources.releases=ALL-UNNAMED']) +} // Prepare github authentication for plugins if (System.properties['org.ajoberstar.grgit.auth.username'] == null) { System.setProperty('org.ajoberstar.grgit.auth.username', diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ccebba7710deaf9f98673a68957ea02138b60d0a..e6441136f3d4ba8a0da8d277868979cfbc8ad796 100644 GIT binary patch literal 43453 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 yu?e%!_ptzGB|8GrCfu%p?(_ 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
NnX)EH+Nua)3Y(c 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
@@ -101,7 +102,8 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, || !permissions.includes('accessConsole')" v-on:click="vmAction('openConsole')" :src="resourceBase + (running - ? 'computer.svg' : 'computer-off.svg')" + ? (inUse ? 'computer-in-use.svg' : 'computer.svg') + : 'computer-off.svg')" :title="localize('Open console')"> @@ -159,6 +161,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer", vmDefinition.name = vmDefinition.metadata.name; vmDefinition.currentCpus = vmDefinition.status.cpus; vmDefinition.currentRam = Number(vmDefinition.status.ram); + vmDefinition.usedBy = vmDefinition.status.consoleClient || ""; for (const condition of vmDefinition.status.conditions) { if (condition.type === "Running") { vmDefinition.running = condition.status === "True"; From 355eded86b5f03b09c9e947ca7908cafb396799c Mon Sep 17 00:00:00 2001 From: Michael Lipp Date: Sun, 10 Nov 2024 16:19:46 +0000 Subject: [PATCH 086/342] Add tracking of client (viewer) connection state and visualize in GUI. --- deploy/crds/vms-crd.yaml | 11 +++ .../vmoperator/runner/qemu/StatusUpdater.java | 93 +++++++++++++++++++ .../runner/qemu/events/MonitorEvent.java | 14 ++- .../qemu/events/SpiceConnectedEvent.java | 37 ++++++++ .../qemu/events/SpiceDisconnectedEvent.java | 37 ++++++++ .../runner/qemu/events/SpiceEvent.java | 46 +++++++++ .../vmoperator/vmconlet/l10n.properties | 1 + .../vmoperator/vmconlet/l10n_de.properties | 1 + .../vmconlet/browser/VmConlet-functions.ts | 4 +- .../vmoperator/vmviewer/computer-in-use.svg | 86 +++++++++++++++++ .../vmviewer/browser/VmViewer-functions.ts | 7 +- 11 files changed, 331 insertions(+), 6 deletions(-) create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceConnectedEvent.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceDisconnectedEvent.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceEvent.java create mode 100644 org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg diff --git a/deploy/crds/vms-crd.yaml b/deploy/crds/vms-crd.yaml index cda817c..492deae 100644 --- a/deploy/crds/vms-crd.yaml +++ b/deploy/crds/vms-crd.yaml @@ -1457,6 +1457,11 @@ spec: Amount of memory in use. type: string default: "0" + consoleClient: + description: >- + The hostname of the currently connected client. + type: string + default: "" displayPasswordSerial: description: >- Counts changes of the display password. Set to -1 @@ -1473,6 +1478,12 @@ spec: lastTransitionTime: "1970-01-01T00:00:00Z" reason: Creation message: "Creation of CR" + - type: ConsoleConnected + status: "False" + observedGeneration: 1 + lastTransitionTime: "1970-01-01T00:00:00Z" + reason: Creation + message: "Creation of CR" type: array items: type: object diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index 412681f..f6814b3 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -30,10 +30,13 @@ import java.math.BigDecimal; import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; +import java.util.ArrayList; +import java.util.List; import java.util.Map; 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.APP_NAME; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; @@ -50,6 +53,8 @@ import org.jdrupes.vmoperator.runner.qemu.events.HotpluggableCpuStatus; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jdrupes.vmoperator.runner.qemu.events.ShutdownEvent; +import org.jdrupes.vmoperator.runner.qemu.events.SpiceConnectedEvent; +import org.jdrupes.vmoperator.runner.qemu.events.SpiceDisconnectedEvent; import org.jdrupes.vmoperator.util.GsonPtr; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; @@ -275,6 +280,7 @@ public class StatusUpdater extends Component { private void updateRunningCondition(RunnerStateChange event, K8sDynamicModel from, JsonObject cond) { + @SuppressWarnings("PMD.AvoidDuplicateLiterals") boolean reportedRunning = "True".equals(cond.get("status").getAsString()); if (RUNNING_STATES.contains(event.runState()) @@ -363,4 +369,91 @@ public class StatusUpdater extends Component { public void onShutdown(ShutdownEvent event) throws ApiException { shutdownByGuest = event.byGuest(); } + + /** + * On spice connected. + * + * @param event the event + * @throws ApiException the api exception + */ + @Handler + public void onSpiceConnected(SpiceConnectedEvent event) + throws ApiException { + if (vmStub == null) { + return; + } + vmStub.updateStatus(from -> { + JsonObject status = from.status(); + status.addProperty("consoleClient", event.clientHost()); + updateConsoleConnectedCondition(from, status, true); + return status; + }); + + // Log event + var evt = new EventsV1Event() + .reportingController(VM_OP_GROUP + "/" + APP_NAME) + .action("ConsoleConnectionUpdate") + .reason("Connection from " + event.clientHost()); + K8s.createEvent(apiClient, vmStub.model().get(), evt); + } + + /** + * On spice disconnected. + * + * @param event the event + * @throws ApiException the api exception + */ + @Handler + public void onSpiceDisconnected(SpiceDisconnectedEvent event) + throws ApiException { + if (vmStub == null) { + return; + } + vmStub.updateStatus(from -> { + JsonObject status = from.status(); + status.addProperty("consoleClient", ""); + updateConsoleConnectedCondition(from, status, false); + return status; + }); + + // Log event + var evt = new EventsV1Event() + .reportingController(VM_OP_GROUP + "/" + APP_NAME) + .action("ConsoleConnectionUpdate") + .reason("Disconnected from " + event.clientHost()); + K8s.createEvent(apiClient, vmStub.model().get(), evt); + } + + private void updateConsoleConnectedCondition(VmDefinitionModel from, + JsonObject status, boolean connected) { + // Optimize, as we can get this several times + var current = status.getAsJsonArray("conditions").asList().stream() + .map(cond -> (JsonObject) cond) + .filter(cond -> "ConsoleConnected" + .equals(cond.get("type").getAsString())) + .findFirst() + .map(cond -> "True".equals(cond.get("status").getAsString())); + if (current.isPresent() && current.get() == connected) { + return; + } + + // Do update + final var condition = Map.of("type", "ConsoleConnected", + "status", connected ? "True" : "False", + "observedGeneration", from.getMetadata().getGeneration(), + "reason", connected ? "Connected" : "Disconnected", + "lastTransitionTime", Instant.now().toString()); + List toReplace = new ArrayList<>(List.of(condition)); + List newConds + = status.getAsJsonArray("conditions").asList().stream() + .map(cond -> (JsonObject) cond) + .map(cond -> "ConsoleConnected" + .equals(cond.get("type").getAsString()) + ? toReplace.remove(0) + : cond) + .collect(Collectors.toCollection(() -> new ArrayList<>())); + newConds.addAll(toReplace); + status.add("conditions", + apiClient.getJSON().getGson().toJsonTree(newConds)); + } } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java index ba04a26..2cc0f33 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java @@ -34,7 +34,8 @@ public class MonitorEvent extends Event { * The kind of monitor event. */ public enum Kind { - READY, POWERDOWN, DEVICE_TRAY_MOVED, BALLOON_CHANGE, SHUTDOWN + READY, POWERDOWN, DEVICE_TRAY_MOVED, BALLOON_CHANGE, SHUTDOWN, + SPICE_CONNECTED, SPICE_DISCONNECTED } private final Kind kind; @@ -49,8 +50,7 @@ public class MonitorEvent extends Event { @SuppressWarnings("PMD.TooFewBranchesForASwitchStatement") public static Optional from(JsonNode response) { try { - var kind = MonitorEvent.Kind - .valueOf(response.get("event").asText()); + var kind = Kind.valueOf(response.get("event").asText()); switch (kind) { case POWERDOWN: return Optional.of(new PowerdownEvent(kind, null)); @@ -63,6 +63,14 @@ public class MonitorEvent extends Event { case SHUTDOWN: return Optional .of(new ShutdownEvent(kind, response.get(EVENT_DATA))); + case SPICE_CONNECTED: + return Optional + .of(new SpiceConnectedEvent(kind, + response.get(EVENT_DATA))); + case SPICE_DISCONNECTED: + return Optional + .of(new SpiceDisconnectedEvent(kind, + response.get(EVENT_DATA))); default: return Optional .of(new MonitorEvent(kind, response.get(EVENT_DATA))); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceConnectedEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceConnectedEvent.java new file mode 100644 index 0000000..c133307 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceConnectedEvent.java @@ -0,0 +1,37 @@ +/* + * 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.events; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Signals a connection from a client. + */ +public class SpiceConnectedEvent extends SpiceEvent { + + /** + * Instantiates a new spice connected event. + * + * @param kind the kind + * @param data the data + */ + public SpiceConnectedEvent(Kind kind, JsonNode data) { + super(kind, data); + } +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceDisconnectedEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceDisconnectedEvent.java new file mode 100644 index 0000000..cfcb489 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceDisconnectedEvent.java @@ -0,0 +1,37 @@ +/* + * 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.events; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Signals a connection from a client. + */ +public class SpiceDisconnectedEvent extends SpiceEvent { + + /** + * Instantiates a new spice disconnected event. + * + * @param kind the kind + * @param data the data + */ + public SpiceDisconnectedEvent(Kind kind, JsonNode data) { + super(kind, data); + } +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceEvent.java new file mode 100644 index 0000000..6706f0c --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceEvent.java @@ -0,0 +1,46 @@ +/* + * 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.events; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Signals a connection from a client. + */ +public class SpiceEvent extends MonitorEvent { + + /** + * Instantiates a new tray moved. + * + * @param kind the kind + * @param data the data + */ + public SpiceEvent(Kind kind, JsonNode data) { + super(kind, data); + } + + /** + * Returns the client's host. + * + * @return the client's host address + */ + public String clientHost() { + return data().get("client").get("host").asText(); + } +} diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties index 880369b..41bf670 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties +++ b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties @@ -11,5 +11,6 @@ nodeName = Node requestedCpus = Requested CPUs requestedRam = Requested RAM running = Running +usedBy = Used by vmActions = Actions vmname = Name diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties index 7e1d95e..819db03 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties +++ b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties @@ -15,6 +15,7 @@ maximumRam = Maximales RAM nodeName = Knoten requestedCpus = Angeforderte CPUs requestedRam = Angefordertes RAM +usedBy = Benutzt von vmActions = Aktionen vmname = Name Value\ is\ above\ maximum = Wert ist zu groß diff --git a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts index 44d6471..8daf3a9 100644 --- a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts +++ b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts @@ -111,7 +111,8 @@ window.orgJDrupesVmOperatorVmConlet.initView = (viewDom: HTMLElement, ["runningConditionSince", "since"], ["currentCpus", "currentCpus"], ["currentRam", "currentRam"], - ["nodeName", "nodeName"] + ["nodeName", "nodeName"], + ["usedBy", "usedBy"] ], { sortKey: "name", sortOrder: "up" @@ -179,6 +180,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet", vmDefinition.name = vmDefinition.metadata.name; vmDefinition.currentCpus = vmDefinition.status.cpus; vmDefinition.currentRam = Number(vmDefinition.status.ram); + vmDefinition.usedBy = vmDefinition.status.consoleClient || ""; for (const condition of vmDefinition.status.conditions) { if (condition.type === "Running") { vmDefinition.running = condition.status === "True"; diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg new file mode 100644 index 0000000..90339c1 --- /dev/null +++ b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + 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 a14e83c..42c7d10 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 @@ -72,6 +72,7 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, previewApi.vmDefinition.spec.vm.state !== 'Stopped' && previewApi.vmDefinition.running); const running = computed(() => previewApi.vmDefinition.running); + const inUse = computed(() => previewApi.vmDefinition.usedBy != ''); const permissions = computed(() => previewApi.vmDefinition.spec ? previewApi.vmDefinition.userPermissions : []); @@ -88,7 +89,7 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, }; return { localize, resourceBase, vmAction, configured, - startable, stoppable, running, permissions }; + startable, stoppable, running, inUse, permissions }; }, template: `
@@ -101,7 +102,8 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, || !permissions.includes('accessConsole')" v-on:click="vmAction('openConsole')" :src="resourceBase + (running - ? 'computer.svg' : 'computer-off.svg')" + ? (inUse ? 'computer-in-use.svg' : 'computer.svg') + : 'computer-off.svg')" :title="localize('Open console')"> @@ -159,6 +161,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer", vmDefinition.name = vmDefinition.metadata.name; vmDefinition.currentCpus = vmDefinition.status.cpus; vmDefinition.currentRam = Number(vmDefinition.status.ram); + vmDefinition.usedBy = vmDefinition.status.consoleClient || ""; for (const condition of vmDefinition.status.conditions) { if (condition.type === "Running") { vmDefinition.running = condition.status === "True"; From 12d6745d759581dd4aee82f0aeabb27e7cfe92dd Mon Sep 17 00:00:00 2001 From: Michael Lipp Date: Tue, 12 Nov 2024 19:29:46 +0000 Subject: [PATCH 087/342] Add some logging messages and enhance logging configurability. --- deploy/crds/vms-crd.yaml | 5 ++++ dev-example/config.yaml | 12 +++++++++ .../manager/ConfigMapReconciler.java | 27 +++++++++++++++---- .../vmoperator/manager/Reconciler.java | 5 ++++ .../runner/qemu/CommandDefinition.java | 5 ++++ .../vmoperator/runner/qemu/Runner.java | 18 +++++++++++++ 6 files changed, 67 insertions(+), 5 deletions(-) diff --git a/deploy/crds/vms-crd.yaml b/deploy/crds/vms-crd.yaml index 492deae..f1bbaf2 100644 --- a/deploy/crds/vms-crd.yaml +++ b/deploy/crds/vms-crd.yaml @@ -1019,6 +1019,11 @@ spec: - accessConsole - "*" default: [] + loggingProperties: + type: string + description: >- + Override the default logging properties for + the runner for this VM. vm: type: object description: Defines the VM. diff --git a/dev-example/config.yaml b/dev-example/config.yaml index 3f973e4..af1f3b8 100644 --- a/dev-example/config.yaml +++ b/dev-example/config.yaml @@ -17,6 +17,18 @@ metallb.universe.tf/loadBalancerIPs: 192.168.168.1 metallb.universe.tf/ip-allocated-from-pool: single-common metallb.universe.tf/allow-shared-ip: single-common + loggingProperties: | + # Defaults for namespace (VM domain) + handlers=java.util.logging.ConsoleHandler + + #org.jgrapes.level=FINE + #org.jgrapes.core.handlerTracking.level=FINER + + org.jdrupes.vmoperator.runner.qemu.level=FINEST + + java.util.logging.ConsoleHandler.level=ALL + java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter + java.util.logging.SimpleFormatter.format=%1$tb %1$td %1$tT %4$s %5$s%6$s%n "/GuiSocketServer": port: 8888 "/GuiHttpServer": 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 129a54d..68ca7fa 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 @@ -18,6 +18,7 @@ package org.jdrupes.vmoperator.manager; +import com.google.gson.JsonObject; import freemarker.template.Configuration; import freemarker.template.TemplateException; import io.kubernetes.client.custom.V1Patch; @@ -36,6 +37,8 @@ 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.util.DataPath; +import org.jdrupes.vmoperator.util.GsonPtr; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; @@ -71,10 +74,6 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; public Map reconcile(Map model, VmChannel channel) throws IOException, TemplateException, ApiException { - // Get API - DynamicKubernetesApi cmApi = new DynamicKubernetesApi("", "v1", - "configmaps", channel.client()); - // Combine template and data and parse result var fmTemplate = fmConfig.getTemplate("runnerConfig.ftl.yaml"); StringWriter out = new StringWriter(); @@ -84,8 +83,26 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; var mapDef = Dynamics.newFromYaml( new Yaml(new SafeConstructor(new LoaderOptions())), out.toString()); + // Maybe override logging.properties from reconciler configuration. + DataPath. get(model, "reconciler", "loggingProperties") + .ifPresent(props -> { + GsonPtr.to(mapDef.getRaw()).get(JsonObject.class, "data") + .get().addProperty("logging.properties", props); + }); + + // Maybe override logging.properties from VM definition. + DataPath. get(model, "cr", "spec", "loggingProperties") + .ifPresent(props -> { + GsonPtr.to(mapDef.getRaw()).get(JsonObject.class, "data") + .get().addProperty("logging.properties", props); + }); + + // Get API + DynamicKubernetesApi cmApi = new DynamicKubernetesApi("", "v1", + "configmaps", channel.client()); + // Apply and maybe force pod update - var newState = K8s.apply(cmApi, mapDef, out.toString()); + var newState = K8s.apply(cmApi, mapDef, mapDef.getRaw().toString()); maybeForceUpdate(channel.client(), newState); @SuppressWarnings("unchecked") var res = (Map) channel.client().getJSON().getGson() 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 32753ac..3fa2ffe 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 @@ -132,6 +132,11 @@ import org.jgrapes.util.events.ConfigurationUpdate; * ``` * This makes all VM consoles available at IP address 192.168.168.1 * with the port numbers from the VM definitions. + * + * * `loggingProperties`: If defined, specifies the default logging + * properties to be used by the runners managed by the controller. + * This property is a string that holds the content of + * a logging.properties file. */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.AvoidDuplicateLiterals" }) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CommandDefinition.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CommandDefinition.java index 9057606..7aec209 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CommandDefinition.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/CommandDefinition.java @@ -69,4 +69,9 @@ class CommandDefinition { public String name() { return name; } + + @Override + public String toString() { + return "Command " + name + ": " + command; + } } \ No newline at end of file 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 0b6e22e..fedaf1e 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 @@ -48,6 +48,8 @@ import java.util.Set; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.DefaultParser; @@ -318,6 +320,7 @@ public class Runner extends Component { }); } + @SuppressWarnings("PMD.LambdaCanBeMethodReference") private void processInitialConfiguration(Configuration newConfig) { try { config = newConfig; @@ -333,12 +336,15 @@ public class Runner extends Component { var tplData = dataFromTemplate(); swtpmDefinition = Optional.ofNullable(tplData.get(SWTPM)) .map(d -> new CommandDefinition(SWTPM, d)).orElse(null); + logger.finest(() -> swtpmDefinition.toString()); qemuDefinition = Optional.ofNullable(tplData.get(QEMU)) .map(d -> new CommandDefinition(QEMU, d)).orElse(null); + logger.finest(() -> qemuDefinition.toString()); cloudInitImgDefinition = Optional.ofNullable(tplData.get(CLOUD_INIT_IMG)) .map(d -> new CommandDefinition(CLOUD_INIT_IMG, d)) .orElse(null); + logger.finest(() -> cloudInitImgDefinition.toString()); // Forward some values to child components qemuMonitor.configure(config.monitorSocket, @@ -364,6 +370,12 @@ public class Runner extends Component { break; } } + if (codePaths.iterator().hasNext() && config.firmwareRom == null) { + throw new IllegalArgumentException("No ROM found, candidates were: " + + StreamSupport.stream(codePaths.spliterator(), false) + .map(JsonNode::asText).collect(Collectors.joining(", "))); + } + // Get file for firmware vars, if necessary config.firmwareVars = config.dataDir.resolve(FW_VARS); if (!Files.exists(config.firmwareVars)) { @@ -405,12 +417,14 @@ public class Runner extends Component { model.put("hasDisplayPassword", config.hasDisplayPassword); model.put("cloudInit", config.cloudInit); model.put("vm", config.vm); + logger.finest(() -> "Processing template with model: " + model); // Combine template and data and parse result // (tempting, but no need to use a pipe here) var fmTemplate = fmConfig.getTemplate(templatePath.toString()); StringWriter out = new StringWriter(); fmTemplate.process(model, out); + logger.finest(() -> "Result of processing template: " + out); return yamlMapper.readValue(out.toString(), JsonNode.class); } @@ -746,6 +760,10 @@ public class Runner extends Component { props = Runner.class.getResourceAsStream("logging.properties"); } LogManager.getLogManager().readConfiguration(props); + Logger.getLogger(Runner.class.getName()).log(Level.CONFIG, + () -> path.isPresent() + ? "Using logging configuration from " + path.get() + : "Using default logging configuration"); } catch (IOException e) { e.printStackTrace(); } From 40cbeb694bfd37aaa446b3d3ef80c8c56d4de1b3 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 12 Nov 2024 22:04:15 +0100 Subject: [PATCH 088/342] Avoid NPE. --- .../src/org/jdrupes/vmoperator/runner/qemu/Runner.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) 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 fedaf1e..52db0ce 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 @@ -204,7 +204,7 @@ public class Runner extends Component { private static final String FW_VARS = "fw-vars.fd"; private static int exitStatus; - private EventPipeline rep; + private final EventPipeline rep = newEventPipeline(); private final ObjectMapper yamlMapper = new ObjectMapper(YAMLFactory .builder().disable(YAMLGenerator.Feature.WRITE_DOC_START_MARKER) .build()); @@ -446,8 +446,7 @@ public class Runner extends Component { // https://github.com/kubernetes-client/java/issues/100 io.kubernetes.client.openapi.Configuration.setDefaultApiClient(null); - // Prepare specific event pipeline to avoid concurrency. - rep = newEventPipeline(); + // Provide specific event pipeline to avoid concurrency. event.setAssociated(EventPipeline.class, rep); try { // Store process id From 228322748b494c9a3c9b1f1db755f9f4de7fe9c7 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 12 Nov 2024 22:41:54 +0100 Subject: [PATCH 089/342] Use 4m bios if smaller version is not available. --- .../resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml b/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml index 9aadbf6..32fdf55 100644 --- a/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml +++ b/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml @@ -8,6 +8,9 @@ - "/usr/share/edk2/ovmf/OVMF_CODE.fd" - "/usr/share/edk2/x64/OVMF_CODE.fd" - "/usr/share/OVMF/OVMF_CODE.fd" + # Use 4M version as fallback (if smaller version not available) + - "/usr/share/edk2/ovmf-4m/OVMF_CODE.fd" + - "/usr/share/edk2/x64/OVMF_CODE.4m.fd" "vars": - "/usr/share/edk2/ovmf/OVMF_VARS.fd" - "/usr/share/edk2/x64/OVMF_VARS.fd" From 97732073078bec55dcb2f3490a4cd4c1b34cb101 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 13 Nov 2024 11:14:53 +0100 Subject: [PATCH 090/342] Better name. --- .../resources/org/jdrupes/vmoperator/vmconlet/l10n.properties | 2 +- .../org/jdrupes/vmoperator/vmconlet/l10n_de.properties | 2 +- .../jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties index 41bf670..f4165c4 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties +++ b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties @@ -11,6 +11,6 @@ nodeName = Node requestedCpus = Requested CPUs requestedRam = Requested RAM running = Running -usedBy = Used by +usedFrom = Used from vmActions = Actions vmname = Name diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties index 819db03..29239ed 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties +++ b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties @@ -15,7 +15,7 @@ maximumRam = Maximales RAM nodeName = Knoten requestedCpus = Angeforderte CPUs requestedRam = Angefordertes RAM -usedBy = Benutzt von +usedFrom = Benutzt von vmActions = Aktionen vmname = Name Value\ is\ above\ maximum = Wert ist zu groß diff --git a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts index 8daf3a9..b171569 100644 --- a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts +++ b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts @@ -112,7 +112,7 @@ window.orgJDrupesVmOperatorVmConlet.initView = (viewDom: HTMLElement, ["currentCpus", "currentCpus"], ["currentRam", "currentRam"], ["nodeName", "nodeName"], - ["usedBy", "usedBy"] + ["usedFrom", "usedFrom"] ], { sortKey: "name", sortOrder: "up" @@ -180,7 +180,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet", vmDefinition.name = vmDefinition.metadata.name; vmDefinition.currentCpus = vmDefinition.status.cpus; vmDefinition.currentRam = Number(vmDefinition.status.ram); - vmDefinition.usedBy = vmDefinition.status.consoleClient || ""; + vmDefinition.usedFrom = vmDefinition.status.consoleClient || ""; for (const condition of vmDefinition.status.conditions) { if (condition.type === "Running") { vmDefinition.running = condition.status === "True"; From 4d447717c2a40a9e933bf95ab60921fa72e88366 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 13 Nov 2024 23:45:54 +0100 Subject: [PATCH 091/342] Improve tracking. --- .../runner/qemu/ConsoleTracker.java | 159 +++++++++++++++ .../vmoperator/runner/qemu/StatusUpdater.java | 183 ++---------------- .../vmoperator/runner/qemu/VmDefUpdater.java | 141 ++++++++++++++ .../runner/qemu/events/MonitorEvent.java | 15 +- .../runner/qemu/events/SpiceEvent.java | 9 + .../qemu/events/SpiceInitializedEvent.java | 46 +++++ 6 files changed, 375 insertions(+), 178 deletions(-) create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceInitializedEvent.java diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java new file mode 100644 index 0000000..7d54235 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java @@ -0,0 +1,159 @@ +/* + * 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.runner.qemu; + +import com.google.gson.JsonObject; +import io.kubernetes.client.apimachinery.GroupVersionKind; +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.models.EventsV1Event; +import java.io.IOException; +import java.util.logging.Level; +import static org.jdrupes.vmoperator.common.Constants.APP_NAME; +import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; +import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; +import org.jdrupes.vmoperator.common.K8s; +import org.jdrupes.vmoperator.common.K8sClient; +import org.jdrupes.vmoperator.common.VmDefinitionStub; +import org.jdrupes.vmoperator.runner.qemu.events.Exit; +import org.jdrupes.vmoperator.runner.qemu.events.SpiceDisconnectedEvent; +import org.jdrupes.vmoperator.runner.qemu.events.SpiceInitializedEvent; +import org.jgrapes.core.Channel; +import org.jgrapes.core.annotation.Handler; +import org.jgrapes.core.events.Start; + +/** + * A (sub)component that updates the console status in the CR status. + * Created as child of {@link StatusUpdater}. + */ +@SuppressWarnings("PMD.DataflowAnomalyAnalysis") +public class ConsoleTracker extends VmDefUpdater { + + private final K8sClient apiClient; + private VmDefinitionStub vmStub; + private String mainChannelClientHost; + private long mainChannelClientPort; + + /** + * Instantiates a new status updater. + * + * @param componentChannel the component channel + */ + @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") + public ConsoleTracker(Channel componentChannel) { + super(componentChannel); + apiClient = (K8sClient) io.kubernetes.client.openapi.Configuration + .getDefaultApiClient(); + } + + /** + * Handle the start event. + * + * @param event the event + * @throws IOException + * @throws ApiException + */ + @Handler + public void onStart(Start event) { + if (namespace == null) { + return; + } + try { + vmStub = VmDefinitionStub.get(apiClient, + new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), + namespace, vmName); + } catch (ApiException e) { + logger.log(Level.SEVERE, e, + () -> "Cannot access VM object, terminating."); + event.cancel(true); + fire(new Exit(1)); + } + } + + /** + * On spice connected. + * + * @param event the event + * @throws ApiException the api exception + */ + @Handler + @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", + "PMD.AvoidDuplicateLiterals" }) + public void onSpiceInitialized(SpiceInitializedEvent event) + throws ApiException { + if (vmStub == null) { + return; + } + + // Only process connections using main channel. + if (event.channelType() != 1) { + return; + } + mainChannelClientHost = event.clientHost(); + mainChannelClientPort = event.clientPort(); + vmStub.updateStatus(from -> { + JsonObject status = from.status(); + status.addProperty("consoleClient", event.clientHost()); + updateCondition(apiClient, from, status, "ConsoleConnected", + true, "Connection from " + event.clientHost(), null); + return status; + }); + + // Log event + var evt = new EventsV1Event() + .reportingController(VM_OP_GROUP + "/" + APP_NAME) + .action("ConsoleConnectionUpdate") + .reason("Connection from " + event.clientHost()); + K8s.createEvent(apiClient, vmStub.model().get(), evt); + } + + /** + * On spice disconnected. + * + * @param event the event + * @throws ApiException the api exception + */ + @Handler + @SuppressWarnings("PMD.AvoidDuplicateLiterals") + public void onSpiceDisconnected(SpiceDisconnectedEvent event) + throws ApiException { + if (vmStub == null) { + return; + } + + // Only process disconnects from main channel. + if (!event.clientHost().equals(mainChannelClientHost) + || event.clientPort() != mainChannelClientPort) { + return; + } + vmStub.updateStatus(from -> { + JsonObject status = from.status(); + status.addProperty("consoleClient", ""); + updateCondition(apiClient, from, status, "ConsoleConnected", + false, event.clientHost() + " has disconnected", null); + return status; + }); + + // Log event + var evt = new EventsV1Event() + .reportingController(VM_OP_GROUP + "/" + APP_NAME) + .action("ConsoleConnectionUpdate") + .reason("Disconnected from " + event.clientHost()); + K8s.createEvent(apiClient, vmStub.model().get(), evt); + } +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index f6814b3..ca5d46a 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -27,22 +27,13 @@ import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.EventsV1Event; import java.io.IOException; import java.math.BigDecimal; -import java.nio.file.Files; -import java.nio.file.Path; -import java.time.Instant; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -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.APP_NAME; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import org.jdrupes.vmoperator.common.K8s; import org.jdrupes.vmoperator.common.K8sClient; -import org.jdrupes.vmoperator.common.K8sDynamicModel; import org.jdrupes.vmoperator.common.VmDefinitionModel; import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.runner.qemu.events.BalloonChangeEvent; @@ -53,28 +44,21 @@ import org.jdrupes.vmoperator.runner.qemu.events.HotpluggableCpuStatus; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jdrupes.vmoperator.runner.qemu.events.ShutdownEvent; -import org.jdrupes.vmoperator.runner.qemu.events.SpiceConnectedEvent; -import org.jdrupes.vmoperator.runner.qemu.events.SpiceDisconnectedEvent; import org.jdrupes.vmoperator.util.GsonPtr; import org.jgrapes.core.Channel; -import org.jgrapes.core.Component; import org.jgrapes.core.annotation.Handler; import org.jgrapes.core.events.HandlingError; import org.jgrapes.core.events.Start; -import org.jgrapes.util.events.ConfigurationUpdate; -import org.jgrapes.util.events.InitialConfiguration; /** * Updates the CR status. */ @SuppressWarnings("PMD.DataflowAnomalyAnalysis") -public class StatusUpdater extends Component { +public class StatusUpdater extends VmDefUpdater { private static final Set RUNNING_STATES = Set.of(RunState.RUNNING, RunState.TERMINATING); - private String namespace; - private String vmName; private K8sClient apiClient; private long observedGeneration; private boolean guestShutdownStops; @@ -98,6 +82,7 @@ public class StatusUpdater extends Component { () -> "Cannot access events API, terminating."); fire(new Exit(1)); } + attach(new ConsoleTracker(componentChannel)); } /** @@ -114,43 +99,6 @@ public class StatusUpdater extends Component { } } - /** - * On configuration update. - * - * @param event the event - */ - @Handler - @SuppressWarnings("unchecked") - public void onConfigurationUpdate(ConfigurationUpdate event) { - event.structured("/Runner").ifPresent(c -> { - if (event instanceof InitialConfiguration) { - namespace = (String) c.get("namespace"); - updateNamespace(); - vmName = Optional.ofNullable((Map) c.get("vm")) - .map(vm -> vm.get("name")).orElse(null); - } - }); - } - - private void updateNamespace() { - if (namespace == null) { - var path = Path - .of("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); - if (Files.isReadable(path)) { - try { - namespace = Files.lines(path).findFirst().orElse(null); - } catch (IOException e) { - logger.log(Level.WARNING, e, - () -> "Cannot read namespace."); - } - } - } - if (namespace == null) { - logger.warning(() -> "Namespace is unknown, some functions" - + " won't be available."); - } - } - /** * Handle the start event. * @@ -238,13 +186,9 @@ public class StatusUpdater extends Component { } vmStub.updateStatus(vmDef, from -> { JsonObject status = from.status(); - status.getAsJsonArray("conditions").asList().stream() - .map(cond -> (JsonObject) cond) - .forEach(cond -> { - if ("Running".equals(cond.get("type").getAsString())) { - updateRunningCondition(event, from, cond); - } - }); + boolean running = RUNNING_STATES.contains(event.runState()); + updateCondition(apiClient, vmDef, vmDef.status(), "Running", + running, event.reason(), event.message()); if (event.runState() == RunState.STARTING) { status.addProperty("ram", GsonPtr.to(from.data()) .getAsString("spec", "vm", "maximumRam").orElse("0")); @@ -253,6 +197,13 @@ public class StatusUpdater extends Component { status.addProperty("ram", "0"); status.addProperty("cpus", 0); } + + // In case console connection was still present + if (!running) { + status.addProperty("consoleClient", ""); + updateCondition(apiClient, from, status, "ConsoleConnected", + false, "VM has stopped", null); + } return status; }); @@ -278,29 +229,6 @@ public class StatusUpdater extends Component { K8s.createEvent(apiClient, vmDef, evt); } - private void updateRunningCondition(RunnerStateChange event, - K8sDynamicModel from, JsonObject cond) { - @SuppressWarnings("PMD.AvoidDuplicateLiterals") - boolean reportedRunning - = "True".equals(cond.get("status").getAsString()); - if (RUNNING_STATES.contains(event.runState()) - && !reportedRunning) { - cond.addProperty("status", "True"); - cond.addProperty("lastTransitionTime", - Instant.now().toString()); - } - if (!RUNNING_STATES.contains(event.runState()) - && reportedRunning) { - cond.addProperty("status", "False"); - cond.addProperty("lastTransitionTime", - Instant.now().toString()); - } - cond.addProperty("reason", event.reason()); - cond.addProperty("message", event.message()); - cond.addProperty("observedGeneration", - from.getMetadata().getGeneration()); - } - /** * On ballon change. * @@ -369,91 +297,4 @@ public class StatusUpdater extends Component { public void onShutdown(ShutdownEvent event) throws ApiException { shutdownByGuest = event.byGuest(); } - - /** - * On spice connected. - * - * @param event the event - * @throws ApiException the api exception - */ - @Handler - public void onSpiceConnected(SpiceConnectedEvent event) - throws ApiException { - if (vmStub == null) { - return; - } - vmStub.updateStatus(from -> { - JsonObject status = from.status(); - status.addProperty("consoleClient", event.clientHost()); - updateConsoleConnectedCondition(from, status, true); - return status; - }); - - // Log event - var evt = new EventsV1Event() - .reportingController(VM_OP_GROUP + "/" + APP_NAME) - .action("ConsoleConnectionUpdate") - .reason("Connection from " + event.clientHost()); - K8s.createEvent(apiClient, vmStub.model().get(), evt); - } - - /** - * On spice disconnected. - * - * @param event the event - * @throws ApiException the api exception - */ - @Handler - public void onSpiceDisconnected(SpiceDisconnectedEvent event) - throws ApiException { - if (vmStub == null) { - return; - } - vmStub.updateStatus(from -> { - JsonObject status = from.status(); - status.addProperty("consoleClient", ""); - updateConsoleConnectedCondition(from, status, false); - return status; - }); - - // Log event - var evt = new EventsV1Event() - .reportingController(VM_OP_GROUP + "/" + APP_NAME) - .action("ConsoleConnectionUpdate") - .reason("Disconnected from " + event.clientHost()); - K8s.createEvent(apiClient, vmStub.model().get(), evt); - } - - private void updateConsoleConnectedCondition(VmDefinitionModel from, - JsonObject status, boolean connected) { - // Optimize, as we can get this several times - var current = status.getAsJsonArray("conditions").asList().stream() - .map(cond -> (JsonObject) cond) - .filter(cond -> "ConsoleConnected" - .equals(cond.get("type").getAsString())) - .findFirst() - .map(cond -> "True".equals(cond.get("status").getAsString())); - if (current.isPresent() && current.get() == connected) { - return; - } - - // Do update - final var condition = Map.of("type", "ConsoleConnected", - "status", connected ? "True" : "False", - "observedGeneration", from.getMetadata().getGeneration(), - "reason", connected ? "Connected" : "Disconnected", - "lastTransitionTime", Instant.now().toString()); - List toReplace = new ArrayList<>(List.of(condition)); - List newConds - = status.getAsJsonArray("conditions").asList().stream() - .map(cond -> (JsonObject) cond) - .map(cond -> "ConsoleConnected" - .equals(cond.get("type").getAsString()) - ? toReplace.remove(0) - : cond) - .collect(Collectors.toCollection(() -> new ArrayList<>())); - newConds.addAll(toReplace); - status.add("conditions", - apiClient.getJSON().getGson().toJsonTree(newConds)); - } } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java new file mode 100644 index 0000000..893fc61 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java @@ -0,0 +1,141 @@ +/* + * 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.runner.qemu; + +import com.google.gson.JsonObject; +import io.kubernetes.client.openapi.ApiClient; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.logging.Level; +import java.util.stream.Collectors; +import org.jdrupes.vmoperator.common.VmDefinitionModel; +import org.jgrapes.core.Channel; +import org.jgrapes.core.Component; +import org.jgrapes.core.annotation.Handler; +import org.jgrapes.util.events.ConfigurationUpdate; +import org.jgrapes.util.events.InitialConfiguration; + +/** + * Updates the CR status. + */ +@SuppressWarnings("PMD.DataflowAnomalyAnalysis") +public class VmDefUpdater extends Component { + + protected String namespace; + protected String vmName; + + /** + * Instantiates a new status updater. + * + * @param componentChannel the component channel + */ + @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") + public VmDefUpdater(Channel componentChannel) { + super(componentChannel); + } + + /** + * On configuration update. + * + * @param event the event + */ + @Handler + @SuppressWarnings("unchecked") + public void onConfigurationUpdate(ConfigurationUpdate event) { + event.structured("/Runner").ifPresent(c -> { + if (event instanceof InitialConfiguration) { + namespace = (String) c.get("namespace"); + updateNamespace(); + vmName = Optional.ofNullable((Map) c.get("vm")) + .map(vm -> vm.get("name")).orElse(null); + } + }); + } + + private void updateNamespace() { + if (namespace == null) { + var path = Path + .of("/var/run/secrets/kubernetes.io/serviceaccount/namespace"); + if (Files.isReadable(path)) { + try { + namespace = Files.lines(path).findFirst().orElse(null); + } catch (IOException e) { + logger.log(Level.WARNING, e, + () -> "Cannot read namespace."); + } + } + } + if (namespace == null) { + logger.warning(() -> "Namespace is unknown, some functions" + + " won't be available."); + } + } + + /** + * Update condition. + * + * @param apiClient the api client + * @param from the vM definition + * @param status the current status + * @param type the condition type + * @param state the new state + * @param reason the reason for the change + */ + protected void updateCondition(ApiClient apiClient, VmDefinitionModel from, + JsonObject status, String type, boolean state, String reason, + String message) { + // Optimize, as we can get this several times + var current = status.getAsJsonArray("conditions").asList().stream() + .map(cond -> (JsonObject) cond) + .filter(cond -> type.equals(cond.get("type").getAsString())) + .findFirst() + .map(cond -> "True".equals(cond.get("status").getAsString())); + if (current.isPresent() && current.get() == state) { + return; + } + + // Do update + final var condition = new HashMap<>(Map.of("type", type, + "status", state ? "True" : "False", + "observedGeneration", from.getMetadata().getGeneration(), + "reason", reason, + "lastTransitionTime", Instant.now().toString())); + if (message != null) { + condition.put("message", message); + } + List toReplace = new ArrayList<>(List.of(condition)); + List newConds + = status.getAsJsonArray("conditions").asList().stream() + .map(cond -> (JsonObject) cond) + .map(cond -> type.equals(cond.get("type").getAsString()) + ? toReplace.remove(0) + : cond) + .collect(Collectors.toCollection(() -> new ArrayList<>())); + newConds.addAll(toReplace); + status.add("conditions", + apiClient.getJSON().getGson().toJsonTree(newConds)); + } +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java index 2cc0f33..df981c8 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java @@ -35,7 +35,7 @@ public class MonitorEvent extends Event { */ public enum Kind { READY, POWERDOWN, DEVICE_TRAY_MOVED, BALLOON_CHANGE, SHUTDOWN, - SPICE_CONNECTED, SPICE_DISCONNECTED + SPICE_CONNECTED, SPICE_INITIALIZED, SPICE_DISCONNECTED } private final Kind kind; @@ -64,13 +64,14 @@ public class MonitorEvent extends Event { return Optional .of(new ShutdownEvent(kind, response.get(EVENT_DATA))); case SPICE_CONNECTED: - return Optional - .of(new SpiceConnectedEvent(kind, - response.get(EVENT_DATA))); + return Optional.of(new SpiceConnectedEvent(kind, + response.get(EVENT_DATA))); + case SPICE_INITIALIZED: + return Optional.of(new SpiceInitializedEvent(kind, + response.get(EVENT_DATA))); case SPICE_DISCONNECTED: - return Optional - .of(new SpiceDisconnectedEvent(kind, - response.get(EVENT_DATA))); + return Optional.of(new SpiceDisconnectedEvent(kind, + response.get(EVENT_DATA))); default: return Optional .of(new MonitorEvent(kind, response.get(EVENT_DATA))); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceEvent.java index 6706f0c..4ce27e2 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceEvent.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceEvent.java @@ -43,4 +43,13 @@ public class SpiceEvent extends MonitorEvent { public String clientHost() { return data().get("client").get("host").asText(); } + + /** + * Returns the client's port. + * + * @return the client's port number + */ + public long clientPort() { + return data().get("client").get("port").asLong(); + } } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceInitializedEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceInitializedEvent.java new file mode 100644 index 0000000..7bb84b7 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/SpiceInitializedEvent.java @@ -0,0 +1,46 @@ +/* + * 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.events; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Signals a connection from a client. + */ +public class SpiceInitializedEvent extends SpiceEvent { + + /** + * Instantiates a new spice connected event. + * + * @param kind the kind + * @param data the data + */ + public SpiceInitializedEvent(Kind kind, JsonNode data) { + super(kind, data); + } + + /** + * Returns the channel type. + * + * @return the channel type + */ + public int channelType() { + return data().get("client").get("channel-type").asInt(); + } +} From f1d973502ddf819638e3e543638acd2e2a9fa3af Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 14 Nov 2024 11:58:51 +0100 Subject: [PATCH 092/342] Fix transparency. --- .../vmoperator/vmviewer/computer-in-use.svg | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg index 90339c1..00e4cc0 100644 --- a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg +++ b/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg @@ -51,9 +51,9 @@ inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" - inkscape:zoom="1.28" - inkscape:cx="326.5625" - inkscape:cy="548.04688" + inkscape:zoom="0.90509668" + inkscape:cx="345.81941" + inkscape:cy="376.2029" inkscape:window-width="1920" inkscape:window-height="1008" inkscape:window-x="0" @@ -63,18 +63,17 @@ - + + style="opacity:1;stroke-width:0.00145614;stroke-linecap:square;stroke-linejoin:round;stroke-miterlimit:0;stroke-dasharray:none;paint-order:fill markers stroke" + d="m 0,13.998258 h 5.4336202 v 2.001741 H 0 Z" + sodipodi:nodetypes="ccccc" /> + From 811164f7b9c34c9e26fb19211b67cc48e69e6503 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 14 Nov 2024 11:59:14 +0100 Subject: [PATCH 093/342] Move api client to base class. --- .../runner/qemu/ConsoleTracker.java | 5 ++--- .../vmoperator/runner/qemu/StatusUpdater.java | 19 ++++------------- .../vmoperator/runner/qemu/VmDefUpdater.java | 21 +++++++++++++++---- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java index 7d54235..95b748c 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java @@ -44,7 +44,6 @@ import org.jgrapes.core.events.Start; @SuppressWarnings("PMD.DataflowAnomalyAnalysis") public class ConsoleTracker extends VmDefUpdater { - private final K8sClient apiClient; private VmDefinitionStub vmStub; private String mainChannelClientHost; private long mainChannelClientPort; @@ -109,7 +108,7 @@ public class ConsoleTracker extends VmDefUpdater { vmStub.updateStatus(from -> { JsonObject status = from.status(); status.addProperty("consoleClient", event.clientHost()); - updateCondition(apiClient, from, status, "ConsoleConnected", + updateCondition(from, status, "ConsoleConnected", true, "Connection from " + event.clientHost(), null); return status; }); @@ -144,7 +143,7 @@ public class ConsoleTracker extends VmDefUpdater { vmStub.updateStatus(from -> { JsonObject status = from.status(); status.addProperty("consoleClient", ""); - updateCondition(apiClient, from, status, "ConsoleConnected", + updateCondition(from, status, "ConsoleConnected", false, event.clientHost() + " has disconnected", null); return status; }); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index ca5d46a..f663476 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -33,7 +33,6 @@ import static org.jdrupes.vmoperator.common.Constants.APP_NAME; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import org.jdrupes.vmoperator.common.K8s; -import org.jdrupes.vmoperator.common.K8sClient; import org.jdrupes.vmoperator.common.VmDefinitionModel; import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.runner.qemu.events.BalloonChangeEvent; @@ -59,7 +58,6 @@ public class StatusUpdater extends VmDefUpdater { private static final Set RUNNING_STATES = Set.of(RunState.RUNNING, RunState.TERMINATING); - private K8sClient apiClient; private long observedGeneration; private boolean guestShutdownStops; private boolean shutdownByGuest; @@ -73,15 +71,6 @@ public class StatusUpdater extends VmDefUpdater { @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") public StatusUpdater(Channel componentChannel) { super(componentChannel); - try { - apiClient = new K8sClient(); - io.kubernetes.client.openapi.Configuration - .setDefaultApiClient(apiClient); - } catch (IOException e) { - logger.log(Level.SEVERE, e, - () -> "Cannot access events API, terminating."); - fire(new Exit(1)); - } attach(new ConsoleTracker(componentChannel)); } @@ -187,8 +176,8 @@ public class StatusUpdater extends VmDefUpdater { vmStub.updateStatus(vmDef, from -> { JsonObject status = from.status(); boolean running = RUNNING_STATES.contains(event.runState()); - updateCondition(apiClient, vmDef, vmDef.status(), "Running", - running, event.reason(), event.message()); + updateCondition(vmDef, vmDef.status(), "Running", running, + event.reason(), event.message()); if (event.runState() == RunState.STARTING) { status.addProperty("ram", GsonPtr.to(from.data()) .getAsString("spec", "vm", "maximumRam").orElse("0")); @@ -201,8 +190,8 @@ public class StatusUpdater extends VmDefUpdater { // In case console connection was still present if (!running) { status.addProperty("consoleClient", ""); - updateCondition(apiClient, from, status, "ConsoleConnected", - false, "VM has stopped", null); + updateCondition(from, status, "ConsoleConnected", false, + "VM has stopped", null); } return status; }); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java index 893fc61..1c260c7 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java @@ -19,7 +19,6 @@ package org.jdrupes.vmoperator.runner.qemu; import com.google.gson.JsonObject; -import io.kubernetes.client.openapi.ApiClient; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -31,7 +30,9 @@ import java.util.Map; import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; +import org.jdrupes.vmoperator.common.K8sClient; import org.jdrupes.vmoperator.common.VmDefinitionModel; +import org.jdrupes.vmoperator.runner.qemu.events.Exit; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; import org.jgrapes.core.annotation.Handler; @@ -46,15 +47,28 @@ public class VmDefUpdater extends Component { protected String namespace; protected String vmName; + protected K8sClient apiClient; /** * Instantiates a new status updater. * * @param componentChannel the component channel + * @throws IOException */ @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") public VmDefUpdater(Channel componentChannel) { super(componentChannel); + if (apiClient == null) { + try { + apiClient = new K8sClient(); + io.kubernetes.client.openapi.Configuration + .setDefaultApiClient(apiClient); + } catch (IOException e) { + logger.log(Level.SEVERE, e, + () -> "Cannot access events API, terminating."); + fire(new Exit(1)); + } + } } /** @@ -104,9 +118,8 @@ public class VmDefUpdater extends Component { * @param state the new state * @param reason the reason for the change */ - protected void updateCondition(ApiClient apiClient, VmDefinitionModel from, - JsonObject status, String type, boolean state, String reason, - String message) { + protected void updateCondition(VmDefinitionModel from, JsonObject status, + String type, boolean state, String reason, String message) { // Optimize, as we can get this several times var current = status.getAsJsonArray("conditions").asList().stream() .map(cond -> (JsonObject) cond) From 4ea568ea17ec338897b192ae0b3cd5c22a9cded1 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 14 Nov 2024 12:40:45 +0100 Subject: [PATCH 094/342] Automatically repeat status update in case of conflict. --- .../vmoperator/common/K8sGenericStub.java | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java index 09516a0..0689a97 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java @@ -193,7 +193,33 @@ public class K8sGenericStub updateStatus(O object, + Function status, int retries) throws ApiException { + while (true) { + try { + return K8s.optional(api.updateStatus(object, status)); + } catch (ApiException e) { + if (HttpURLConnection.HTTP_CONFLICT != e.getCode() + || retries-- <= 0) { + throw e; + } + } + } + } + + /** + * Updates the object's status, retrying up to 16 times if there + * is a conflict. * * @param object the current state of the object (passed to `status`) * @param status function that returns the new status @@ -202,7 +228,7 @@ public class K8sGenericStub updateStatus(O object, Function status) throws ApiException { - return K8s.optional(api.updateStatus(object, status)); + return updateStatus(object, status, 16); } /** From 0ba8d922ef486854da01603410952506a7755635 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 14 Nov 2024 18:46:19 +0100 Subject: [PATCH 095/342] Add used by information. --- deploy/crds/vms-crd.yaml | 6 ++++++ .../manager/events/GetDisplayPassword.java | 16 ++++++++++++++-- .../manager/DisplaySecretMonitor.java | 17 ++++++++++++++++- .../jdrupes/vmoperator/vmconlet/l10n.properties | 1 + .../vmoperator/vmconlet/l10n_de.properties | 1 + .../vmconlet/browser/VmConlet-functions.ts | 4 +++- .../jdrupes/vmoperator/vmviewer/VmViewer.java | 9 ++++++--- 7 files changed, 47 insertions(+), 7 deletions(-) diff --git a/deploy/crds/vms-crd.yaml b/deploy/crds/vms-crd.yaml index f1bbaf2..93c70cc 100644 --- a/deploy/crds/vms-crd.yaml +++ b/deploy/crds/vms-crd.yaml @@ -1467,6 +1467,12 @@ spec: The hostname of the currently connected client. type: string default: "" + consoleUser: + description: >- + The id of the user who has last requested a console + connection. + type: string + default: "" displayPasswordSerial: description: >- Counts changes of the display password. Set to -1 diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetDisplayPassword.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetDisplayPassword.java index 3322f1a..f6fa555 100644 --- a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetDisplayPassword.java +++ b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetDisplayPassword.java @@ -29,14 +29,17 @@ import org.jgrapes.core.Event; public class GetDisplayPassword extends Event { private final VmDefinition vmDef; + private final String user; /** - * Instantiates a new returns the display secret. + * Instantiates a new request for the display secret. * * @param vmDef the vm name + * @param user the requesting user */ - public GetDisplayPassword(VmDefinition vmDef) { + public GetDisplayPassword(VmDefinition vmDef, String user) { this.vmDef = vmDef; + this.user = user; } /** @@ -48,6 +51,15 @@ public class GetDisplayPassword extends Event { return vmDef; } + /** + * Return the id of the user who has requested the password. + * + * @return the string + */ + public String user() { + return user; + } + /** * Return the password. May only be called when the event is completed. * 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 69d4058..2f480a3 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 @@ -18,6 +18,8 @@ package org.jdrupes.vmoperator.manager; +import com.google.gson.JsonObject; +import io.kubernetes.client.apimachinery.GroupVersionKind; import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.V1Secret; @@ -37,10 +39,13 @@ import java.util.Optional; import java.util.Scanner; import java.util.logging.Level; import static org.jdrupes.vmoperator.common.Constants.APP_NAME; +import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; +import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import static org.jdrupes.vmoperator.common.Constants.VM_OP_NAME; import org.jdrupes.vmoperator.common.K8sClient; import org.jdrupes.vmoperator.common.K8sV1PodStub; import org.jdrupes.vmoperator.common.K8sV1SecretStub; +import org.jdrupes.vmoperator.common.VmDefinitionStub; import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET; import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_PASSWORD; import static org.jdrupes.vmoperator.manager.Constants.DATA_PASSWORD_EXPIRY; @@ -181,12 +186,22 @@ public class DisplaySecretMonitor + "app.kubernetes.io/instance=" + event.vmDefinition().metadata().getName()); var stubs = K8sV1SecretStub.list(client(), - event.vmDefinition().metadata().getNamespace(), options); + event.vmDefinition().namespace(), options); if (stubs.isEmpty()) { return; } var stub = stubs.iterator().next(); + // Valid request, update console user in status + var vmStub = VmDefinitionStub.get(client(), + new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), + event.vmDefinition().namespace(), event.vmDefinition().name()); + vmStub.updateStatus(from -> { + JsonObject status = from.status(); + status.addProperty("consoleUser", event.user()); + return status; + }); + // Check validity var model = stub.model().get(); @SuppressWarnings("PMD.StringInstantiation") diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties index f4165c4..4ab3a3f 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties +++ b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n.properties @@ -11,6 +11,7 @@ nodeName = Node requestedCpus = Requested CPUs requestedRam = Requested RAM running = Running +usedBy = Used by usedFrom = Used from vmActions = Actions vmname = Name diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties index 29239ed..15a8b68 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties +++ b/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/l10n_de.properties @@ -15,6 +15,7 @@ maximumRam = Maximales RAM nodeName = Knoten requestedCpus = Angeforderte CPUs requestedRam = Angefordertes RAM +usedBy = Benutzt durch usedFrom = Benutzt von vmActions = Aktionen vmname = Name diff --git a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts index b171569..cfda2de 100644 --- a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts +++ b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts @@ -112,7 +112,8 @@ window.orgJDrupesVmOperatorVmConlet.initView = (viewDom: HTMLElement, ["currentCpus", "currentCpus"], ["currentRam", "currentRam"], ["nodeName", "nodeName"], - ["usedFrom", "usedFrom"] + ["usedFrom", "usedFrom"], + ["usedBy", "usedBy"] ], { sortKey: "name", sortOrder: "up" @@ -181,6 +182,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet", vmDefinition.currentCpus = vmDefinition.status.cpus; vmDefinition.currentRam = Number(vmDefinition.status.ram); vmDefinition.usedFrom = vmDefinition.status.consoleClient || ""; + vmDefinition.usedBy = vmDefinition.status.consoleUser || ""; for (const condition of vmDefinition.status.conditions) { if (condition.type === "Running") { vmDefinition.running = condition.status === "True"; 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 a21c420..f87b341 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 @@ -527,9 +527,12 @@ public class VmViewer extends FreeMarkerConlet { break; case "openConsole": if (perms.contains(Permission.ACCESS_CONSOLE)) { - var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef), - e -> openConsole(vmName, channel, model, - e.password().orElse(null))); + var user = WebConsoleUtils.userFromSession(channel.session()) + .map(ConsoleUser::getName).orElse(""); + var pwQuery + = Event.onCompletion(new GetDisplayPassword(vmDef, user), + e -> openConsole(vmName, channel, model, + e.password().orElse(null))); fire(pwQuery, vmChannel); } break; From 69507b540cb4c753616b43872e8ef6c73aded85e Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 14 Nov 2024 20:17:33 +0100 Subject: [PATCH 096/342] Improve messages. --- .../jdrupes/vmoperator/runner/qemu/ConsoleTracker.java | 8 ++++---- .../org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java index 95b748c..f2309df 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java @@ -108,8 +108,8 @@ public class ConsoleTracker extends VmDefUpdater { vmStub.updateStatus(from -> { JsonObject status = from.status(); status.addProperty("consoleClient", event.clientHost()); - updateCondition(from, status, "ConsoleConnected", - true, "Connection from " + event.clientHost(), null); + updateCondition(from, status, "ConsoleConnected", true, "Connected", + "Connection from " + event.clientHost()); return status; }); @@ -143,8 +143,8 @@ public class ConsoleTracker extends VmDefUpdater { vmStub.updateStatus(from -> { JsonObject status = from.status(); status.addProperty("consoleClient", ""); - updateCondition(from, status, "ConsoleConnected", - false, event.clientHost() + " has disconnected", null); + updateCondition(from, status, "ConsoleConnected", false, + "Disconnected", event.clientHost() + " has disconnected"); return status; }); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index f663476..0b18df0 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -191,7 +191,7 @@ public class StatusUpdater extends VmDefUpdater { if (!running) { status.addProperty("consoleClient", ""); updateCondition(from, status, "ConsoleConnected", false, - "VM has stopped", null); + "VmStopped", "The VM has been shut down"); } return status; }); From e864f677c3aab675653d0673130c7e7688c01152 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 14 Nov 2024 22:10:18 +0100 Subject: [PATCH 097/342] Allow operator to patch CR status. --- deploy/vmop-role.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/deploy/vmop-role.yaml b/deploy/vmop-role.yaml index 16c7cfb..55447e6 100644 --- a/deploy/vmop-role.yaml +++ b/deploy/vmop-role.yaml @@ -11,6 +11,12 @@ rules: - vms verbs: - '*' +- apiGroups: + - vmoperator.jdrupes.org + resources: + - vms/status + verbs: + - patch - apiGroups: - apps resources: From dc7382dc8669483e33ad4cb7efb449bea432ce36 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 15 Nov 2024 09:53:34 +0100 Subject: [PATCH 098/342] Always update console user. --- .../manager/DisplaySecretMonitor.java | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) 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 2f480a3..141c806 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 @@ -180,19 +180,7 @@ public class DisplaySecretMonitor @SuppressWarnings("PMD.StringInstantiation") public void onGetDisplaySecrets(GetDisplayPassword event, VmChannel channel) throws ApiException { - ListOptions options = new ListOptions(); - options.setLabelSelector("app.kubernetes.io/name=" + APP_NAME + "," - + "app.kubernetes.io/component=" + COMP_DISPLAY_SECRET + "," - + "app.kubernetes.io/instance=" - + event.vmDefinition().metadata().getName()); - var stubs = K8sV1SecretStub.list(client(), - event.vmDefinition().namespace(), options); - if (stubs.isEmpty()) { - return; - } - var stub = stubs.iterator().next(); - - // Valid request, update console user in status + // Update console user in status var vmStub = VmDefinitionStub.get(client(), new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), event.vmDefinition().namespace(), event.vmDefinition().name()); @@ -202,6 +190,20 @@ public class DisplaySecretMonitor return status; }); + // Look for secret + ListOptions options = new ListOptions(); + options.setLabelSelector("app.kubernetes.io/name=" + APP_NAME + "," + + "app.kubernetes.io/component=" + COMP_DISPLAY_SECRET + "," + + "app.kubernetes.io/instance=" + + event.vmDefinition().metadata().getName()); + var stubs = K8sV1SecretStub.list(client(), + event.vmDefinition().namespace(), options); + if (stubs.isEmpty()) { + // No secret means no password for this VM wanted + return; + } + var stub = stubs.iterator().next(); + // Check validity var model = stub.model().get(); @SuppressWarnings("PMD.StringInstantiation") @@ -209,6 +211,7 @@ public class DisplaySecretMonitor .get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null); if (model.getData().get(DATA_DISPLAY_PASSWORD) != null && stillValid(expiry)) { + // Fixed secret, don't touch event.setResult( new String(model.getData().get(DATA_DISPLAY_PASSWORD))); return; From 558d8f95485c66049a763cce32a096154ba563b5 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 15 Nov 2024 09:58:30 +0100 Subject: [PATCH 099/342] Fix layout. --- .../org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 708a1a3..0af656b 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 @@ -68,7 +68,7 @@ -
+ From 28df6ede159571f93690c9b0a300867aa151277a Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 15 Nov 2024 15:29:19 +0100 Subject: [PATCH 100/342] Force fixed webconsole library. --- org.jdrupes.vmoperator.manager/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index ab41391..e286f7b 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -18,7 +18,7 @@ dependencies { implementation 'org.jgrapes:org.jgrapes.http:[3.5.0,4)' implementation 'org.jgrapes:org.jgrapes.webconsole.base:[2.1.0,3)' - implementation 'org.jgrapes:org.jgrapes.webconsole.vuejs:[1.5.0,2)' + implementation 'org.jgrapes:org.jgrapes.webconsole.vuejs:[1.8.0,2)' implementation 'org.jgrapes:org.jgrapes.webconsole.rbac:[1.4.0,2)' implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.7.0,2)' implementation 'org.jgrapes:org.jgrapes.webconlet.markdowndisplay:[1.2.0,2)' From 31758b5ef107c33f029c442ef00e5748255259a0 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 15 Nov 2024 17:30:50 +0100 Subject: [PATCH 101/342] Add fallbacks for efi vars as well. --- .../resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml b/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml index 32fdf55..600f0ad 100644 --- a/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml +++ b/org.jdrupes.vmoperator.runner.qemu/resources/org/jdrupes/vmoperator/runner/qemu/defaults.yaml @@ -15,6 +15,9 @@ - "/usr/share/edk2/ovmf/OVMF_VARS.fd" - "/usr/share/edk2/x64/OVMF_VARS.fd" - "/usr/share/OVMF/OVMF_VARS.fd" + # Use 4M version as fallback (if smaller version not available) + - "/usr/share/edk2/ovmf-4m/OVMF_VARS.fd" + - "/usr/share/edk2/x64/OVMF_VARS.4m.fd" "uefi-4m": "rom": - "/usr/share/edk2/ovmf-4m/OVMF_CODE.fd" From 13cd262a47c6f83f4102073d2060295223f74619 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 16 Nov 2024 17:15:31 +0100 Subject: [PATCH 102/342] New CRD. --- deploy/crds/vmpools-crd.yaml | 59 ++++++++++++++++++++++++++++++++++++ deploy/crds/vms-crd.yaml | 7 +++++ 2 files changed, 66 insertions(+) create mode 100644 deploy/crds/vmpools-crd.yaml diff --git a/deploy/crds/vmpools-crd.yaml b/deploy/crds/vmpools-crd.yaml new file mode 100644 index 0000000..5f8414f --- /dev/null +++ b/deploy/crds/vmpools-crd.yaml @@ -0,0 +1,59 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: vmpools.vmoperator.jdrupes.org +spec: + group: vmoperator.jdrupes.org + # list of versions supported by this CustomResourceDefinition + versions: + - name: v1 + served: true + storage: true + schema: + openAPIV3Schema: + type: object + properties: + spec: + type: object + properties: + permissions: + type: array + description: >- + Defines permissions for accessing and manipulating the Pool. + items: + type: object + description: >- + Permissions can be granted to a user or to a role. + oneOf: + - required: + - user + - required: + - role + properties: + user: + type: string + role: + type: string + may: + type: array + items: + type: string + enum: + - start + - stop + - reset + - accessConsole + - "*" + default: [] + required: + - permissions + # either Namespaced or Cluster + scope: Namespaced + names: + # plural name to be used in the URL: /apis/// + plural: vmpools + # singular name to be used as an alias on the CLI and for display + singular: vmpool + # kind is normally the CamelCased singular type. Your resource manifests use this. + kind: VmPool + listKind: VmPoolList diff --git a/deploy/crds/vms-crd.yaml b/deploy/crds/vms-crd.yaml index 93c70cc..5f67b4c 100644 --- a/deploy/crds/vms-crd.yaml +++ b/deploy/crds/vms-crd.yaml @@ -1019,6 +1019,13 @@ spec: - accessConsole - "*" default: [] + pools: + type: array + description: >- + List of pools to which this VM belongs. + items: + type: string + default: [] loggingProperties: type: string description: >- From dec4c11785f0c730736095ccefc350ae9782c0b9 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 16 Nov 2024 17:33:37 +0100 Subject: [PATCH 103/342] Fix sync selection. --- .../jdrupes/vmoperator/vmviewer/VmViewer.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) 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 f87b341..b0d8502 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 @@ -123,8 +123,8 @@ public class VmViewer extends FreeMarkerConlet { private static ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule()); private Class preferredIpVersion = Inet4Address.class; - private Set syncUsers = new HashSet<>(); - private final Set syncRoles = new HashSet<>(); + private Set syncUsers = Collections.emptySet(); + private Set syncRoles = Collections.emptySet(); private boolean deleteConnectionFile = true; /** @@ -173,12 +173,19 @@ public class VmViewer extends FreeMarkerConlet { .filter(v -> v instanceof String).map(v -> (String) v) .map(Boolean::parseBoolean).orElse(true); - // Sync preview for users or roles + // Users or roles for which previews should be synchronized syncUsers = ((List>) c.getOrDefault( "syncPreviewsFor", Collections.emptyList())).stream() - .map(m -> Optional.ofNullable(m.get("user")) - .orElse(m.get("role"))) + .map(m -> m.get("user")) .filter(s -> s != null).collect(Collectors.toSet()); + logger.finest(() -> "Syncing previews for users: " + + syncUsers.toString()); + syncRoles = ((List>) c.getOrDefault( + "syncPreviewsFor", Collections.emptyList())).stream() + .map(m -> m.get("role")) + .filter(s -> s != null).collect(Collectors.toSet()); + logger.finest(() -> "Syncing previews for roles: " + + syncRoles.toString()); } catch (ClassCastException e) { logger.config("Malformed configuration: " + e.getMessage()); } From 5d90a6a8a9b4f1c8fe82982f2193bf6429b48320 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 17 Nov 2024 12:21:16 +0100 Subject: [PATCH 104/342] Move test to tc1. --- dev-example/.gitignore | 1 + dev-example/config.yaml | 4 +- dev-example/gen-pool-vm-crds.sh | 47 +++++++++++++++++++++++ dev-example/test-vm.tpl.yaml | 67 +++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 2 deletions(-) create mode 100755 dev-example/gen-pool-vm-crds.sh create mode 100644 dev-example/test-vm.tpl.yaml diff --git a/dev-example/.gitignore b/dev-example/.gitignore index 925478d..728072e 100644 --- a/dev-example/.gitignore +++ b/dev-example/.gitignore @@ -1 +1,2 @@ /test-vm-ci.yaml +/kubeconfig.yaml diff --git a/dev-example/config.yaml b/dev-example/config.yaml index af1f3b8..1c80ab8 100644 --- a/dev-example/config.yaml +++ b/dev-example/config.yaml @@ -7,8 +7,8 @@ "/Controller": namespace: vmop-dev "/Reconciler": - runnerData: - storageClassName: null + runnerDataPvc: + storageClassName: rook-cephfs loadBalancerService: labels: label1: label1 diff --git a/dev-example/gen-pool-vm-crds.sh b/dev-example/gen-pool-vm-crds.sh new file mode 100755 index 0000000..264e3ba --- /dev/null +++ b/dev-example/gen-pool-vm-crds.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +function usage() { + cat >&2 <&2 "Unknown option: $1"; exit 1;; + *) template="$1";; + esac + shift +done + +if [ -z "$template" ]; then + usage +fi + +if [ "$count" = "0" ]; then + exit 0 +fi +for number in $(seq 1 $count); do + if [ -z "$prefix" ]; then + prefix=$(basename $template .tpl.yaml) + fi + name="$prefix$number" + index=$(($number - 1)) + esh -o $destination/$name.yaml $template number=$number index=$index +done diff --git a/dev-example/test-vm.tpl.yaml b/dev-example/test-vm.tpl.yaml new file mode 100644 index 0000000..aa6f3d1 --- /dev/null +++ b/dev-example/test-vm.tpl.yaml @@ -0,0 +1,67 @@ +apiVersion: "vmoperator.jdrupes.org/v1" +kind: VirtualMachine +metadata: + namespace: vmop-dev + name: test-vm<%= ${number} %> + annotations: + argocd.argoproj.io/sync-wave: "20" + +spec: + image: +# repository: docker-registry.lan.mnl.de +# path: vmoperator/org.jdrupes.vmoperator.runner.qemu-arch +# pullPolicy: Always +# repository: ghcr.io +# path: mnlipp/org.jdrupes.vmoperator.runner.qemu-alpine +# version: "3.0.0" + source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:testing + pullPolicy: Always + + permissions: + - role: admin + may: + - "*" + - user: test + may: + - accessConsole + + guestShutdownStops: true + + cloudInit: {} + + vm: + # state: Running + bootMenu: true + maximumCpus: 4 + currentCpus: 2 + maximumRam: 4Gi + currentRam: 3Gi + + networks: + # No bridge on TC1 + # - tap: {} + - user: {} + + disks: + - volumeClaimTemplate: + metadata: + name: system + spec: + storageClassName: ceph-rbd3slow + dataSource: + name: test-vm-snapshot-1 + kind: VolumeSnapshot + apiGroup: snapshot.storage.k8s.io + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 40Gi + - cdrom: + image: "" + # image: https://download.fedoraproject.org/pub/fedora/linux/releases/38/Workstation/x86_64/iso/Fedora-Workstation-Live-x86_64-38-1.6.iso + + display: + spice: + port: <%= $((5910 + number)) %> + server: 192.168.179.20 From e7da41f8388949a2418193e1e7f652ba15e84096 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 17 Nov 2024 13:20:20 +0100 Subject: [PATCH 105/342] Fix summary evaluation. --- .../src/org/jdrupes/vmoperator/vmconlet/VmConlet.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/VmConlet.java b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/VmConlet.java index 69418af..7244f56 100644 --- a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/VmConlet.java +++ b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/VmConlet.java @@ -329,7 +329,7 @@ public class VmConlet extends FreeMarkerConlet { .map(r -> Quantity.fromString(r).getNumber().toBigInteger()) .orElse(BigInteger.ZERO)); summary.runningVms - = vmDef.>> fromStatus("conditions") + += vmDef.>> fromStatus("conditions") .orElse(Collections.emptyList()).stream() .filter(cond -> DataPath.get(cond, "type") .map(t -> "Running".equals(t)).orElse(false) From 043666a9328bce525a014f94d9d7e40182daf2e5 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 17 Nov 2024 15:08:22 +0100 Subject: [PATCH 106/342] Generate test VMs. --- dev-example/.gitignore | 1 + dev-example/test-vm-snapshot.yaml | 10 ++++++++++ dev-example/test-vm.tpl.yaml | 6 +++--- 3 files changed, 14 insertions(+), 3 deletions(-) create mode 100644 dev-example/test-vm-snapshot.yaml diff --git a/dev-example/.gitignore b/dev-example/.gitignore index 728072e..16e0d04 100644 --- a/dev-example/.gitignore +++ b/dev-example/.gitignore @@ -1,2 +1,3 @@ /test-vm-ci.yaml /kubeconfig.yaml +/crds/ diff --git a/dev-example/test-vm-snapshot.yaml b/dev-example/test-vm-snapshot.yaml new file mode 100644 index 0000000..fd60a25 --- /dev/null +++ b/dev-example/test-vm-snapshot.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshot +metadata: + namespace: vmop-dev + name: test-vm-system-disk-snapshot +spec: + volumeSnapshotClassName: csi-rbdplugin-snapclass + source: + persistentVolumeClaimName: test-vm-system-disk diff --git a/dev-example/test-vm.tpl.yaml b/dev-example/test-vm.tpl.yaml index aa6f3d1..6d8a89c 100644 --- a/dev-example/test-vm.tpl.yaml +++ b/dev-example/test-vm.tpl.yaml @@ -27,7 +27,8 @@ spec: guestShutdownStops: true - cloudInit: {} + cloudInit: + metaData: {} vm: # state: Running @@ -49,7 +50,7 @@ spec: spec: storageClassName: ceph-rbd3slow dataSource: - name: test-vm-snapshot-1 + name: test-vm-system-disk-snapshot kind: VolumeSnapshot apiGroup: snapshot.storage.k8s.io accessModes: @@ -64,4 +65,3 @@ spec: display: spice: port: <%= $((5910 + number)) %> - server: 192.168.179.20 From 4690b897e959629185c44dc7b080510147ee4356 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 17 Nov 2024 16:32:55 +0100 Subject: [PATCH 107/342] Adapt to changed timestamp format. --- .../jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts index cfda2de..01bd897 100644 --- a/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts +++ b/org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts @@ -204,8 +204,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmconlet.VmConlet", "summarySeries", function(_conletId: string, series: any[]) { chartData.clear(); for (const entry of series) { - chartData.push(new Date(entry.time.epochSecond * 1000 - + entry.time.nano / 1000000), + chartData.push(new Date(entry.time * 1000), entry.values[0], entry.values[1]); } chartDateUpdate.value = new Date(); From 00adeba62521d263add55311885b5e6c70422e15 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 19 Nov 2024 17:10:55 +0100 Subject: [PATCH 108/342] Add pool manager. --- .../jdrupes/vmoperator/common/Constants.java | 3 + .../org/jdrupes/vmoperator/common/VmPool.java | 164 +++++++++++++++ .../manager/events/VmPoolChanged.java | 88 ++++++++ org.jdrupes.vmoperator.manager/build.gradle | 1 + .../vmoperator/manager/Controller.java | 1 + .../vmoperator/manager/PoolManager.java | 191 ++++++++++++++++++ 6 files changed, 448 insertions(+) create mode 100644 org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java create mode 100644 org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/VmPoolChanged.java create mode 100644 org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/Constants.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/Constants.java index 150bb3b..5837264 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/Constants.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/Constants.java @@ -38,4 +38,7 @@ public class Constants { /** The Constant VM_OP_KIND_VM. */ public static final String VM_OP_KIND_VM = "VirtualMachine"; + + /** The Constant VM_OP_KIND_VM_POOL. */ + public static final String VM_OP_KIND_VM_POOL = "VmPool"; } diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java new file mode 100644 index 0000000..aaa2746 --- /dev/null +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java @@ -0,0 +1,164 @@ +/* + * 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.common; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Represents a VM pool. + */ +@SuppressWarnings({ "PMD.DataClass" }) +public class VmPool { + + private String name; + private List permissions = Collections.emptyList(); + private final Set vms + = Collections.synchronizedSet(new HashSet<>()); + + /** + * Returns the name. + * + * @return the name + */ + public String name() { + return name; + } + + /** + * Sets the name. + * + * @param name the name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * @return the permissions + */ + public List permissions() { + return permissions; + } + + /** + * Sets the permissions. + * + * @param permissions the permissions to set + */ + public void setPermissions(List permissions) { + this.permissions = permissions; + } + + /** + * Returns the VM names. + * + * @return the vms + */ + public Set vms() { + return vms; + } + + @Override + @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") + public String toString() { + StringBuilder builder = new StringBuilder(50); + builder.append("VmPool [name=").append(name).append(", permissions=") + .append(permissions).append(", vms="); + if (vms.size() <= 3) { + builder.append(vms); + } else { + builder.append('['); + vms.stream().limit(3).map(s -> s + ",").forEach(builder::append); + builder.append("...]"); + } + builder.append(']'); + return builder.toString(); + } + + /** + * A permission grant to a user or role. + * + * @param user the user + * @param role the role + * @param may the may + */ + public record Grant(String user, String role, Set may) { + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + if (user != null) { + builder.append("User ").append(user); + } else { + builder.append("Role ").append(role); + } + builder.append(" may=").append(may).append(']'); + return builder.toString(); + } + } + + /** + * Permissions for accessing and manipulating the pool. + */ + public enum Permission { + START("start"), STOP("stop"), RESET("reset"), + ACCESS_CONSOLE("accessConsole"); + + @SuppressWarnings("PMD.UseConcurrentHashMap") + private static Map reprs = new HashMap<>(); + + static { + for (var value : EnumSet.allOf(Permission.class)) { + reprs.put(value.repr, value); + } + } + + private final String repr; + + Permission(String repr) { + this.repr = repr; + } + + /** + * Create permission from representation in CRD. + * + * @param value the value + * @return the permission + */ + @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") + public static Set parse(String value) { + if ("*".equals(value)) { + return EnumSet.allOf(Permission.class); + } + return Set.of(reprs.get(value)); + } + + @Override + public String toString() { + return repr; + } + } + +} diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/VmPoolChanged.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/VmPoolChanged.java new file mode 100644 index 0000000..0c506a1 --- /dev/null +++ b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/VmPoolChanged.java @@ -0,0 +1,88 @@ +/* + * 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.manager.events; + +import org.jdrupes.vmoperator.common.VmPool; +import org.jgrapes.core.Channel; +import org.jgrapes.core.Components; +import org.jgrapes.core.Event; + +/** + * Indicates a change in a pool configuration. + */ +@SuppressWarnings("PMD.DataClass") +public class VmPoolChanged extends Event { + + private final VmPool vmPool; + private final boolean deleted; + + /** + * Instantiates a new VM changed event. + * + * @param pool the pool + * @param deleted true, if the pool was deleted + */ + public VmPoolChanged(VmPool pool, boolean deleted) { + vmPool = pool; + this.deleted = deleted; + } + + /** + * Instantiates a new VM changed event for an existing pool. + * + * @param pool the pool + */ + public VmPoolChanged(VmPool pool) { + this(pool, false); + } + + /** + * Returns the VM pool. + * + * @return the vm pool + */ + public VmPool vmPool() { + return vmPool; + } + + /** + * Pool has been deleted. + * + * @return true, if successful + */ + public boolean deleted() { + return deleted; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(30); + builder.append(Components.objectName(this)) + .append(" ["); + if (deleted) { + builder.append("Deleted: "); + } + builder.append(vmPool); + if (channels() != null) { + builder.append(", channels=").append(Channel.toString(channels())); + } + builder.append(']'); + return builder.toString(); + } +} diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index e286f7b..d3d80cb 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -33,6 +33,7 @@ dependencies { runtimeOnly project(':org.jdrupes.vmoperator.vmconlet') runtimeOnly project(':org.jdrupes.vmoperator.vmviewer') + runtimeOnly project(':org.jdrupes.vmoperator.poolaccess') } application { 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 effc938..d847785 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 @@ -106,6 +106,7 @@ public class Controller extends Component { // to access the VM's console. Might change in the future. // attach(new ServiceMonitor(channel()).channelManager(chanMgr)); attach(new Reconciler(channel())); + attach(new PoolManager(channel())); } /** diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java new file mode 100644 index 0000000..f47c569 --- /dev/null +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java @@ -0,0 +1,191 @@ +/* + * VM-Operator + * Copyright (C) 2023,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; + +import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.util.Watch; +import java.io.IOException; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.locks.ReentrantLock; +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.K8sDynamicModels; +import org.jdrupes.vmoperator.common.K8sDynamicStub; +import org.jdrupes.vmoperator.common.K8sObserver.ResponseType; +import org.jdrupes.vmoperator.common.VmPool; +import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM_POOL; +import org.jdrupes.vmoperator.manager.events.VmDefChanged; +import org.jdrupes.vmoperator.manager.events.VmPoolChanged; +import org.jdrupes.vmoperator.util.GsonPtr; +import org.jgrapes.core.Channel; +import org.jgrapes.core.annotation.Handler; + +/** + * Watches for changes of VM pools. + */ +@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports" }) +public class PoolManager extends + AbstractMonitor { + + private final ReentrantLock pendingLock = new ReentrantLock(); + private final Map> pending = new ConcurrentHashMap<>(); + private final Map pools = new ConcurrentHashMap<>(); + + /** + * Instantiates a new VM pool manager. + * + * @param componentChannel the component channel + * @param channelManager the channel manager + */ + public PoolManager(Channel componentChannel) { + super(componentChannel, K8sDynamicModel.class, + K8sDynamicModels.class); + } + + @Override + protected void prepareMonitoring() throws IOException, ApiException { + client(new K8sClient()); + + // Get all our API versions + var ctx = K8s.context(client(), VM_OP_GROUP, "", VM_OP_KIND_VM_POOL); + if (ctx.isEmpty()) { + logger.severe(() -> "Cannot get CRD context."); + return; + } + context(ctx.get()); + } + + @Override + protected void handleChange(K8sClient client, + Watch.Response response) { + + var type = ResponseType.valueOf(response.type); + var poolName = response.object.metadata().getName(); + + // When pool is deleted, save VMs in pending + if (type == ResponseType.DELETED) { + try { + pendingLock.lock(); + Optional.ofNullable(pools.get(poolName)).ifPresent( + p -> { + pending.computeIfAbsent(poolName, k -> Collections + .synchronizedSet(new HashSet<>())).addAll(p.vms()); + pools.remove(poolName); + fire(new VmPoolChanged(p, true)); + }); + } finally { + pendingLock.unlock(); + } + return; + } + + // Get full definition + var poolModel = response.object; + if (poolModel.data() == null) { + // ADDED event does not provide data, see + // https://github.com/kubernetes-client/java/issues/3215 + try { + poolModel = K8sDynamicStub.get(client(), context(), namespace(), + poolModel.metadata().getName()).model().orElse(null); + } catch (ApiException e) { + return; + } + } + + // Convert to VM pool + var vmPool = client().getJSON().getGson().fromJson( + GsonPtr.to(poolModel.data()).to("spec").get(), + VmPool.class); + V1ObjectMeta metadata = response.object.getMetadata(); + vmPool.setName(metadata.getName()); + + // If modified, merge changes + if (type == ResponseType.MODIFIED && pools.containsKey(poolName)) { + pools.get(poolName).setPermissions(vmPool.permissions()); + return; + } + + // Add new pool + try { + pendingLock.lock(); + Optional.ofNullable(pending.get(poolName)).ifPresent(s -> { + vmPool.vms().addAll(s); + }); + pending.remove(poolName); + pools.put(poolName, vmPool); + fire(new VmPoolChanged(vmPool)); + } finally { + pendingLock.unlock(); + } + } + + /** + * Track VM definition changes. + * + * @param event the event + */ + @Handler + public void onVmDefChanged(VmDefChanged event) { + String vmName = event.vmDefinition().name(); + switch (event.type()) { + case ADDED: + try { + pendingLock.lock(); + event.vmDefinition().> fromSpec("pools") + .orElse(Collections.emptyList()).stream().forEach(p -> { + if (pools.containsKey(p)) { + pools.get(p).vms().add(vmName); + } else { + pending.computeIfAbsent(p, k -> Collections + .synchronizedSet(new HashSet<>())).add(vmName); + } + fire(new VmPoolChanged(pools.get(p))); + }); + } finally { + pendingLock.unlock(); + } + break; + case DELETED: + try { + pendingLock.lock(); + pools.values().stream().forEach(p -> { + if (p.vms().remove(vmName)) { + fire(new VmPoolChanged(p)); + } + }); + // Should not be necessary, but just in case + pending.values().stream().forEach(s -> s.remove(vmName)); + } finally { + pendingLock.unlock(); + } + break; + default: + break; + } + } +} From 27f983c18d9f51668b9e7c619ab5bc6248e2a268 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 12:50:25 +0100 Subject: [PATCH 109/342] Rename vmviewer to vmaccess. --- org.jdrupes.vmoperator.manager/build.gradle | 2 +- .../.checkstyle | 0 .../.eclipse-pmd | 0 .../.eslintignore | 0 .../.eslintrc.json | 0 .../.gitignore | 0 .../org.eclipse.buildship.core.prefs | 0 .../org.eclipse.core.resources.prefs | 0 .../.settings/org.eclipse.core.runtime.prefs | 0 .../.settings/org.eclipse.jdt.ui.prefs | 0 .../build.gradle | 0 .../package.json | 0 ...pes.webconsole.base.ConletComponentFactory | 1 + .../vmaccess/VmAccess-confirmReset.ftl.html | 4 +-- .../vmaccess/VmAccess-edit.ftl.html | 6 ++-- .../vmaccess/VmAccess-l10nBundles.ftl.js | 0 .../vmaccess/VmAccess-preview.ftl.html | 4 +-- .../vmoperator/vmaccess}/computer-in-use.svg | 0 .../vmoperator/vmaccess}/computer-off.svg | 0 .../jdrupes/vmoperator/vmaccess}/computer.svg | 0 .../vmoperator/vmaccess}/l10n.properties | 2 +- .../vmoperator/vmaccess}/l10n_de.properties | 2 +- .../vmoperator/vmaccess}/l10n_en.properties | 0 .../vmoperator/vmaccess}/reset-icon.svg | 0 .../rollup.config.mjs | 4 +-- .../jdrupes/vmoperator/vmaccess/VmAccess.java | 24 ++++++------- .../vmoperator/vmaccess/VmAccessFactory.java | 10 +++--- .../vmaccess/browser/VmAccess-functions.ts | 32 +++++++++--------- .../vmaccess/browser/VmAccess-style.scss | 10 +++--- .../vmaccess}/browser/l10nBundles-stub.d.ts | 0 .../vmoperator/vmaccess}/package-info.java | 4 +-- .../tsconfig.json | 2 +- ...pes.webconsole.base.ConletComponentFactory | 1 - settings.gradle | 2 ++ ...iewer-preview.png => VmAccess-preview.png} | Bin webpages/vm-operator/user-gui.md | 4 +-- 36 files changed, 58 insertions(+), 56 deletions(-) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.checkstyle (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.eclipse-pmd (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.eslintignore (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.eslintrc.json (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.gitignore (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.settings/org.eclipse.buildship.core.prefs (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.settings/org.eclipse.core.resources.prefs (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.settings/org.eclipse.core.runtime.prefs (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/.settings/org.eclipse.jdt.ui.prefs (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/build.gradle (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/package.json (100%) create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory rename org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-confirmReset.ftl.html => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-confirmReset.ftl.html (91%) rename org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-edit.ftl.html => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html (73%) rename org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-l10nBundles.ftl.js => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-l10nBundles.ftl.js (100%) rename org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-preview.ftl.html => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-preview.ftl.html (59%) rename {org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess}/computer-in-use.svg (100%) rename {org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess}/computer-off.svg (100%) rename {org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess}/computer.svg (100%) rename {org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess}/l10n.properties (86%) rename {org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess}/l10n_de.properties (93%) rename {org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess}/l10n_en.properties (100%) rename {org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess}/reset-icon.svg (100%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/rollup.config.mjs (92%) rename org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java => org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java (97%) rename org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewerFactory.java => org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccessFactory.java (85%) rename org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-functions.ts => org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts (91%) rename org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss => org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-style.scss (87%) rename {org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess}/browser/l10nBundles-stub.d.ts (100%) rename {org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer => org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess}/package-info.java (89%) rename {org.jdrupes.vmoperator.vmviewer => org.jdrupes.vmoperator.vmaccess}/tsconfig.json (92%) delete mode 100644 org.jdrupes.vmoperator.vmviewer/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory rename webpages/vm-operator/{VmViewer-preview.png => VmAccess-preview.png} (100%) diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index d3d80cb..f5ffe2c 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -31,8 +31,8 @@ dependencies { runtimeOnly 'org.slf4j:slf4j-jdk14:[2.0.7,3)' runtimeOnly 'org.apache.logging.log4j:log4j-to-jul:2.20.0' + runtimeOnly project(':org.jdrupes.vmoperator.vmaccess') runtimeOnly project(':org.jdrupes.vmoperator.vmconlet') - runtimeOnly project(':org.jdrupes.vmoperator.vmviewer') runtimeOnly project(':org.jdrupes.vmoperator.poolaccess') } diff --git a/org.jdrupes.vmoperator.vmviewer/.checkstyle b/org.jdrupes.vmoperator.vmaccess/.checkstyle similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.checkstyle rename to org.jdrupes.vmoperator.vmaccess/.checkstyle diff --git a/org.jdrupes.vmoperator.vmviewer/.eclipse-pmd b/org.jdrupes.vmoperator.vmaccess/.eclipse-pmd similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.eclipse-pmd rename to org.jdrupes.vmoperator.vmaccess/.eclipse-pmd diff --git a/org.jdrupes.vmoperator.vmviewer/.eslintignore b/org.jdrupes.vmoperator.vmaccess/.eslintignore similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.eslintignore rename to org.jdrupes.vmoperator.vmaccess/.eslintignore diff --git a/org.jdrupes.vmoperator.vmviewer/.eslintrc.json b/org.jdrupes.vmoperator.vmaccess/.eslintrc.json similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.eslintrc.json rename to org.jdrupes.vmoperator.vmaccess/.eslintrc.json diff --git a/org.jdrupes.vmoperator.vmviewer/.gitignore b/org.jdrupes.vmoperator.vmaccess/.gitignore similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.gitignore rename to org.jdrupes.vmoperator.vmaccess/.gitignore diff --git a/org.jdrupes.vmoperator.vmviewer/.settings/org.eclipse.buildship.core.prefs b/org.jdrupes.vmoperator.vmaccess/.settings/org.eclipse.buildship.core.prefs similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.settings/org.eclipse.buildship.core.prefs rename to org.jdrupes.vmoperator.vmaccess/.settings/org.eclipse.buildship.core.prefs diff --git a/org.jdrupes.vmoperator.vmviewer/.settings/org.eclipse.core.resources.prefs b/org.jdrupes.vmoperator.vmaccess/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.settings/org.eclipse.core.resources.prefs rename to org.jdrupes.vmoperator.vmaccess/.settings/org.eclipse.core.resources.prefs diff --git a/org.jdrupes.vmoperator.vmviewer/.settings/org.eclipse.core.runtime.prefs b/org.jdrupes.vmoperator.vmaccess/.settings/org.eclipse.core.runtime.prefs similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.settings/org.eclipse.core.runtime.prefs rename to org.jdrupes.vmoperator.vmaccess/.settings/org.eclipse.core.runtime.prefs diff --git a/org.jdrupes.vmoperator.vmviewer/.settings/org.eclipse.jdt.ui.prefs b/org.jdrupes.vmoperator.vmaccess/.settings/org.eclipse.jdt.ui.prefs similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/.settings/org.eclipse.jdt.ui.prefs rename to org.jdrupes.vmoperator.vmaccess/.settings/org.eclipse.jdt.ui.prefs diff --git a/org.jdrupes.vmoperator.vmviewer/build.gradle b/org.jdrupes.vmoperator.vmaccess/build.gradle similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/build.gradle rename to org.jdrupes.vmoperator.vmaccess/build.gradle diff --git a/org.jdrupes.vmoperator.vmviewer/package.json b/org.jdrupes.vmoperator.vmaccess/package.json similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/package.json rename to org.jdrupes.vmoperator.vmaccess/package.json diff --git a/org.jdrupes.vmoperator.vmaccess/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory b/org.jdrupes.vmoperator.vmaccess/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory new file mode 100644 index 0000000..ec5cf30 --- /dev/null +++ b/org.jdrupes.vmoperator.vmaccess/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory @@ -0,0 +1 @@ +org.jdrupes.vmoperator.vmaccess.VmAccessFactory diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-confirmReset.ftl.html b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-confirmReset.ftl.html similarity index 91% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-confirmReset.ftl.html rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-confirmReset.ftl.html index f7e3840..d7b9405 100644 --- a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-confirmReset.ftl.html +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-confirmReset.ftl.html @@ -1,9 +1,9 @@
+ class="jdrupes-vmoperator-vmaccess jdrupes-vmoperator-vmaccess-confirm-reset">

${_("confirmResetMsg")}

+ onclick="orgJDrupesVmOperatorVmAccess.confirmReset('${conletType}', '${conletId}')"> diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-edit.ftl.html b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html similarity index 73% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-edit.ftl.html rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html index e86d9db..ba61399 100644 --- a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-edit.ftl.html +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html @@ -1,7 +1,7 @@

diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-l10nBundles.ftl.js b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-l10nBundles.ftl.js similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-l10nBundles.ftl.js rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-l10nBundles.ftl.js diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-preview.ftl.html b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-preview.ftl.html similarity index 59% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-preview.ftl.html rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-preview.ftl.html index c034504..57693ea 100644 --- a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/VmViewer-preview.ftl.html +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-preview.ftl.html @@ -1,7 +1,7 @@
diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/computer-in-use.svg similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-in-use.svg rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/computer-in-use.svg diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-off.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/computer-off.svg similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer-off.svg rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/computer-off.svg diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/computer.svg similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/computer.svg rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/computer.svg diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/l10n.properties b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties similarity index 86% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/l10n.properties rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties index 05309d6..d755e7a 100644 --- a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/l10n.properties +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties @@ -1,4 +1,4 @@ -conletName = VM Console +conletName = VM Access okayLabel = Apply and Close diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/l10n_de.properties b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties similarity index 93% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/l10n_de.properties rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties index 5226cc3..bcdc332 100644 --- a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/l10n_de.properties +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties @@ -1,4 +1,4 @@ -conletName = VM-Konsole +conletName = VM-Zugriff okayLabel = Anwenden und Schließen Select\ VM = VM auswählen diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/l10n_en.properties b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_en.properties similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/l10n_en.properties rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_en.properties diff --git a/org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/reset-icon.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/reset-icon.svg similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/resources/org/jdrupes/vmoperator/vmviewer/reset-icon.svg rename to org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/reset-icon.svg diff --git a/org.jdrupes.vmoperator.vmviewer/rollup.config.mjs b/org.jdrupes.vmoperator.vmaccess/rollup.config.mjs similarity index 92% rename from org.jdrupes.vmoperator.vmviewer/rollup.config.mjs rename to org.jdrupes.vmoperator.vmaccess/rollup.config.mjs index f00a51f..ab1aae9 100644 --- a/org.jdrupes.vmoperator.vmviewer/rollup.config.mjs +++ b/org.jdrupes.vmoperator.vmaccess/rollup.config.mjs @@ -1,8 +1,8 @@ import typescript from 'rollup-plugin-typescript2'; import postcss from 'rollup-plugin-postcss'; -let packagePath = "org/jdrupes/vmoperator/vmviewer"; -let baseName = "VmViewer" +let packagePath = "org/jdrupes/vmoperator/vmaccess"; +let baseName = "VmAccess" let module = "build/generated/resources/" + packagePath + "/" + baseName + "-functions.js"; diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java similarity index 97% rename from org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java rename to org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index b0d8502..b323084 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewer.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.jdrupes.vmoperator.vmviewer; +package org.jdrupes.vmoperator.vmaccess; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonProperty; @@ -89,7 +89,7 @@ import org.jgrapes.webconsole.base.events.UpdateConletType; import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet; /** - * The Class VmViewer. The component supports the following + * The Class {@link VmAccess}. The component supports the following * configuration properties: * * * `displayResource`: a map with the following entries: @@ -107,13 +107,13 @@ import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet; */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports", "PMD.CouplingBetweenObjects", "PMD.GodClass", "PMD.TooManyMethods" }) -public class VmViewer extends FreeMarkerConlet { +public class VmAccess extends FreeMarkerConlet { private static final String VM_NAME_PROPERTY = "vmName"; private static final String RENDERED - = VmViewer.class.getName() + ".rendered"; + = VmAccess.class.getName() + ".rendered"; private static final String PENDING - = VmViewer.class.getName() + ".pending"; + = VmAccess.class.getName() + ".pending"; private static final Set MODES = RenderMode.asSet( RenderMode.Preview, RenderMode.Edit); private static final Set MODES_FOR_GENERATED = RenderMode.asSet( @@ -140,7 +140,7 @@ public class VmViewer extends FreeMarkerConlet { * on by default and that {@link Manager#fire(Event, Channel...)} * sends the event to */ - public VmViewer(Channel componentChannel) { + public VmAccess(Channel componentChannel) { super(componentChannel); } @@ -222,7 +222,7 @@ public class VmViewer extends FreeMarkerConlet { .addRenderMode(RenderMode.Preview) .addScript(new ScriptResource().setScriptType("module") .setScriptUri(event.renderSupport().conletResource( - type(), "VmViewer-functions.js")))); + type(), "VmAccess-functions.js")))); channel.session().put(RENDERED, new HashSet<>()); } @@ -259,7 +259,7 @@ public class VmViewer extends FreeMarkerConlet { foundMissing = true; } fire(new AddConletRequest(event.event().event().renderSupport(), - VmViewer.class.getName(), + VmAccess.class.getName(), RenderMode.asSet(RenderMode.Preview)) .addProperty(VM_NAME_PROPERTY, vmName), connection); @@ -283,7 +283,7 @@ public class VmViewer extends FreeMarkerConlet { private String storagePath(Session session, String conletId) { return "/" + WebConsoleUtils.userFromSession(session) .map(ConsoleUser::getName).orElse("") - + "/" + VmViewer.class.getName() + "/" + conletId; + + "/" + VmAccess.class.getName() + "/" + conletId; } @Override @@ -365,7 +365,7 @@ public class VmViewer extends FreeMarkerConlet { // Render Template tpl - = freemarkerConfig().getTemplate("VmViewer-preview.ftl.html"); + = freemarkerConfig().getTemplate("VmAccess-preview.ftl.html"); channel.respond(new RenderConlet(type(), conletId, processTemplate(event, tpl, fmModel(event, channel, conletId, model))) @@ -383,7 +383,7 @@ public class VmViewer extends FreeMarkerConlet { } if (event.renderAs().contains(RenderMode.Edit)) { Template tpl = freemarkerConfig() - .getTemplate("VmViewer-edit.ftl.html"); + .getTemplate("VmAccess-edit.ftl.html"); var fmModel = fmModel(event, channel, conletId, model); fmModel.put("vmNames", accessibleVms(channel)); channel.respond(new OpenModalDialog(type(), conletId, @@ -633,7 +633,7 @@ public class VmViewer extends FreeMarkerConlet { ResourceBundle resourceBundle) throws TemplateNotFoundException, MalformedTemplateNameException, ParseException, IOException { Template tpl = freemarkerConfig() - .getTemplate("VmViewer-confirmReset.ftl.html"); + .getTemplate("VmAccess-confirmReset.ftl.html"); channel.respond(new OpenModalDialog(type(), model.getConletId(), processTemplate(event, tpl, fmModel(event, channel, model.getConletId(), model))) diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewerFactory.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccessFactory.java similarity index 85% rename from org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewerFactory.java rename to org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccessFactory.java index 6748f47..5140056 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/VmViewerFactory.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccessFactory.java @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.jdrupes.vmoperator.vmviewer; +package org.jdrupes.vmoperator.vmaccess; import java.util.Map; import java.util.Optional; @@ -25,9 +25,9 @@ import org.jgrapes.core.ComponentType; import org.jgrapes.webconsole.base.ConletComponentFactory; /** - * The factory service for {@link VmViewer}s. + * The factory service for {@link VmAccess}s. */ -public class VmViewerFactory implements ConletComponentFactory { +public class VmAccessFactory implements ConletComponentFactory { /* * (non-Javadoc) @@ -36,7 +36,7 @@ public class VmViewerFactory implements ConletComponentFactory { */ @Override public Class componentType() { - return VmViewer.class; + return VmAccess.class; } /* @@ -48,7 +48,7 @@ public class VmViewerFactory implements ConletComponentFactory { @Override public Optional create(Channel componentChannel, Map properties) { - return Optional.of(new VmViewer(componentChannel)); + return Optional.of(new VmAccess(componentChannel)); } } diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-functions.ts b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts similarity index 91% rename from org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-functions.ts rename to org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts index 42c7d10..fb52353 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-functions.ts +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts @@ -24,12 +24,12 @@ import JgwcPlugin, { JGWC } from "jgwc"; import { provideApi, getApi } from "aash-plugin"; import l10nBundles from "l10nBundles"; -import "./VmViewer-style.scss"; +import "./VmAccess-style.scss"; // For global access declare global { interface Window { - orgJDrupesVmOperatorVmViewer: { + orgJDrupesVmOperatorVmAccess: { initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void, initEdit?: (viewDom: HTMLElement, isUpdate: boolean) => void, applyEdit?: (viewDom: HTMLElement, apply: boolean) => void, @@ -38,7 +38,7 @@ declare global { } } -window.orgJDrupesVmOperatorVmViewer = {}; +window.orgJDrupesVmOperatorVmAccess = {}; interface Api { /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -51,7 +51,7 @@ const localize = (key: string) => { l10nBundles, JGWC.lang(), key); }; -window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, +window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement, _isUpdate: boolean) => { const app = createApp({ setup(_props: object) { @@ -107,7 +107,7 @@ window.orgJDrupesVmOperatorVmViewer.initPreview = (previewDom: HTMLElement, :title="localize('Open console')"> -
diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts index d96ad65..6ab15b8 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts @@ -113,7 +113,6 @@ window.orgJDrupesVmOperatorVmMgmt.initView = (viewDom: HTMLElement, ["currentRam", "currentRam"], ["nodeName", "nodeName"], ["assignedTo", "assignedTo"], - ["usedFrom", "usedFrom"], ["usedBy", "usedBy"] ], { sortKey: "name", diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss index e02fe24..607b0c5 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss @@ -78,6 +78,8 @@ padding-left: 1em; table { + display: inline; + td:nth-child(2) { min-width: 7em; From fb69c1d793c8faa7063b34d91bd4d807c4a4ebe3 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 23 Jan 2025 18:25:37 +0100 Subject: [PATCH 137/342] Minor style change. --- .../src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss index 607b0c5..9d7721a 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss @@ -75,7 +75,7 @@ } td.details { - padding-left: 1em; + padding-left: 0; table { display: inline; From 9318b1279abbe48a229d614be2f3a4d86684eacc Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 23 Jan 2025 21:17:06 +0100 Subject: [PATCH 138/342] Move jackson to base library. --- org.jdrupes.vmoperator.common/build.gradle | 1 + org.jdrupes.vmoperator.manager.events/build.gradle | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.common/build.gradle b/org.jdrupes.vmoperator.common/build.gradle index 07877fe..e72cb14 100644 --- a/org.jdrupes.vmoperator.common/build.gradle +++ b/org.jdrupes.vmoperator.common/build.gradle @@ -13,4 +13,5 @@ dependencies { api 'org.jgrapes:org.jgrapes.core:[1.22.1,2)' api 'io.kubernetes:client-java:[19.0.0,20.0.0)' api 'org.yaml:snakeyaml' + api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:[2.16.1,3]' } diff --git a/org.jdrupes.vmoperator.manager.events/build.gradle b/org.jdrupes.vmoperator.manager.events/build.gradle index cfdd79e..bb4b8d8 100644 --- a/org.jdrupes.vmoperator.manager.events/build.gradle +++ b/org.jdrupes.vmoperator.manager.events/build.gradle @@ -10,5 +10,4 @@ plugins { dependencies { api project(':org.jdrupes.vmoperator.common') - api 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:[2.16.1,3]' } From a5ddf6ac977c2301569bd757898c8d65a1823684 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 13:32:00 +0100 Subject: [PATCH 139/342] Avoid updating immutable fields. --- .../vmoperator/manager/PvcReconciler.java | 43 +++++++++++++- .../org/jdrupes/vmoperator/util/GsonPtr.java | 58 ++++++++++++++++++- 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java index d044199..4ced1b1 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java @@ -18,6 +18,7 @@ package org.jdrupes.vmoperator.manager; +import com.google.gson.JsonObject; import freemarker.core.ParseException; import freemarker.template.Configuration; import freemarker.template.MalformedTemplateNameException; @@ -25,6 +26,7 @@ import freemarker.template.TemplateException; import freemarker.template.TemplateNotFoundException; import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject; import io.kubernetes.client.util.generic.dynamic.Dynamics; import io.kubernetes.client.util.generic.options.ListOptions; import io.kubernetes.client.util.generic.options.PatchOptions; @@ -41,6 +43,7 @@ import org.jdrupes.vmoperator.common.K8sV1PvcStub; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.util.DataPath; +import org.jdrupes.vmoperator.util.GsonPtr; import org.yaml.snakeyaml.LoaderOptions; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.SafeConstructor; @@ -179,17 +182,51 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; var pvcDef = Dynamics.newFromYaml( new Yaml(new SafeConstructor(new LoaderOptions())), out.toString()); - // Do apply changes + // Apply changes var pvcStub = K8sV1PvcStub.get(channel.client(), vmDef.namespace(), pvcName); + var pvc = pvcStub.model(); + if (pvc.isEmpty() + || !"Bound".equals(pvc.get().getStatus().getPhase())) { + // Does not exist or isn't bound, use apply + PatchOptions opts = new PatchOptions(); + opts.setForce(true); + opts.setFieldManager("kubernetes-java-kubectl-apply"); + if (pvcStub.patch(V1Patch.PATCH_FORMAT_APPLY_YAML, + new V1Patch(channel.client().getJSON().serialize(pvcDef)), opts) + .isEmpty()) { + logger.warning( + () -> "Could not patch pvc for " + pvcStub.name()); + } + return; + } + + // If bound, use json merge, omitting immutable fields + var spec = GsonPtr.to(pvcDef.getRaw()).to("spec"); + spec.removeExcept("volumeAttributesClassName", "resources"); + spec.access("resources").ifPresent(p -> p.removeExcept("requests")); PatchOptions opts = new PatchOptions(); - opts.setForce(true); opts.setFieldManager("kubernetes-java-kubectl-apply"); - if (pvcStub.patch(V1Patch.PATCH_FORMAT_APPLY_YAML, + if (pvcStub.patch(V1Patch.PATCH_FORMAT_JSON_MERGE_PATCH, new V1Patch(channel.client().getJSON().serialize(pvcDef)), opts) .isEmpty()) { logger.warning( () -> "Could not patch pvc for " + pvcStub.name()); } } + + @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") + private void removeImmutable(DynamicKubernetesObject pvcDef) { + var spec = GsonPtr.to(pvcDef.getRaw()).to("spec").get(JsonObject.class); + for (var itr = spec.entrySet().iterator(); itr.hasNext();) { + var entry = itr.next(); + if ("volumeAttributesClassName".equals(entry.getKey())) { + continue; + } + if ("resources".equals(entry.getKey())) { + continue; + } + itr.remove(); + } + } } 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 8b84ed3..de96ec6 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 @@ -23,6 +23,7 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import java.math.BigInteger; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -62,7 +63,8 @@ public class GsonPtr { * @param selectors the selectors * @return the Gson pointer */ - @SuppressWarnings({ "PMD.ShortMethodName", "PMD.PreserveStackTrace" }) + @SuppressWarnings({ "PMD.ShortMethodName", "PMD.PreserveStackTrace", + "PMD.AvoidDuplicateLiterals" }) public GsonPtr to(Object... selectors) { JsonElement element = position; for (Object sel : selectors) { @@ -91,6 +93,42 @@ public class GsonPtr { return new GsonPtr(element); } + /** + * Create a new instance pointing to the {@link JsonElement} + * selected by the given selectors. If a selector of type + * {@link String} denotes a non-existant member of a + * {@link JsonObject} the result is empty. + * + * @param selectors the selectors + * @return the Gson pointer + */ + @SuppressWarnings({ "PMD.ShortMethodName", "PMD.PreserveStackTrace" }) + public Optional access(Object... selectors) { + JsonElement element = position; + for (Object sel : selectors) { + if (element instanceof JsonObject obj + && sel instanceof String member) { + element = obj.get(member); + if (element == null) { + return Optional.empty(); + } + continue; + } + if (element instanceof JsonArray arr + && sel instanceof Integer index) { + try { + element = arr.get(index); + } catch (IndexOutOfBoundsException e) { + throw new IllegalStateException("Selected array index" + + " may not be empty."); + } + continue; + } + throw new IllegalStateException("Invalid selection"); + } + return Optional.of(new GsonPtr(element)); + } + /** * Returns {@link JsonElement} that the pointer points to. * @@ -336,4 +374,22 @@ public class GsonPtr { return this; } + /** + * Removes all properties except the specified ones. + * + * @param properties the properties + */ + public void removeExcept(String... properties) { + if (!position.isJsonObject()) { + return; + } + for (var itr = ((JsonObject) position).entrySet().iterator(); + itr.hasNext();) { + var entry = itr.next(); + if (Arrays.asList(properties).contains(entry.getKey())) { + continue; + } + itr.remove(); + } + } } From 80d416550050588c7567fd95b6988cf8a70b9448 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 13:32:27 +0100 Subject: [PATCH 140/342] Upgrade base library. --- org.jdrupes.vmoperator.manager/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index b581971..eda5ce0 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.jgrapes:org.jgrapes.io:[2.12.1,3)' implementation 'org.jgrapes:org.jgrapes.http:[3.5.0,4)' - implementation 'org.jgrapes:org.jgrapes.webconsole.base:[2.1.0,3)' + implementation 'org.jgrapes:org.jgrapes.webconsole.base:[2.2.0,3)' implementation 'org.jgrapes:org.jgrapes.webconsole.vuejs:[1.8.0,2)' implementation 'org.jgrapes:org.jgrapes.webconsole.rbac:[1.4.0,2)' implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.7.0,2)' From 877d4c69cde50345521b6ca7858c1a2506b5b2aa Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 13:34:16 +0100 Subject: [PATCH 141/342] Remove obsolete method. --- .../jdrupes/vmoperator/manager/PvcReconciler.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java index 4ced1b1..5f10f47 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java @@ -214,19 +214,4 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; () -> "Could not patch pvc for " + pvcStub.name()); } } - - @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") - private void removeImmutable(DynamicKubernetesObject pvcDef) { - var spec = GsonPtr.to(pvcDef.getRaw()).to("spec").get(JsonObject.class); - for (var itr = spec.entrySet().iterator(); itr.hasNext();) { - var entry = itr.next(); - if ("volumeAttributesClassName".equals(entry.getKey())) { - continue; - } - if ("resources".equals(entry.getKey())) { - continue; - } - itr.remove(); - } - } } From 5d722abd2e95cc052124d3fe41ce27568c8be596 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 13:35:51 +0100 Subject: [PATCH 142/342] Add assignment based on last usage. --- deploy/crds/vmpools-crd.yaml | 9 +++ dev-example/test-pool.yaml | 1 + .../vmoperator/common/VmDefinition.java | 34 +++++++- .../org/jdrupes/vmoperator/common/VmPool.java | 38 +++++++++ .../vmoperator/manager/PoolMonitor.java | 40 +++++++++- .../jdrupes/vmoperator/manager/VmMonitor.java | 80 +++++++++++++------ .../vmoperator/vmaccess/l10n.properties | 1 + .../vmoperator/vmaccess/l10n_de.properties | 3 + .../jdrupes/vmoperator/vmaccess/VmAccess.java | 12 ++- 9 files changed, 186 insertions(+), 32 deletions(-) diff --git a/deploy/crds/vmpools-crd.yaml b/deploy/crds/vmpools-crd.yaml index 193d547..b34d096 100644 --- a/deploy/crds/vmpools-crd.yaml +++ b/deploy/crds/vmpools-crd.yaml @@ -16,6 +16,15 @@ spec: spec: type: object properties: + retention: + description: >- + Defines the timeout for assignments. The time may be + specified as ISO 8601 time or duration. When specifying + a duration, it will be added to the last time the VM's + console was used to obtain the timeout. + type: string + pattern: '^(?:\d{4}-(?:0[1-9]|1[0-2])-(?:0[1-9]|[12]\d|3[01])T(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d(?:\.\d{1,9})?(?:Z|[+-](?:[01]\d|2[0-3])(?:|:?[0-5]\d))|P(?:\d+Y)?(?:\d+M)?(?:\d+W)?(?:\d+D)?(?:T(?:\d+[Hh])?(?:\d+[Mm])?(?:\d+(?:\.\d{1,9})?[Ss])?)?)$' + default: "PT1h" permissions: type: array description: >- diff --git a/dev-example/test-pool.yaml b/dev-example/test-pool.yaml index 43c36b8..96289e3 100644 --- a/dev-example/test-pool.yaml +++ b/dev-example/test-pool.yaml @@ -4,6 +4,7 @@ metadata: namespace: vmop-dev name: test-vms spec: + retention: "PT1m" permissions: - user: admin may: diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java index 375612b..2742b88 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java @@ -18,7 +18,11 @@ package org.jdrupes.vmoperator.common; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import io.kubernetes.client.openapi.models.V1Condition; import io.kubernetes.client.openapi.models.V1ObjectMeta; +import java.time.Instant; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; @@ -36,9 +40,12 @@ import org.jdrupes.vmoperator.util.DataPath; /** * Represents a VM definition. */ -@SuppressWarnings({ "PMD.DataClass" }) +@SuppressWarnings({ "PMD.DataClass", "PMD.TooManyMethods" }) public class VmDefinition { + private static ObjectMapper objectMapper + = new ObjectMapper().registerModule(new JavaTimeModule()); + private String kind; private String apiVersion; private V1ObjectMeta metadata; @@ -306,6 +313,31 @@ public class VmDefinition { return fromStatus("assignment", "user"); } + /** + * Last usage of assigned VM. + * + * @return the optional + */ + public Optional assignmentLastUsed() { + return this. fromStatus("assignment", "lastUsed") + .map(Instant::parse); + } + + /** + * Return a condition from the status. + * + * @param name the condition's name + * @return the status, if the condition is defined + */ + public Optional condition(String name) { + return this.>> fromStatus("conditions") + .orElse(Collections.emptyList()).stream() + .filter(cond -> DataPath.get(cond, "type") + .map(name::equals).orElse(false)) + .findFirst() + .map(cond -> objectMapper.convertValue(cond, V1Condition.class)); + } + /** * Return a condition's status. * diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java index 426a69c..8bf6dee 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java @@ -18,6 +18,8 @@ package org.jdrupes.vmoperator.common; +import java.time.Duration; +import java.time.Instant; import java.util.Collection; import java.util.Collections; import java.util.HashSet; @@ -36,6 +38,7 @@ import org.jdrupes.vmoperator.util.DataPath; public class VmPool { private String name; + private String retention; private boolean defined; private List permissions = Collections.emptyList(); private final Set vms @@ -86,6 +89,24 @@ public class VmPool { this.defined = defined; } + /** + * Gets the retention. + * + * @return the retention + */ + public String retention() { + return retention; + } + + /** + * Sets the retention. + * + * @param retention the retention to set + */ + public void setRetention(String retention) { + this.retention = retention; + } + /** * Permissions granted for a VM from the pool. * @@ -113,6 +134,11 @@ public class VmPool { return vms; } + /** + * To string. + * + * @return the string + */ @Override @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") public String toString() { @@ -147,4 +173,16 @@ public class VmPool { .flatMap(Function.identity()).collect(Collectors.toSet()); } + /** + * Return the instant until which an assignment should be retained. + * + * @param lastUsed the last used + * @return the instant + */ + public Instant retainUntil(Instant lastUsed) { + if (retention.startsWith("P")) { + return lastUsed.plus(Duration.parse(retention)); + } + return Instant.parse(retention); + } } diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java index e11f667..4a7a1cb 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java @@ -18,21 +18,26 @@ package org.jdrupes.vmoperator.manager; +import com.google.gson.JsonObject; +import io.kubernetes.client.apimachinery.GroupVersionKind; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.util.Watch; import java.io.IOException; +import java.time.Instant; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; +import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import org.jdrupes.vmoperator.common.K8s; import org.jdrupes.vmoperator.common.K8sClient; import org.jdrupes.vmoperator.common.K8sDynamicModel; import org.jdrupes.vmoperator.common.K8sDynamicModels; import org.jdrupes.vmoperator.common.K8sDynamicStub; import org.jdrupes.vmoperator.common.K8sObserver.ResponseType; +import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.common.VmPool; import static org.jdrupes.vmoperator.manager.Constants.VM_OP_KIND_VM_POOL; import org.jdrupes.vmoperator.manager.events.GetPools; @@ -129,6 +134,7 @@ public class PoolMonitor extends var vmPool = pools.computeIfAbsent(poolName, k -> new VmPool(poolName)); var newData = client().getJSON().getGson().fromJson( GsonPtr.to(poolModel.data()).to("spec").get(), VmPool.class); + vmPool.setRetention(newData.retention()); vmPool.setPermissions(newData.permissions()); vmPool.setDefined(true); poolPipeline.fire(new VmPoolChanged(vmPool)); @@ -138,13 +144,15 @@ public class PoolMonitor extends * Track VM definition changes. * * @param event the event + * @throws ApiException */ @Handler - public void onVmDefChanged(VmDefChanged event) { - String vmName = event.vmDefinition().name(); + public void onVmDefChanged(VmDefChanged event) throws ApiException { + final var vmDef = event.vmDefinition(); + final String vmName = vmDef.name(); switch (event.type()) { case ADDED: - event.vmDefinition().> fromSpec("pools") + vmDef.> fromSpec("pools") .orElse(Collections.emptyList()).stream().forEach(p -> { pools.computeIfAbsent(p, k -> new VmPool(p)) .vms().add(vmName); @@ -157,10 +165,34 @@ public class PoolMonitor extends poolPipeline.fire(new VmPoolChanged(p)); } }); - break; + return; default: break; } + + // Sync last usage to console state change if user matches + var assignedTo = vmDef.assignedTo().orElse(null); + if (assignedTo == null || !assignedTo + .equals(vmDef. fromStatus("consoleUser").orElse(null))) { + return; + } + var lastUsed + = vmDef.assignmentLastUsed().orElse(Instant.ofEpochSecond(0)); + var conChange = vmDef.condition("ConsoleConnected") + .map(c -> c.getLastTransitionTime().toInstant()) + .orElse(Instant.ofEpochSecond(0)); + if (!conChange.isAfter(lastUsed)) { + return; + } + var vmStub = VmDefinitionStub.get(client(), + new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), + vmDef.namespace(), vmDef.name()); + vmStub.updateStatus(from -> { + JsonObject status = from.status(); + var assignment = GsonPtr.to(status).to("assignment"); + assignment.set("lastUsed", conChange.toString()); + return status; + }); } /** 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 b8ba467..9b6f75f 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 @@ -1,6 +1,6 @@ /* * VM-Operator - * Copyright (C) 2023,2024 Michael N. Lipp + * Copyright (C) 2023,2025 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 @@ -25,7 +25,9 @@ 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.time.Instant; import java.util.ArrayList; +import java.util.Comparator; import java.util.Optional; import java.util.Set; import java.util.logging.Level; @@ -43,10 +45,12 @@ import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.common.VmDefinitionModel; import org.jdrupes.vmoperator.common.VmDefinitionModels; import org.jdrupes.vmoperator.common.VmDefinitionStub; +import org.jdrupes.vmoperator.common.VmPool; 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.AssignVm; import org.jdrupes.vmoperator.manager.events.ChannelManager; +import org.jdrupes.vmoperator.manager.events.GetPools; import org.jdrupes.vmoperator.manager.events.GetVms; import org.jdrupes.vmoperator.manager.events.GetVms.VmData; import org.jdrupes.vmoperator.manager.events.ModifyVm; @@ -245,28 +249,59 @@ public class VmMonitor extends * * @param event the event * @throws ApiException the api exception + * @throws InterruptedException */ @Handler - public void onAssignVm(AssignVm event) throws ApiException { - // Search for existing assignment. - var assignedVm = channelManager.channels().stream() - .filter(c -> c.vmDefinition().assignedFrom() - .map(p -> p.equals(event.fromPool())).orElse(false)) - .filter(c -> c.vmDefinition().assignedTo() - .map(u -> u.equals(event.toUser())).orElse(false)) - .findFirst(); - if (assignedVm.isPresent()) { - event.setResult(new VmData(assignedVm.get().vmDefinition(), - assignedVm.get())); - return; - } + @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") + public void onAssignVm(AssignVm event) + throws ApiException, InterruptedException { + VmPool vmPool = null; + while (true) { + // Search for existing assignment. + var assignedVm = channelManager.channels().stream() + .filter(c -> c.vmDefinition().assignedFrom() + .map(p -> p.equals(event.fromPool())).orElse(false)) + .filter(c -> c.vmDefinition().assignedTo() + .map(u -> u.equals(event.toUser())).orElse(false)) + .findFirst(); + if (assignedVm.isPresent()) { + var vmDef = assignedVm.get().vmDefinition(); + event.setResult(new VmData(vmDef, assignedVm.get())); + return; + } - // Find available VM. - assignedVm = channelManager.channels().stream() - .filter(c -> c.vmDefinition().pools().contains(event.fromPool())) - .filter(c -> c.vmDefinition().assignedTo().isEmpty()) - .findFirst(); - if (assignedVm.isPresent()) { + // Get the pool definition for retention time calculations + if (vmPool == null) { + vmPool = newEventPipeline().fire(new GetPools() + .withName(event.fromPool())).get().stream().findFirst() + .orElse(null); + if (vmPool == null) { + return; + } + } + + // Find available VM. + var pool = vmPool; + assignedVm = channelManager.channels().stream() + .filter(c -> c.vmDefinition().pools() + .contains(event.fromPool())) + .filter(c -> !c.vmDefinition() + .conditionStatus("ConsoleConnected").orElse(false)) + .filter(c -> c.vmDefinition().assignedTo().isEmpty() + || pool.retainUntil(c.vmDefinition() + . fromStatus("assignment", "lastUsed") + .map(Instant::parse).orElse(Instant.ofEpochSecond(0))) + .isBefore(Instant.now())) + .sorted(Comparator.comparing(c -> c.vmDefinition() + .assignmentLastUsed().orElse(Instant.ofEpochSecond(0)))) + .findFirst(); + + // None found + if (assignedVm.isEmpty()) { + return; + } + + // Assign to user var vmDef = assignedVm.get().vmDefinition(); var vmStub = VmDefinitionStub.get(client(), new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), @@ -276,14 +311,13 @@ public class VmMonitor extends var assignment = GsonPtr.to(status).to("assignment"); assignment.set("pool", event.fromPool()); assignment.set("user", event.toUser()); + assignment.set("lastUsed", Instant.now().toString()); return status; }); - // Always start a newly assigned VM. + // Make sure that a newly assigned VM is running. fire(new ModifyVm(vmDef.name(), "state", "Running", assignedVm.get())); - event.setResult(new VmData(vmDef, assignedVm.get())); } } - } diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties index d755e7a..6305a4b 100644 --- a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties @@ -5,3 +5,4 @@ okayLabel = Apply and Close confirmResetTitle = Confirm reset confirmResetMsg = Resetting the VM may cause loss of data. \ Please confirm to continue. +poolEmptyNotification = No VM available. Please consult your administrator. diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties index 7d4ff23..dbd3b11 100644 --- a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties @@ -11,3 +11,6 @@ Open\ console = Konsole anzeigen confirmResetTitle = Zurücksetzen bestätigen confirmResetMsg = Zurücksetzen der VM kann zu Datenverlust führen. \ Bitte bestätigen um fortzufahren. +poolEmptyNotification = Keine VM verfügbar. Wenden Sie sich bitte an den \ + Systemadministrator. + \ No newline at end of file diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index e6d4e58..5c72309 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -86,6 +86,7 @@ import org.jgrapes.webconsole.base.events.ConsoleConfigured; import org.jgrapes.webconsole.base.events.ConsolePrepared; import org.jgrapes.webconsole.base.events.ConsoleReady; import org.jgrapes.webconsole.base.events.DeleteConlet; +import org.jgrapes.webconsole.base.events.DisplayNotification; import org.jgrapes.webconsole.base.events.NotifyConletModel; import org.jgrapes.webconsole.base.events.NotifyConletView; import org.jgrapes.webconsole.base.events.OpenModalDialog; @@ -717,10 +718,9 @@ public class VmAccess extends FreeMarkerConlet { } } - @Override - @SuppressWarnings({ "PMD.AvoidDecimalLiteralsInBigDecimalConstructor", - "PMD.ConfusingArgumentToVarargsMethod", "PMD.NcssCount", + @SuppressWarnings({ "PMD.NcssCount", "PMD.CognitiveComplexity", "PMD.AvoidLiteralsInIfCondition" }) + @Override protected void doUpdateConletState(NotifyConletModel event, ConsoleConnection channel, ResourceModel model) throws Exception { event.stop(); @@ -741,7 +741,11 @@ public class VmAccess extends FreeMarkerConlet { vmData = Optional.ofNullable(appPipeline .fire(new AssignVm(model.name(), user)).get()); if (vmData.isEmpty()) { - // TODO message + ResourceBundle resourceBundle + = resourceBundle(channel.locale()); + channel.respond(new DisplayNotification( + resourceBundle.getString("poolEmptyNotification"), + Map.of("autoClose", 15_000, "type", "Error"))); return; } } From 2a70c74234c6fc354403eb7444f00117b32cd372 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 13:39:22 +0100 Subject: [PATCH 143/342] Use consistent method names. --- .../manager/ConfigMapReconciler.java | 4 ++-- .../vmoperator/manager/PvcReconciler.java | 2 +- .../org/jdrupes/vmoperator/util/GsonPtr.java | 18 +++++++++--------- 3 files changed, 12 insertions(+), 12 deletions(-) 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 68ca7fa..9c6dc3e 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 @@ -86,14 +86,14 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; // Maybe override logging.properties from reconciler configuration. DataPath. get(model, "reconciler", "loggingProperties") .ifPresent(props -> { - GsonPtr.to(mapDef.getRaw()).get(JsonObject.class, "data") + GsonPtr.to(mapDef.getRaw()).getAs(JsonObject.class, "data") .get().addProperty("logging.properties", props); }); // Maybe override logging.properties from VM definition. DataPath. get(model, "cr", "spec", "loggingProperties") .ifPresent(props -> { - GsonPtr.to(mapDef.getRaw()).get(JsonObject.class, "data") + GsonPtr.to(mapDef.getRaw()).getAs(JsonObject.class, "data") .get().addProperty("logging.properties", props); }); diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java index 5f10f47..caae5a3 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java @@ -204,7 +204,7 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; // If bound, use json merge, omitting immutable fields var spec = GsonPtr.to(pvcDef.getRaw()).to("spec"); spec.removeExcept("volumeAttributesClassName", "resources"); - spec.access("resources").ifPresent(p -> p.removeExcept("requests")); + spec.get("resources").ifPresent(p -> p.removeExcept("requests")); PatchOptions opts = new PatchOptions(); opts.setFieldManager("kubernetes-java-kubectl-apply"); if (pvcStub.patch(V1Patch.PATCH_FORMAT_JSON_MERGE_PATCH, 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 de96ec6..36c3444 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 @@ -103,7 +103,7 @@ public class GsonPtr { * @return the Gson pointer */ @SuppressWarnings({ "PMD.ShortMethodName", "PMD.PreserveStackTrace" }) - public Optional access(Object... selectors) { + public Optional get(Object... selectors) { JsonElement element = position; for (Object sel : selectors) { if (element instanceof JsonObject obj @@ -147,7 +147,7 @@ public class GsonPtr { * @return the result */ @SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop" }) - public T get(Class cls) { + public T getAs(Class cls) { if (cls.isAssignableFrom(position.getClass())) { return cls.cast(position); } @@ -166,7 +166,7 @@ public class GsonPtr { */ @SuppressWarnings({ "PMD.AvoidBranchingStatementAsLastInLoop" }) public Optional - get(Class cls, Object... selectors) { + getAs(Class cls, Object... selectors) { JsonElement element = position; for (Object sel : selectors) { if (element instanceof JsonObject obj @@ -201,7 +201,7 @@ public class GsonPtr { * @return the as string */ public Optional getAsString(Object... selectors) { - return get(JsonPrimitive.class, selectors) + return getAs(JsonPrimitive.class, selectors) .map(JsonPrimitive::getAsString); } @@ -212,7 +212,7 @@ public class GsonPtr { * @return the as string */ public Optional getAsInt(Object... selectors) { - return get(JsonPrimitive.class, selectors) + return getAs(JsonPrimitive.class, selectors) .map(JsonPrimitive::getAsInt); } @@ -223,7 +223,7 @@ public class GsonPtr { * @return the as string */ public Optional getAsBigInteger(Object... selectors) { - return get(JsonPrimitive.class, selectors) + return getAs(JsonPrimitive.class, selectors) .map(JsonPrimitive::getAsBigInteger); } @@ -234,7 +234,7 @@ public class GsonPtr { * @return the as string */ public Optional getAsLong(Object... selectors) { - return get(JsonPrimitive.class, selectors) + return getAs(JsonPrimitive.class, selectors) .map(JsonPrimitive::getAsLong); } @@ -245,7 +245,7 @@ public class GsonPtr { * @return the boolean */ public Optional getAsBoolean(Object... selectors) { - return get(JsonPrimitive.class, selectors) + return getAs(JsonPrimitive.class, selectors) .map(JsonPrimitive::getAsBoolean); } @@ -260,7 +260,7 @@ public class GsonPtr { @SuppressWarnings("unchecked") public List getAsListOf(Class cls, Object... selectors) { - return get(JsonArray.class, selectors).map(a -> (List) a.asList()) + return getAs(JsonArray.class, selectors).map(a -> (List) a.asList()) .orElse(Collections.emptyList()); } From a0d626cc319f22966ac843201f7d0a878a3c2592 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 13:40:51 +0100 Subject: [PATCH 144/342] Fix warnings. --- .../org/jdrupes/vmoperator/common/K8sClusterGenericStub.java | 5 +++-- .../src/org/jdrupes/vmoperator/manager/PvcReconciler.java | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java index 81a4eab..af87af2 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java @@ -45,7 +45,8 @@ import java.util.function.Function; * @param the generic type * @param the generic type */ -@SuppressWarnings("PMD.DataflowAnomalyAnalysis") +@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", + "PMD.CouplingBetweenObjects" }) public class K8sClusterGenericStub { protected final K8sClient client; @@ -373,7 +374,7 @@ public class K8sClusterGenericStub> Collection list(Class objectClass, Class objectListClass, - K8sClient client, APIResource context, + K8sClient client, APIResource context, ListOptions options, GenericSupplier provider) throws ApiException { var result = new ArrayList(); diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java index caae5a3..34085f0 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PvcReconciler.java @@ -18,7 +18,6 @@ package org.jdrupes.vmoperator.manager; -import com.google.gson.JsonObject; import freemarker.core.ParseException; import freemarker.template.Configuration; import freemarker.template.MalformedTemplateNameException; @@ -26,7 +25,6 @@ import freemarker.template.TemplateException; import freemarker.template.TemplateNotFoundException; import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; -import io.kubernetes.client.util.generic.dynamic.DynamicKubernetesObject; import io.kubernetes.client.util.generic.dynamic.Dynamics; import io.kubernetes.client.util.generic.options.ListOptions; import io.kubernetes.client.util.generic.options.PatchOptions; From 574ad5226bd5d03b4b46566b82b767544a047700 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 14:33:56 +0100 Subject: [PATCH 145/342] Fix typescript error. --- .../jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts index 6ab15b8..f18836a 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts @@ -75,17 +75,17 @@ window.orgJDrupesVmOperatorVmMgmt.initPreview = (previewDom: HTMLElement, chart = new CpuRamChart(canvas, chartData); }) - watch(chartDateUpdate, (_) => { + watch(chartDateUpdate, (_: never) => { chart?.update(); }) - watch(JGWC.langRef(), (_) => { + watch(JGWC.langRef(), (_: never) => { chart?.localizeChart(); }) const period: Ref = ref("day"); - watch(period, (_) => { + watch(period, (_: never) => { const hours = (period.value === "day") ? 24 : 1; chart?.setPeriod(hours * 3600 * 1000); }); From 53a58a2aca1fdda39e159ab2064fbfca08230d61 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 15:12:49 +0100 Subject: [PATCH 146/342] Add users for pool testing. --- dev-example/config.yaml | 18 ++++++++++++++---- dev-example/kustomization.yaml | 14 ++++++++++++-- dev-example/test-pool.yaml | 2 +- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/dev-example/config.yaml b/dev-example/config.yaml index f2e0563..c0dc4b1 100644 --- a/dev-example/config.yaml +++ b/dev-example/config.yaml @@ -40,15 +40,25 @@ - name: admin fullName: Administrator password: "$2b$05$NiBd74ZGdplLC63ePZf1f.UtjMKkbQ23cQoO2OKOFalDBHWAOy21." - - name: test - fullName: Test Account + - name: test1 + fullName: Test Account 1 + password: "$2b$05$hZaI/jToXf/d3BctZdT38Or7H7h6Pn2W3WiB49p5AyhDHFkkYCvo2" + - name: test2 + fullName: Test Account 2 + password: "$2b$05$hZaI/jToXf/d3BctZdT38Or7H7h6Pn2W3WiB49p5AyhDHFkkYCvo2" + - name: test3 + fullName: Test Account 3 password: "$2b$05$hZaI/jToXf/d3BctZdT38Or7H7h6Pn2W3WiB49p5AyhDHFkkYCvo2" "/RoleConfigurator": rolesByUser: # User admin has role admin admin: - admin - test: + test1: + - user + test2: + - user + test3: - user # All users have role other "*": @@ -60,7 +70,7 @@ admin: - "*" user: - - org.jdrupes.vmoperator.vmviewer.VmViewer + - org.jdrupes.vmoperator.vmaccess.VmAccess # Others cannot use any conlet (except login conlet to log out) other: - org.jgrapes.webconlet.oidclogin.LoginConlet diff --git a/dev-example/kustomization.yaml b/dev-example/kustomization.yaml index 7dc4a15..975d95f 100644 --- a/dev-example/kustomization.yaml +++ b/dev-example/kustomization.yaml @@ -54,7 +54,13 @@ patches: - name: admin fullName: Administrator password: "$2b$05$NiBd74ZGdplLC63ePZf1f.UtjMKkbQ23cQoO2OKOFalDBHWAOy21." - - name: test + - name: test1 + fullName: Test Account + password: "$2b$05$hZaI/jToXf/d3BctZdT38Or7H7h6Pn2W3WiB49p5AyhDHFkkYCvo2" + - name: test2 + fullName: Test Account + password: "$2b$05$hZaI/jToXf/d3BctZdT38Or7H7h6Pn2W3WiB49p5AyhDHFkkYCvo2" + - name: test3 fullName: Test Account password: "$2b$05$hZaI/jToXf/d3BctZdT38Or7H7h6Pn2W3WiB49p5AyhDHFkkYCvo2" "/RoleConfigurator": @@ -62,7 +68,11 @@ patches: # User admin has role admin admin: - admin - test: + test1: + - user + test2: + - user + test3: - user # All users have role other "*": diff --git a/dev-example/test-pool.yaml b/dev-example/test-pool.yaml index 96289e3..82b9131 100644 --- a/dev-example/test-pool.yaml +++ b/dev-example/test-pool.yaml @@ -9,6 +9,6 @@ spec: - user: admin may: - accessConsole - - user: test + - role: user may: - accessConsole From aaf1a0c545790aa55a3a120c5f22e27fd9f01cac Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 22:27:07 +0100 Subject: [PATCH 147/342] Add operator for testing. --- dev-example/config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/dev-example/config.yaml b/dev-example/config.yaml index c0dc4b1..586a16e 100644 --- a/dev-example/config.yaml +++ b/dev-example/config.yaml @@ -40,6 +40,9 @@ - name: admin fullName: Administrator password: "$2b$05$NiBd74ZGdplLC63ePZf1f.UtjMKkbQ23cQoO2OKOFalDBHWAOy21." + - name: operator + fullName: Operator + password: "$2b$05$hZaI/jToXf/d3BctZdT38Or7H7h6Pn2W3WiB49p5AyhDHFkkYCvo2" - name: test1 fullName: Test Account 1 password: "$2b$05$hZaI/jToXf/d3BctZdT38Or7H7h6Pn2W3WiB49p5AyhDHFkkYCvo2" @@ -54,6 +57,8 @@ # User admin has role admin admin: - admin + operator: + - operator test1: - user test2: @@ -69,6 +74,8 @@ # Admins can use all conlets admin: - "*" + operator: + - org.jdrupes.vmoperator.vmaccess.VmAccess user: - org.jdrupes.vmoperator.vmaccess.VmAccess # Others cannot use any conlet (except login conlet to log out) From 224855efd3b12350966030c5453d34120fcca146 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 25 Jan 2025 22:27:52 +0100 Subject: [PATCH 148/342] Disable empty lists. --- .../org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html index afbff3a..a34f725 100644 --- a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/VmAccess-edit.ftl.html @@ -10,7 +10,8 @@
diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n.properties b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n.properties index 51ca610..0ab15fd 100644 --- a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n.properties +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n.properties @@ -7,6 +7,7 @@ currentCpus = Current CPUs currentRam = Current RAM maximumCpus = Maximum CPUs maximumRam = Maximum RAM +notInUse = Currently closed nodeName = Node requestedCpus = Requested CPUs requestedRam = Requested RAM diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n_de.properties b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n_de.properties index 3e67928..c8d8c4d 100644 --- a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n_de.properties +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n_de.properties @@ -12,6 +12,7 @@ currentRam = Akuelles RAM maximumCpus = Maximale CPUs maximumRam = Maximales RAM nodeName = Knoten +notInUse = Derzeit geschlossen requestedCpus = Angeforderte CPUs requestedRam = Angefordertes RAM running = Gestartet diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts index f18836a..d8247ba 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts @@ -164,7 +164,7 @@ window.orgJDrupesVmOperatorVmMgmt.initView = (viewDom: HTMLElement, return { controller, vmInfos, filteredData, detailsByName, localize, shortDateTime, formatMemory, vmAction, cic, parseMemory, - maximumCpus, + maximumCpus, scopedId: (id: string) => { return idScope.scopedId(id); } }; } diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss index 9d7721a..3a3f0d7 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss @@ -72,6 +72,10 @@ } } } + + .console-conection-closed { + color: var(--disabled); + } } td.details { From 3ca632c8dab3047a7f42013ae023a4a932d66c9f Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 26 Jan 2025 17:21:36 +0100 Subject: [PATCH 151/342] Exchange columns. --- .../org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts index d8247ba..c7f8519 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts @@ -112,8 +112,8 @@ window.orgJDrupesVmOperatorVmMgmt.initView = (viewDom: HTMLElement, ["currentCpus", "currentCpus"], ["currentRam", "currentRam"], ["nodeName", "nodeName"], - ["assignedTo", "assignedTo"], - ["usedBy", "usedBy"] + ["usedBy", "usedBy"], + ["assignedTo", "assignedTo"] ], { sortKey: "name", sortOrder: "up" From 1b5ad5b73e0e98edc8bca1e99618c764e3af5f35 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 26 Jan 2025 21:49:37 +0100 Subject: [PATCH 152/342] Prevent unauthorized console take over. --- deploy/crds/vms-crd.yaml | 5 +++++ .../jdrupes/vmoperator/common/VmDefinition.java | 2 +- .../jdrupes/vmoperator/vmaccess/l10n.properties | 1 + .../vmoperator/vmaccess/l10n_de.properties | 1 + .../jdrupes/vmoperator/vmaccess/VmAccess.java | 16 +++++++++++++--- 5 files changed, 21 insertions(+), 4 deletions(-) diff --git a/deploy/crds/vms-crd.yaml b/deploy/crds/vms-crd.yaml index 9d7bbb8..7b46dc7 100644 --- a/deploy/crds/vms-crd.yaml +++ b/deploy/crds/vms-crd.yaml @@ -994,6 +994,10 @@ spec: type: array description: >- Defines permissions for accessing and manipulating the VM. + The meaning of most permissions should be obvious. The + difference between "accessConsole" and "takeConsole" is + that "takeConsole" allows the user to take control of + the console even if it is already in use by another user. items: type: object description: >- @@ -1017,6 +1021,7 @@ spec: - stop - reset - accessConsole + - takeConsole - "*" default: [] pools: diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java index da639f4..f577d28 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java @@ -65,7 +65,7 @@ public class VmDefinition { */ public enum Permission { START("start"), STOP("stop"), RESET("reset"), - ACCESS_CONSOLE("accessConsole"); + ACCESS_CONSOLE("accessConsole"), TAKE_CONSOLE("takeConsole"); @SuppressWarnings("PMD.UseConcurrentHashMap") private static Map reprs = new HashMap<>(); diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties index 6305a4b..8f4051e 100644 --- a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n.properties @@ -5,4 +5,5 @@ okayLabel = Apply and Close confirmResetTitle = Confirm reset confirmResetMsg = Resetting the VM may cause loss of data. \ Please confirm to continue. +consoleTakenNotification = Console access is locked by another user. poolEmptyNotification = No VM available. Please consult your administrator. diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties index dbd3b11..e51eb5e 100644 --- a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/l10n_de.properties @@ -11,6 +11,7 @@ Open\ console = Konsole anzeigen confirmResetTitle = Zurücksetzen bestätigen confirmResetMsg = Zurücksetzen der VM kann zu Datenverlust führen. \ Bitte bestätigen um fortzufahren. +consoleTakenNotification = Die Konsole wird von einem anderen Benutzer verwendet. poolEmptyNotification = Keine VM verfügbar. Wenden Sie sich bitte an den \ Systemadministrator. \ No newline at end of file diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index 5c72309..5f2d747 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -779,9 +779,19 @@ public class VmAccess extends FreeMarkerConlet { } break; case "openConsole": - if (perms.contains(VmDefinition.Permission.ACCESS_CONSOLE)) { - var user = WebConsoleUtils.userFromSession(channel.session()) - .map(ConsoleUser::getName).orElse(""); + var user = WebConsoleUtils.userFromSession(channel.session()) + .map(ConsoleUser::getName).orElse(""); + if (vmDef.conditionStatus("ConsoleConnected").orElse(false) + && vmDef.consoleUser().map(cu -> !cu.equals(user) + && !perms.contains(VmDefinition.Permission.TAKE_CONSOLE)) + .orElse(false)) { + channel.respond(new DisplayNotification( + resourceBundle.getString("consoleTakenNotification"), + Map.of("autoClose", 5_000, "type", "Warning"))); + return; + } + if (perms.contains(VmDefinition.Permission.ACCESS_CONSOLE) + || perms.contains(VmDefinition.Permission.TAKE_CONSOLE)) { var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef, user), e -> openConsole(vmDef, channel, model, From 86f6ece2648bbc514cd7fbb9a7ae8a4e54a21c78 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 26 Jan 2025 21:55:24 +0100 Subject: [PATCH 153/342] Adjust auto close time. --- .../src/org/jdrupes/vmoperator/vmaccess/VmAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index 5f2d747..786fedf 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -745,7 +745,7 @@ public class VmAccess extends FreeMarkerConlet { = resourceBundle(channel.locale()); channel.respond(new DisplayNotification( resourceBundle.getString("poolEmptyNotification"), - Map.of("autoClose", 15_000, "type", "Error"))); + Map.of("autoClose", 10_000, "type", "Error"))); return; } } From 5cd4edcec12672a74b07df52ac11aa4c1bfdc258 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 28 Jan 2025 18:08:28 +0100 Subject: [PATCH 154/342] Don't add channels until fully initialized. --- .../manager/events/ChannelManager.java | 17 +++++++++++++++++ .../org/jdrupes/vmoperator/vmmgmt/VmMgmt.java | 2 ++ 2 files changed, 19 insertions(+) diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ChannelManager.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ChannelManager.java index 2cf7a85..ce0e4f0 100644 --- a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ChannelManager.java +++ b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/ChannelManager.java @@ -62,6 +62,11 @@ public class ChannelManager this(k -> null); } + /** + * Return all keys. + * + * @return the keys. + */ @Override public Set keys() { return entries.keySet(); @@ -113,6 +118,18 @@ public class ChannelManager return this; } + /** + * Creates a new channel without adding it to the channel manager. + * After fully initializing the channel, it should be added to the + * manager using {@link #put(K, C)}. + * + * @param key the key + * @return the c + */ + public C createChannel(K key) { + return supplier.apply(key); + } + /** * Returns the {@link Channel} for the given name, creating it using * the supplier passed to the constructor if it doesn't exist yet. diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java index dbe17ca..3842cbc 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java @@ -352,6 +352,8 @@ public class VmMgmt extends FreeMarkerConlet { case "stop": fire(new ModifyVm(vmName, "state", "Stopped", vmChannel)); break; + case "openConsole": + break; case "cpus": fire(new ModifyVm(vmName, "currentCpus", new BigDecimal(event.param(1).toString()).toBigInteger(), From af41c78c078b09068f5c5bdbc44087e8e98990a3 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 29 Jan 2025 17:33:16 +0100 Subject: [PATCH 155/342] Add console access to VM management. --- dev-example/config.yaml | 1 + .../vmoperator/common/VmDefinition.java | 114 ++++++++++++++- .../jdrupes/vmoperator/manager/VmMonitor.java | 11 +- .../jdrupes/vmoperator/vmaccess/VmAccess.java | 119 ++++------------ .../vmaccess/browser/VmAccess-functions.ts | 5 +- .../vmoperator/vmmgmt/VmMgmt-view.ftl.html | 16 ++- .../vmoperator/vmmgmt/computer-in-use.svg | 90 ++++++++++++ .../vmoperator/vmmgmt/computer-off.svg | 74 ++++++++++ .../jdrupes/vmoperator/vmmgmt/computer.svg | 74 ++++++++++ .../jdrupes/vmoperator/vmmgmt/l10n.properties | 5 + .../vmoperator/vmmgmt/l10n_de.properties | 6 + .../org/jdrupes/vmoperator/vmmgmt/VmMgmt.java | 132 +++++++++++++++--- .../vmmgmt/browser/VmMgmt-functions.ts | 24 +++- .../vmmgmt/browser/VmMgmt-style.scss | 14 ++ 14 files changed, 561 insertions(+), 124 deletions(-) create mode 100644 org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer-in-use.svg create mode 100644 org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer-off.svg create mode 100644 org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer.svg diff --git a/dev-example/config.yaml b/dev-example/config.yaml index 586a16e..2a72bc8 100644 --- a/dev-example/config.yaml +++ b/dev-example/config.yaml @@ -75,6 +75,7 @@ admin: - "*" operator: + - org.jdrupes.vmoperator.vmmgmt.VmMgmt - org.jdrupes.vmoperator.vmaccess.VmAccess user: - org.jdrupes.vmoperator.vmaccess.VmAccess diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java index f577d28..ffb1bf2 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java @@ -1,6 +1,6 @@ /* * VM-Operator - * Copyright (C) 2024 Michael N. Lipp + * Copyright (C) 2025 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 @@ -22,11 +22,15 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import io.kubernetes.client.openapi.models.V1Condition; import io.kubernetes.client.openapi.models.V1ObjectMeta; +import io.kubernetes.client.util.Strings; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.time.Instant; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -34,6 +38,8 @@ import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; +import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import org.jdrupes.vmoperator.util.DataPath; @@ -43,7 +49,11 @@ import org.jdrupes.vmoperator.util.DataPath; @SuppressWarnings({ "PMD.DataClass", "PMD.TooManyMethods" }) public class VmDefinition { - private static ObjectMapper objectMapper + @SuppressWarnings("PMD.FieldNamingConventions") + private static final Logger logger + = Logger.getLogger(VmDefinition.class.getName()); + @SuppressWarnings("PMD.FieldNamingConventions") + private static final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule()); private String kind; @@ -427,6 +437,8 @@ public class VmDefinition { /** * Collect all permissions for the given user with the given roles. + * If permission "takeConsole" is granted, the result will also + * contain "accessConsole" to simplify checks. * * @param user the user * @param roles the roles @@ -434,7 +446,7 @@ public class VmDefinition { */ public Set permissionsFor(String user, Collection roles) { - return this.>> fromSpec("permissions") + var result = this.>> fromSpec("permissions") .orElse(Collections.emptyList()).stream() .filter(p -> DataPath.get(p, "user").map(u -> u.equals(user)) .orElse(false) @@ -443,7 +455,29 @@ public class VmDefinition { .orElse(Collections.emptyList()).stream()) .flatMap(Function.identity()) .map(Permission::parse).map(Set::stream) - .flatMap(Function.identity()).collect(Collectors.toSet()); + .flatMap(Function.identity()) + .collect(Collectors.toCollection(HashSet::new)); + + // Take console implies access console, simplify checks + if (result.contains(Permission.TAKE_CONSOLE)) { + result.add(Permission.ACCESS_CONSOLE); + } + return result; + } + + /** + * Check if the console is accessible. Returns true if the console is + * currently unused, used by the given user or if the permissions + * allow taking over the console. + * + * @param user the user + * @param permissions the permissions + * @return true, if successful + */ + public boolean consoleAccessible(String user, Set permissions) { + return !conditionStatus("ConsoleConnected").orElse(true) + || consoleUser().map(cu -> cu.equals(user)).orElse(true) + || permissions.contains(VmDefinition.Permission.TAKE_CONSOLE); } /** @@ -456,6 +490,78 @@ public class VmDefinition { .map(Number::longValue); } + /** + * Create a connection file. + * + * @param password the password + * @param preferredIpVersion the preferred IP version + * @param deleteConnectionFile the delete connection file + * @return the string + */ + public String connectionFile(String password, + Class preferredIpVersion, boolean deleteConnectionFile) { + var addr = displayIp(preferredIpVersion); + if (addr.isEmpty()) { + logger.severe(() -> "Failed to find display IP for " + name()); + return null; + } + var port = this. fromVm("display", "spice", "port") + .map(Number::longValue); + if (port.isEmpty()) { + logger.severe(() -> "No port defined for display of " + name()); + return null; + } + StringBuffer data = new StringBuffer(100) + .append("[virt-viewer]\ntype=spice\nhost=") + .append(addr.get().getHostAddress()).append("\nport=") + .append(port.get().toString()) + .append('\n'); + if (password != null) { + data.append("password=").append(password).append('\n'); + } + this. fromVm("display", "spice", "proxyUrl") + .ifPresent(u -> { + if (!Strings.isNullOrEmpty(u)) { + data.append("proxy=").append(u).append('\n'); + } + }); + if (deleteConnectionFile) { + data.append("delete-this-file=1\n"); + } + return data.toString(); + } + + private Optional displayIp(Class preferredIpVersion) { + Optional server = fromVm("display", "spice", "server"); + if (server.isPresent()) { + var srv = server.get(); + try { + var addr = InetAddress.getByName(srv); + logger.fine(() -> "Using IP address from CRD for " + + getMetadata().getName() + ": " + addr); + return Optional.of(addr); + } catch (UnknownHostException e) { + logger.log(Level.SEVERE, e, () -> "Invalid server address " + + srv + ": " + e.getMessage()); + return Optional.empty(); + } + } + var addrs = Optional.> ofNullable( + extra("nodeAddresses")).orElse(Collections.emptyList()).stream() + .map(a -> { + try { + return InetAddress.getByName(a); + } catch (UnknownHostException e) { + logger.warning(() -> "Invalid IP address: " + a); + return null; + } + }).filter(a -> a != null).toList(); + logger.fine(() -> "Known IP addresses for " + name() + ": " + addrs); + return addrs.stream() + .filter(a -> preferredIpVersion.isAssignableFrom(a.getClass())) + .findFirst().or(() -> addrs.stream().findFirst()); + } + /** * Hash code. * 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 102a6c9..2060109 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 @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.Optional; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.stream.Collectors; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; @@ -125,7 +126,12 @@ public class VmMonitor extends protected void handleChange(K8sClient client, Watch.Response response) { V1ObjectMeta metadata = response.object.getMetadata(); - VmChannel channel = channelManager.channelGet(metadata.getName()); + AtomicBoolean toBeAdded = new AtomicBoolean(false); + VmChannel channel = channelManager.channel(metadata.getName()) + .orElseGet(() -> { + toBeAdded.set(true); + return channelManager.createChannel(metadata.getName()); + }); // Get full definition and associate with channel as backup var vmModel = response.object; @@ -151,6 +157,9 @@ public class VmMonitor extends + response.object.getMetadata()); return; } + if (toBeAdded.get()) { + channelManager.put(vmDef.name(), channel); + } // Create and fire changed event. Remove channel from channel // manager on completion. diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index 786fedf..fa00482 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -32,10 +32,7 @@ import io.kubernetes.client.util.Strings; import java.io.IOException; import java.net.Inet4Address; import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.time.Duration; -import java.util.Base64; import java.util.Collections; import java.util.EnumSet; import java.util.HashSet; @@ -779,24 +776,8 @@ public class VmAccess extends FreeMarkerConlet { } break; case "openConsole": - var user = WebConsoleUtils.userFromSession(channel.session()) - .map(ConsoleUser::getName).orElse(""); - if (vmDef.conditionStatus("ConsoleConnected").orElse(false) - && vmDef.consoleUser().map(cu -> !cu.equals(user) - && !perms.contains(VmDefinition.Permission.TAKE_CONSOLE)) - .orElse(false)) { - channel.respond(new DisplayNotification( - resourceBundle.getString("consoleTakenNotification"), - Map.of("autoClose", 5_000, "type", "Warning"))); - return; - } - if (perms.contains(VmDefinition.Permission.ACCESS_CONSOLE) - || perms.contains(VmDefinition.Permission.TAKE_CONSOLE)) { - var pwQuery - = Event.onCompletion(new GetDisplayPassword(vmDef, user), - e -> openConsole(vmDef, channel, model, - e.password().orElse(null))); - fire(pwQuery, vmChannel); + if (perms.contains(VmDefinition.Permission.ACCESS_CONSOLE)) { + openConsole(channel, model, vmChannel, vmDef, perms); } break; default:// ignore @@ -804,6 +785,30 @@ public class VmAccess extends FreeMarkerConlet { } } + private void openConsole(ConsoleConnection channel, ResourceModel model, + VmChannel vmChannel, VmDefinition vmDef, Set perms) { + var resourceBundle = resourceBundle(channel.locale()); + var user = WebConsoleUtils.userFromSession(channel.session()) + .map(ConsoleUser::getName).orElse(""); + if (!vmDef.consoleAccessible(user, perms)) { + channel.respond(new DisplayNotification( + resourceBundle.getString("consoleTakenNotification"), + Map.of("autoClose", 5_000, "type", "Warning"))); + return; + } + var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef, user), + e -> { + var data = vmDef.connectionFile(e.password().orElse(null), + preferredIpVersion, deleteConnectionFile); + if (data == null) { + return; + } + channel.respond(new NotifyConletView(type(), + model.getConletId(), "openConsole", data)); + }); + fire(pwQuery, vmChannel); + } + @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", "PMD.UseLocaleWithCaseConversions" }) private void selectResource(NotifyConletModel event, @@ -823,78 +828,6 @@ public class VmAccess extends FreeMarkerConlet { } } - private void openConsole(VmDefinition vmDef, ConsoleConnection connection, - ResourceModel model, String password) { - if (vmDef == null) { - return; - } - var addr = displayIp(vmDef); - if (addr.isEmpty()) { - logger - .severe(() -> "Failed to find display IP for " + vmDef.name()); - return; - } - var port = vmDef. fromVm("display", "spice", "port") - .map(Number::longValue); - if (port.isEmpty()) { - logger - .severe(() -> "No port defined for display of " + vmDef.name()); - return; - } - StringBuffer data = new StringBuffer(100) - .append("[virt-viewer]\ntype=spice\nhost=") - .append(addr.get().getHostAddress()).append("\nport=") - .append(port.get().toString()) - .append('\n'); - if (password != null) { - data.append("password=").append(password).append('\n'); - } - vmDef. fromVm("display", "spice", "proxyUrl") - .ifPresent(u -> { - if (!Strings.isNullOrEmpty(u)) { - data.append("proxy=").append(u).append('\n'); - } - }); - if (deleteConnectionFile) { - data.append("delete-this-file=1\n"); - } - connection.respond(new NotifyConletView(type(), - model.getConletId(), "openConsole", "application/x-virt-viewer", - Base64.getEncoder().encodeToString(data.toString().getBytes()))); - } - - private Optional displayIp(VmDefinition vmDef) { - Optional server = vmDef.fromVm("display", "spice", "server"); - if (server.isPresent()) { - var srv = server.get(); - try { - var addr = InetAddress.getByName(srv); - logger.fine(() -> "Using IP address from CRD for " - + vmDef.getMetadata().getName() + ": " + addr); - return Optional.of(addr); - } catch (UnknownHostException e) { - logger.log(Level.SEVERE, e, () -> "Invalid server address " - + srv + ": " + e.getMessage()); - return Optional.empty(); - } - } - var addrs = Optional.> ofNullable(vmDef - .extra("nodeAddresses")).orElse(Collections.emptyList()).stream() - .map(a -> { - try { - return InetAddress.getByName(a); - } catch (UnknownHostException e) { - logger.warning(() -> "Invalid IP address: " + a); - return null; - } - }).filter(a -> a != null).toList(); - logger.fine(() -> "Known IP addresses for " - + vmDef.name() + ": " + addrs); - return addrs.stream() - .filter(a -> preferredIpVersion.isAssignableFrom(a.getClass())) - .findFirst().or(() -> addrs.stream().findFirst()); - } - private void confirmReset(NotifyConletModel event, ConsoleConnection channel, ResourceModel model, ResourceBundle resourceBundle) throws TemplateNotFoundException, diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts index de65216..9d2e134 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts @@ -198,7 +198,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess", }); JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess", - "openConsole", function(_conletId: string, mimeType: string, data: string) { + "openConsole", function(_conletId: string, data: string) { let target = document.getElementById( "org.jdrupes.vmoperator.vmaccess.VmAccess.target"); if (!target) { @@ -208,7 +208,8 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess", target.setAttribute("style", "display: none;"); document.querySelector("body")!.append(target); } - const url = "data:" + mimeType + ";base64," + data; + const url = "data:application/x-virt-viewer;base64," + + window.btoa(data); window.open(url, target.id); }); diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html index a57c533..178d069 100644 --- a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html @@ -1,6 +1,7 @@
+ data-jgwc-on-unload="JGConsole.jgwc.unmountVueApps" + data-conlet-resource-base="${conletResource('')}">
+ + + + + + + + + + + + + + + + diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer-off.svg b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer-off.svg new file mode 100644 index 0000000..27c11ae --- /dev/null +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer-off.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer.svg b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer.svg new file mode 100644 index 0000000..f7a6b94 --- /dev/null +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/computer.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n.properties b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n.properties index 0ab15fd..fb0362f 100644 --- a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n.properties +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n.properties @@ -17,3 +17,8 @@ usedBy = Used by usedFrom = Used from vmActions = Actions vmname = Name + +confirmResetTitle = Confirm reset +confirmResetMsg = Resetting the VM may cause loss of data. \ + Please confirm to continue. +consoleTakenNotification = Console access is locked by another user. diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n_de.properties b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n_de.properties index c8d8c4d..2c142ae 100644 --- a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n_de.properties +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/l10n_de.properties @@ -24,6 +24,12 @@ vmname = Name Value\ is\ above\ maximum = Wert ist zu groß Illegal\ format = Ungültiges Format +confirmResetTitle = Zurücksetzen bestätigen +confirmResetMsg = Zurücksetzen der VM kann zu Datenverlust führen. \ + Bitte bestätigen um fortzufahren. +consoleTakenNotification = Die Konsole wird von einem anderen Benutzer verwendet. + +Open\ console = Konsole anzeigen Start\ VM = VM Starten Stop\ VM = VM Anhalten diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java index 3842cbc..2959f46 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java @@ -27,15 +27,22 @@ import io.kubernetes.client.custom.Quantity.Format; import java.io.IOException; import java.math.BigDecimal; import java.math.BigInteger; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.time.Duration; import java.time.Instant; +import java.util.Collections; import java.util.EnumSet; +import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.ResourceBundle; import java.util.Set; import org.jdrupes.vmoperator.common.K8sObserver; import org.jdrupes.vmoperator.common.VmDefinition; +import org.jdrupes.vmoperator.common.VmDefinition.Permission; import org.jdrupes.vmoperator.manager.events.ChannelTracker; +import org.jdrupes.vmoperator.manager.events.GetDisplayPassword; import org.jdrupes.vmoperator.manager.events.ModifyVm; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; @@ -44,13 +51,17 @@ import org.jgrapes.core.Channel; import org.jgrapes.core.Event; import org.jgrapes.core.Manager; import org.jgrapes.core.annotation.Handler; +import org.jgrapes.util.events.ConfigurationUpdate; import org.jgrapes.webconsole.base.Conlet.RenderMode; import org.jgrapes.webconsole.base.ConletBaseModel; import org.jgrapes.webconsole.base.ConsoleConnection; -import org.jgrapes.webconsole.base.events.AddConletRequest; +import org.jgrapes.webconsole.base.ConsoleRole; +import org.jgrapes.webconsole.base.ConsoleUser; +import org.jgrapes.webconsole.base.WebConsoleUtils; import org.jgrapes.webconsole.base.events.AddConletType; import org.jgrapes.webconsole.base.events.AddPageResources.ScriptResource; import org.jgrapes.webconsole.base.events.ConsoleReady; +import org.jgrapes.webconsole.base.events.DisplayNotification; import org.jgrapes.webconsole.base.events.NotifyConletModel; import org.jgrapes.webconsole.base.events.NotifyConletView; import org.jgrapes.webconsole.base.events.RenderConlet; @@ -61,10 +72,12 @@ import org.jgrapes.webconsole.base.freemarker.FreeMarkerConlet; /** * The Class {@link VmMgmt}. */ -@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", - "PMD.CouplingBetweenObjects" }) +@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.CouplingBetweenObjects", + "PMD.ExcessiveImports" }) public class VmMgmt extends FreeMarkerConlet { + private Class preferredIpVersion = Inet4Address.class; + private boolean deleteConnectionFile = true; private static final Set MODES = RenderMode.asSet( RenderMode.Preview, RenderMode.View); private final ChannelTracker { setPeriodicRefresh(Duration.ofMinutes(1), () -> new Update()); } + /** + * Configure the component. + * + * @param event the event + */ + @SuppressWarnings({ "unchecked", "PMD.AvoidDuplicateLiterals" }) + @Handler + public void onConfigurationUpdate(ConfigurationUpdate event) { + event.structured("/Manager/GuiHttpServer" + + "/ConsoleWeblet/WebConsole/ComponentCollector/VmAccess") + .ifPresent(c -> { + try { + var dispRes = (Map) c + .getOrDefault("displayResource", + Collections.emptyMap()); + switch ((String) dispRes.getOrDefault("preferredIpVersion", + "")) { + case "ipv6": + preferredIpVersion = Inet6Address.class; + break; + case "ipv4": + default: + preferredIpVersion = Inet4Address.class; + break; + } + + // Delete connection file + deleteConnectionFile + = Optional.ofNullable(c.get("deleteConnectionFile")) + .filter(v -> v instanceof String) + .map(v -> (String) v) + .map(Boolean::parseBoolean).orElse(true); + } catch (ClassCastException e) { + logger.config("Malformed configuration: " + e.getMessage()); + } + }); + } + /** * On {@link ConsoleReady}, fire the {@link AddConletType}. * @@ -117,7 +168,7 @@ public class VmMgmt extends FreeMarkerConlet { } @Override - protected Optional createNewState(AddConletRequest event, + protected Optional createStateRepresentation(Event event, ConsoleConnection connection, String conletId) throws Exception { return Optional.of(new VmsModel(conletId)); } @@ -160,17 +211,25 @@ public class VmMgmt extends FreeMarkerConlet { } if (sendVmInfos) { for (var item : channelTracker.values()) { - channel.respond(new NotifyConletView(type(), - conletId, "updateVm", - simplifiedVmDefinition(item.associated()))); + updateVm(channel, conletId, item.associated()); } } - return renderedAs; } + private void updateVm(ConsoleConnection channel, String conletId, + VmDefinition vmDef) { + var user = WebConsoleUtils.userFromSession(channel.session()) + .map(ConsoleUser::getName).orElse(null); + var roles = WebConsoleUtils.rolesFromSession(channel.session()) + .stream().map(ConsoleRole::getName).toList(); + channel.respond(new NotifyConletView(type(), conletId, "updateVm", + simplifiedVmDefinition(vmDef, user, roles))); + } + @SuppressWarnings("PMD.AvoidDuplicateLiterals") - private Map simplifiedVmDefinition(VmDefinition vmDef) { + private Map simplifiedVmDefinition(VmDefinition vmDef, + String user, List roles) { // Convert RAM sizes to unitless numbers var spec = DataPath.deepCopy(vmDef.spec()); var vmSpec = DataPath.> get(spec, "vm").get(); @@ -191,7 +250,9 @@ public class VmMgmt extends FreeMarkerConlet { "name", vmDef.name()), "spec", spec, "status", status, - "nodeName", vmDef.extra("nodeName")); + "nodeName", vmDef.extra("nodeName"), + "permissions", vmDef.permissionsFor(user, roles).stream() + .map(VmDefinition.Permission::toString).toList()); } /** @@ -221,8 +282,7 @@ public class VmMgmt extends FreeMarkerConlet { channelTracker.put(vmName, channel, vmDef); for (var entry : conletIdsByConsoleConnection().entrySet()) { for (String conletId : entry.getValue()) { - entry.getKey().respond(new NotifyConletView(type(), - conletId, "updateVm", simplifiedVmDefinition(vmDef))); + updateVm(entry.getKey(), conletId, vmDef); } } } @@ -337,22 +397,35 @@ public class VmMgmt extends FreeMarkerConlet { @Override @SuppressWarnings("PMD.AvoidDecimalLiteralsInBigDecimalConstructor") protected void doUpdateConletState(NotifyConletModel event, - ConsoleConnection channel, VmsModel conletState) - throws Exception { + ConsoleConnection channel, VmsModel model) throws Exception { event.stop(); String vmName = event.param(0); - var vmChannel = channelTracker.channel(vmName).orElse(null); - if (vmChannel == null) { + var value = channelTracker.value(vmName); + var vmChannel = value.map(v -> v.channel()).orElse(null); + var vmDef = value.map(v -> v.associated()).orElse(null); + if (vmDef == null) { return; } + var user = WebConsoleUtils.userFromSession(channel.session()) + .map(ConsoleUser::getName).orElse(""); + var roles = WebConsoleUtils.rolesFromSession(channel.session()) + .stream().map(ConsoleRole::getName).toList(); + var perms = vmDef.permissionsFor(user, roles); switch (event.method()) { case "start": - fire(new ModifyVm(vmName, "state", "Running", vmChannel)); + if (perms.contains(VmDefinition.Permission.START)) { + fire(new ModifyVm(vmName, "state", "Running", vmChannel)); + } break; case "stop": - fire(new ModifyVm(vmName, "state", "Stopped", vmChannel)); + if (perms.contains(VmDefinition.Permission.STOP)) { + fire(new ModifyVm(vmName, "state", "Stopped", vmChannel)); + } break; case "openConsole": + if (perms.contains(VmDefinition.Permission.ACCESS_CONSOLE)) { + openConsole(channel, model, vmChannel, vmDef, user, perms); + } break; case "cpus": fire(new ModifyVm(vmName, "currentCpus", @@ -370,6 +443,29 @@ public class VmMgmt extends FreeMarkerConlet { } } + private void openConsole(ConsoleConnection channel, VmsModel model, + VmChannel vmChannel, VmDefinition vmDef, String user, + Set perms) { + ResourceBundle resourceBundle = resourceBundle(channel.locale()); + if (!vmDef.consoleAccessible(user, perms)) { + channel.respond(new DisplayNotification( + resourceBundle.getString("consoleTakenNotification"), + Map.of("autoClose", 5_000, "type", "Warning"))); + return; + } + var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef, user), + e -> { + var data = vmDef.connectionFile(e.password().orElse(null), + preferredIpVersion, deleteConnectionFile); + if (data == null) { + return; + } + channel.respond(new NotifyConletView(type(), + model.getConletId(), "openConsole", data)); + }); + fire(pwQuery, vmChannel); + } + @Override protected boolean doSetLocale(SetLocale event, ConsoleConnection channel, String conletId) throws Exception { diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts index c7f8519..40534b1 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts @@ -104,6 +104,7 @@ window.orgJDrupesVmOperatorVmMgmt.initView = (viewDom: HTMLElement, setup(_props: object) { const conletId: string = (viewDom.parentNode!).dataset["conletId"]!; + const resourceBase = (viewDom).dataset.conletResourceBase; const controller = reactive(new JGConsole.TableController([ ["name", "vmname"], @@ -162,9 +163,9 @@ window.orgJDrupesVmOperatorVmMgmt.initView = (viewDom: HTMLElement, } return { - controller, vmInfos, filteredData, detailsByName, localize, - shortDateTime, formatMemory, vmAction, cic, parseMemory, - maximumCpus, + controller, vmInfos, filteredData, detailsByName, + resourceBase, localize, shortDateTime, formatMemory, + vmAction, cic, parseMemory, maximumCpus, scopedId: (id: string) => { return idScope.scopedId(id); } }; } @@ -219,3 +220,20 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmmgmt.VmMgmt", Object.assign(vmSummary, summary); }); +JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmmgmt.VmMgmt", + "openConsole", function(_conletId: string, data: string) { + let target = document.getElementById( + "org.jdrupes.vmoperator.vmmgt.VmMgmt.target"); + if (!target) { + target = document.createElement("iframe"); + target.id = "org.jdrupes.vmoperator.vmmgt.VmMgmt.target"; + target.setAttribute("name", target.id); + target.setAttribute("style", "display: none;"); + document.querySelector("body")!.append(target); + } + const url = "data:application/x-virt-viewer;base64," + + window.btoa(data); + window.open(url, target.id); + }); + + diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss index 3a3f0d7..7a7af97 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss @@ -103,6 +103,10 @@ .jdrupes-vmoperator-vmmgmt-view-action-list { white-space: nowrap; + & > * + * { + margin-left: 0.5em; + } + [role=button] { padding: 0.25rem; @@ -110,4 +114,14 @@ box-shadow: var(--darkening); } } + + img { + display: inline; + height: 1.5em; + vertical-align: top; + + &[aria-disabled=''], &[aria-disabled='true'] { + opacity: 0.4; + } + } } From 8d96307bb59c92351666a5002d014f03750bb839 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 29 Jan 2025 18:42:10 +0100 Subject: [PATCH 156/342] Add reset action to VM management. --- .../jdrupes/vmoperator/vmaccess/VmAccess.java | 28 +++++----- .../vmmgmt/VmMgmt-confirmReset.ftl.html | 13 +++++ .../vmoperator/vmmgmt/VmMgmt-view.ftl.html | 10 ++++ .../vmoperator/vmmgmt/l10n_de.properties | 1 + .../org/jdrupes/vmoperator/vmmgmt/VmMgmt.java | 31 ++++++++++- .../vmmgmt/browser/VmMgmt-functions.ts | 10 +++- .../vmmgmt/browser/VmMgmt-style.scss | 51 ++++++++++++++++++- 7 files changed, 126 insertions(+), 18 deletions(-) create mode 100644 org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-confirmReset.ftl.html diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index fa00482..eea1eae 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -785,6 +785,20 @@ public class VmAccess extends FreeMarkerConlet { } } + private void confirmReset(NotifyConletModel event, + ConsoleConnection channel, ResourceModel model, + ResourceBundle resourceBundle) throws TemplateNotFoundException, + MalformedTemplateNameException, ParseException, IOException { + Template tpl = freemarkerConfig() + .getTemplate("VmAccess-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"))); + } + private void openConsole(ConsoleConnection channel, ResourceModel model, VmChannel vmChannel, VmDefinition vmDef, Set perms) { var resourceBundle = resourceBundle(channel.locale()); @@ -828,20 +842,6 @@ public class VmAccess extends FreeMarkerConlet { } } - private void confirmReset(NotifyConletModel event, - ConsoleConnection channel, ResourceModel model, - ResourceBundle resourceBundle) throws TemplateNotFoundException, - MalformedTemplateNameException, ParseException, IOException { - Template tpl = freemarkerConfig() - .getTemplate("VmAccess-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.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-confirmReset.ftl.html b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-confirmReset.ftl.html new file mode 100644 index 0000000..d174707 --- /dev/null +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-confirmReset.ftl.html @@ -0,0 +1,13 @@ +
+

${_("confirmResetMsg")}

+

+ + + + + + +

+
\ No newline at end of file diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html index 178d069..4dfc8d7 100644 --- a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html @@ -72,6 +72,16 @@ v-on:click="vmAction(entry.name, 'stop')"> + + + + + + { } @Override - @SuppressWarnings("PMD.AvoidDecimalLiteralsInBigDecimalConstructor") + @SuppressWarnings({ "PMD.AvoidDecimalLiteralsInBigDecimalConstructor", + "PMD.NcssCount" }) protected void doUpdateConletState(NotifyConletModel event, ConsoleConnection channel, VmsModel model) throws Exception { event.stop(); @@ -422,6 +425,16 @@ public class VmMgmt extends FreeMarkerConlet { fire(new ModifyVm(vmName, "state", "Stopped", vmChannel)); } break; + case "reset": + if (perms.contains(VmDefinition.Permission.RESET)) { + confirmReset(event, channel, model, vmName); + } + break; + case "resetConfirmed": + if (perms.contains(VmDefinition.Permission.RESET)) { + fire(new ResetVm(vmName), vmChannel); + } + break; case "openConsole": if (perms.contains(VmDefinition.Permission.ACCESS_CONSOLE)) { openConsole(channel, model, vmChannel, vmDef, user, perms); @@ -443,6 +456,22 @@ public class VmMgmt extends FreeMarkerConlet { } } + private void confirmReset(NotifyConletModel event, + ConsoleConnection channel, VmsModel model, String vmName) + throws TemplateNotFoundException, + MalformedTemplateNameException, ParseException, IOException { + Template tpl = freemarkerConfig() + .getTemplate("VmMgmt-confirmReset.ftl.html"); + ResourceBundle resourceBundle = resourceBundle(channel.locale()); + var fmModel = fmModel(event, channel, model.getConletId(), model); + fmModel.put("vmName", vmName); + channel.respond(new OpenModalDialog(type(), model.getConletId(), + processTemplate(event, tpl, fmModel)) + .addOption("cancelable", true).addOption("closeLabel", "") + .addOption("title", + resourceBundle.getString("confirmResetTitle"))); + } + private void openConsole(ConsoleConnection channel, VmsModel model, VmChannel vmChannel, VmDefinition vmDef, String user, Set perms) { diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts index 40534b1..f0407b7 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts @@ -34,7 +34,9 @@ declare global { interface Window { orgJDrupesVmOperatorVmMgmt: { initPreview?: (previewDom: HTMLElement, isUpdate: boolean) => void, - initView?: (viewDom: HTMLElement, isUpdate: boolean) => void + initView?: (viewDom: HTMLElement, isUpdate: boolean) => void, + confirmReset?: (conletType: string, conletId: string, + vmName: string) => void } } } @@ -236,4 +238,8 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmmgmt.VmMgmt", window.open(url, target.id); }); - +window.orgJDrupesVmOperatorVmMgmt.confirmReset = + (conletType: string, conletId: string, vmName: string) => { + JGConsole.instance.closeModalDialog(conletType, conletId); + JGConsole.notifyConletModel(conletId, "resetConfirmed", vmName); +} diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss index 7a7af97..4c11b65 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss @@ -114,7 +114,24 @@ box-shadow: var(--darkening); } } - + + 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; + } + } + img { display: inline; height: 1.5em; @@ -125,3 +142,35 @@ } } } + +.jdrupes-vmoperator-vmmgmt.jdrupes-vmoperator-vmmgmt-confirm-reset { + + [role=button] { + padding: 0.25rem; + + &:not([aria-disabled]):hover, &[aria-disabled='false']:hover { + box-shadow: var(--darkening); + } + } + + span[role="button"].svg-icon { + display: inline-block; + line-height: 1; + /* Align with forkawesome */ + font-size: 14px; + fill: var(--danger); + + &[aria-disabled="true"], &[aria-disabled=""] { + fill: var(--disabled); + } + + svg { + width: 2.5em; + height: 2.5em; + } + } + + p { + text-align: center; + } +} From ebda41346a096c88c41e91c3b06e0ddbe45bc31a Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 29 Jan 2025 21:01:49 +0100 Subject: [PATCH 157/342] Simplify permission management. --- .../org/jdrupes/vmoperator/vmaccess/VmAccess.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index eea1eae..c82ccd4 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -546,26 +546,26 @@ public class VmAccess extends FreeMarkerConlet { .map(ConsoleUser::getName).orElse(null); var roles = WebConsoleUtils.rolesFromSession(session) .stream().map(ConsoleRole::getName).toList(); - Set result = new HashSet<>(); if (model.mode() == ResourceModel.Mode.POOL) { if (pool == null) { pool = appPipeline.fire(new GetPools() .withName(model.name())).get().stream().findFirst() .orElse(null); } - if (pool != null) { - result.addAll(pool.permissionsFor(user, roles)); + if (pool == null) { + return Collections.emptySet(); } + return pool.permissionsFor(user, roles); } if (vmDef == null) { vmDef = appPipeline.fire(new GetVms().assignedFrom(model.name()) .assignedTo(user)).get().stream().map(VmData::definition) .findFirst().orElse(null); } - if (vmDef != null) { - result.addAll(vmDef.permissionsFor(user, roles)); + if (vmDef == null) { + return Collections.emptySet(); } - return result; + return vmDef.permissionsFor(user, roles); } private void updatePreview(ConsoleConnection channel, ResourceModel model, From e447a944dce88e3eb0704549ce0e30dca3fdff09 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 30 Jan 2025 16:55:54 +0100 Subject: [PATCH 158/342] Generate metaData even if only cloudInit is specified. --- .../vmoperator/manager/runnerConfig.ftl.yaml | 6 +----- .../org/jdrupes/vmoperator/manager/Reconciler.java | 13 +++++++------ 2 files changed, 8 insertions(+), 11 deletions(-) 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 214b5b8..8a50a5e 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 @@ -58,11 +58,7 @@ data: # Forward the cloud-init data if provided <#if spec.cloudInit??> cloudInit: - <#if spec.cloudInit.metaData??> - metaData: ${ toJson(adjustCloudInitMeta(spec.cloudInit.metaData, cr.metadata())) } - <#else> - metaData: {} - + metaData: ${ toJson(adjustCloudInitMeta(spec.cloudInit.metaData!{}, cr.metadata())) } <#if spec.cloudInit.userData??> userData: ${ toJson(spec.cloudInit.userData) } <#else> 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 3fa2ffe..641247a 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 @@ -29,7 +29,9 @@ import freemarker.template.TemplateException; import freemarker.template.TemplateExceptionHandler; import freemarker.template.TemplateHashModel; import freemarker.template.TemplateMethodModelEx; +import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; +import freemarker.template.utility.DeepUnwrap; import io.kubernetes.client.custom.Quantity; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.V1ObjectMeta; @@ -53,7 +55,6 @@ 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.DataPath; import org.jdrupes.vmoperator.util.ExtendedObjectWrapper; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; @@ -354,8 +355,9 @@ public class Reconciler extends Component { return ""; } try { - var imageUri = new URI("file://" + Constants.IMAGE_REPO_PATH - + "/").resolve(image); + var imageUri + = new URI("file://" + Constants.IMAGE_REPO_PATH + "/") + .resolve(image); if ("file".equals(imageUri.getScheme())) { return imageUri.getPath(); } @@ -374,9 +376,8 @@ public class Reconciler extends Component { public Object exec(@SuppressWarnings("rawtypes") List arguments) throws TemplateModelException { @SuppressWarnings("unchecked") - var res = (Map) DataPath - .deepCopy(((AdapterTemplateModel) arguments.get(0)) - .getAdaptedObject(Object.class)); + var res = new HashMap<>((Map) DeepUnwrap + .unwrap((TemplateModel) arguments.get(0))); var metadata = (V1ObjectMeta) ((AdapterTemplateModel) arguments.get(1)) .getAdaptedObject(Object.class); From 99c96e44c37f7eb620d809a29772751aacdfb24b Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 30 Jan 2025 22:00:10 +0100 Subject: [PATCH 159/342] Allow access to vmpools. --- deploy/vmop-role.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/deploy/vmop-role.yaml b/deploy/vmop-role.yaml index 55447e6..c96fb47 100644 --- a/deploy/vmop-role.yaml +++ b/deploy/vmop-role.yaml @@ -9,6 +9,7 @@ rules: - vmoperator.jdrupes.org resources: - vms + - vmpools verbs: - '*' - apiGroups: From 29dd6aab82f6eb8cf4c47183856f46c3e185bddf Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 30 Jan 2025 22:04:41 +0100 Subject: [PATCH 160/342] Javadoc fixes. --- .../src/org/jdrupes/vmoperator/manager/PoolMonitor.java | 1 - .../src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java | 4 ++-- .../src/org/jdrupes/vmoperator/vmaccess/VmAccess.java | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java index 0606650..b83c0f5 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java @@ -64,7 +64,6 @@ public class PoolMonitor extends * Instantiates a new VM pool manager. * * @param componentChannel the component channel - * @param channelManager the channel manager */ public PoolMonitor(Channel componentChannel) { super(componentChannel, K8sDynamicModel.class, diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java index 1c260c7..9683457 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java @@ -111,12 +111,12 @@ public class VmDefUpdater extends Component { /** * Update condition. * - * @param apiClient the api client - * @param from the vM definition + * @param from the VM definition * @param status the current status * @param type the condition type * @param state the new state * @param reason the reason for the change + * @param message the message */ protected void updateCondition(VmDefinitionModel from, JsonObject status, String type, boolean state, String reason, String message) { diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index c82ccd4..0015d6c 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -685,8 +685,7 @@ public class VmAccess extends FreeMarkerConlet { * On vm pool changed. * * @param event the event - * @param channel the channel - * @throws InterruptedException + * @throws InterruptedException the interrupted exception */ @Handler(namedChannels = "manager") @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") From 150b9f29083f53fd05fde1d8a2c6d4285daa0732 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 30 Jan 2025 22:14:09 +0100 Subject: [PATCH 161/342] Fix spaces. --- dev-example/Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dev-example/Readme.md b/dev-example/Readme.md index 516fb7e..3676411 100644 --- a/dev-example/Readme.md +++ b/dev-example/Readme.md @@ -3,9 +3,9 @@ The CRD must be deployed independently. Apart from that, the `kustomize.yaml` -* creates a small cdrom image repository and +* creates a small cdrom image repository and -* deploys the operator in namespace `vmop-dev` with a replica of 0. +* deploys the operator in namespace `vmop-dev` with a replica of 0. This allows you to run the manager in your IDE. From ecd7ba7baf7dcb8643786c9eb24c4e9c2cea49f2 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Thu, 30 Jan 2025 22:17:35 +0100 Subject: [PATCH 162/342] Fix trailing space. --- README.md | 2 +- dev-example/Readme.md | 2 +- overview.md | 2 +- webpages/vm-operator/controller.md | 46 +++++++++++++++--------------- webpages/vm-operator/index.md | 12 ++++---- webpages/vm-operator/manager.md | 46 +++++++++++++++--------------- webpages/vm-operator/runner.md | 36 +++++++++++------------ webpages/vm-operator/upgrading.md | 16 +++++------ webpages/vm-operator/user-gui.md | 12 ++++---- webpages/vm-operator/webgui.md | 20 ++++++------- 10 files changed, 97 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 9118f9d..4c989b6 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ # Run Qemu in Kubernetes Pods The goal of this project is to provide easy to use and flexible components -for running Qemu based VMs in Kubernetes pods. +for running Qemu based VMs in Kubernetes pods. See the [project's home page](https://jdrupes.org/vm-operator/) for details. diff --git a/dev-example/Readme.md b/dev-example/Readme.md index 3676411..ba381e1 100644 --- a/dev-example/Readme.md +++ b/dev-example/Readme.md @@ -1,7 +1,7 @@ # Example setup for development The CRD must be deployed independently. Apart from that, the -`kustomize.yaml` +`kustomize.yaml` * creates a small cdrom image repository and diff --git a/overview.md b/overview.md index 447a33c..30d595e 100644 --- a/overview.md +++ b/overview.md @@ -3,7 +3,7 @@ A Kubernetes operator for running VMs as pods. VM-Operator =========== -The VM-operator enables you to easily run Qemu based VMs as pods +The VM-operator enables you to easily run Qemu based VMs as pods in Kubernetes. It is built on the [JGrapes](https://mnlipp.github.io/jgrapes/) event driven framework. diff --git a/webpages/vm-operator/controller.md b/webpages/vm-operator/controller.md index 17ca790..cc6a274 100644 --- a/webpages/vm-operator/controller.md +++ b/webpages/vm-operator/controller.md @@ -5,12 +5,12 @@ layout: vm-operator # The Controller -The controller component (which is part of the manager) monitors -custom resources of kind `VirtualMachine`. It creates or modifies +The controller component (which is part of the manager) monitors +custom resources of kind `VirtualMachine`. It creates or modifies other resources in the cluster as required to get the VM defined -by the CR up and running. +by the CR up and running. -Here is the sample definition of a VM from the +Here is the sample definition of a VM from the ["local-path" example](https://github.com/mnlipp/VM-Operator/tree/main/example/local-path): ```yaml @@ -28,10 +28,10 @@ spec: currentCpus: 2 maximumRam: 8Gi currentRam: 4Gi - + networks: - user: {} - + disks: - volumeClaimTemplate: metadata: @@ -58,9 +58,9 @@ spec: # generateSecret: false ``` -## Pod management +## Pod management -The central resource created by the controller is a +The central resource created by the controller is a [`Pod`](https://kubernetes.io/docs/concepts/workloads/pods/) with the same name as the VM (`metadata.name`). The pod is created only if `spec.vm.state` is "Running" (default is "Stopped" which deletes the @@ -72,7 +72,7 @@ and thus the VM is automatically restarted. If set to `true`, the VM's state is set to "Stopped" when the VM terminates and the pod is deleted. -[^oldSts]: Before version 3.4, the operator created a +[^oldSts]: Before version 3.4, the operator created a [stateful set](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) that in turn created the pod and the PVCs (see below). @@ -113,7 +113,7 @@ as shown in this example: ``` The disk will be available as "/dev/*name*-disk" in the VM, -using the string from `.volumeClaimTemplate.metadata.name` as *name*. +using the string from `.volumeClaimTemplate.metadata.name` as *name*. If no name is defined in the metadata, then "/dev/disk-*n*" is used instead, with *n* being the index of the volume claim template in the list of disks. @@ -140,28 +140,28 @@ the PVCs by label in a delete command. ## Choosing an image for the runner -The image used for the runner can be configured with +The image used for the runner can be configured with [`spec.image`](https://github.com/mnlipp/VM-Operator/blob/7e094e720b7b59a5e50f4a9a4ad29a6000ec76e6/deploy/crds/vms-crd.yaml#L19). This is a mapping with either a single key `source` or a detailed configuration using the keys `repository`, `path` etc. -Currently two runner images are maintained. One that is based on -Arch Linux (`ghcr.io/mnlipp/org.jdrupes.vmoperator.runner.qemu-arch`) and a +Currently two runner images are maintained. One that is based on +Arch Linux (`ghcr.io/mnlipp/org.jdrupes.vmoperator.runner.qemu-arch`) and a second one based on Alpine (`ghcr.io/mnlipp/org.jdrupes.vmoperator.runner.qemu-alpine`). -Starting with release 1.0, all versions of runner images and managers +Starting with release 1.0, all versions of runner images and managers that have the same major release number are guaranteed to be compatible. ## Generating cloud-init data -*Since: 2.2.0* +*Since: 2.2.0* The optional object `.spec.cloudInit` with sub-objects `.cloudInit.metaData`, -`.cloudInit.userData` and `.cloudInit.networkConfig` can be used to provide +`.cloudInit.userData` and `.cloudInit.networkConfig` can be used to provide data for [cloud-init](https://cloudinit.readthedocs.io/en/latest/index.html). The data from the CRD will be made available to the VM by the runner -as a vfat formatted disk (see the description of +as a vfat formatted disk (see the description of [NoCloud](https://cloudinit.readthedocs.io/en/latest/reference/datasources/nocloud.html)). If `.metaData.instance-id` is not defined, the controller automatically @@ -180,9 +180,9 @@ generated automatically by the runner.) *Since: 2.3.0* You can define a display password using a Kubernetes secret. -When you start a VM, the controller checks if there is a secret -with labels "app.kubernetes.io/name: vm-runner, -app.kubernetes.io/component: display-secret, +When you start a VM, the controller checks if there is a secret +with labels "app.kubernetes.io/name: vm-runner, +app.kubernetes.io/component: display-secret, app.kubernetes.io/instance: *vmname*" in the namespace of the VM definition. The name of the secret can be chosen freely. @@ -204,13 +204,13 @@ data: ``` If such a secret for the VM is found, the VM is configured to use -the display password specified. The display password in the secret +the display password specified. The display password in the secret can be updated while the VM runs[^delay]. Activating/deactivating the display password while a VM runs is not supported by Qemu and therefore requires stopping the VM, adding/removing the secret and restarting the VM. -[^delay]: Be aware of the possible delay, see e.g. +[^delay]: Be aware of the possible delay, see e.g. [here](https://web.archive.org/web/20240223073838/https://ahmet.im/blog/kubernetes-secret-volumes-delay/). *Since: 3.0.0* @@ -221,7 +221,7 @@ values are those defined by qemu (`+n` seconds from now, `n` Unix timestamp, `never` and `now`). Unless `spec.vm.display.spice.generateSecret` is set to `false` in the VM -definition (CRD), the controller creates a secret for the display +definition (CRD), the controller creates a secret for the display password automatically if none is found. The secret is created with a random password that expires immediately, which makes the display effectively inaccessible until the secret is modified. diff --git a/webpages/vm-operator/index.md b/webpages/vm-operator/index.md index 9859fe2..baf8e20 100644 --- a/webpages/vm-operator/index.md +++ b/webpages/vm-operator/index.md @@ -15,9 +15,9 @@ The image used for the VM pods combines Qemu and a control program for starting and managing the Qemu process. This application is called "[the runner](runner.html)". -While you can deploy a runner manually (or with the help of some +While you can deploy a runner manually (or with the help of some helm templates), the preferred way is to deploy "[the manager](manager.html)" -application which acts as a Kubernetes operator for runners +application which acts as a Kubernetes operator for runners and thus the VMs. If you just want to try out things, you can skip the remainder of this @@ -25,11 +25,11 @@ page and proceed to "[the manager](manager.html)". ## Motivation The project was triggered by a remark in the discussion about RedHat -[dropping SPICE support](https://bugzilla.redhat.com/show_bug.cgi?id=2030592) +[dropping SPICE support](https://bugzilla.redhat.com/show_bug.cgi?id=2030592) from the RHEL packages. Which means that you have to run Qemu in a container on RHEL and derivatives if you want to continue using Spice. So KubeVirt comes to mind. But -[one comment](https://bugzilla.redhat.com/show_bug.cgi?id=2030592#c4) +[one comment](https://bugzilla.redhat.com/show_bug.cgi?id=2030592#c4) mentioned that the [KubeVirt](https://kubevirt.io/) project isn't interested in supporting SPICE either. @@ -44,7 +44,7 @@ much as possible. ## VMs and Pods VMs are not the typical workload managed by Kubernetes. You can neither -have replicas nor can the containers simply be restarted without a major +have replicas nor can the containers simply be restarted without a major impact on the "application". So there are many features for managing pods that we cannot make use of. Qemu in its container can only be deployed as a pod or using a stateful set with replica 1, which is rather @@ -57,6 +57,6 @@ A second look, however, reveals that Kubernetes has more to offer. * Its managing features *are* useful for running the component that manages the pods with the VMs. -And if you use Kubernetes anyway, well then the VMs within Kubernetes +And if you use Kubernetes anyway, well then the VMs within Kubernetes provide you with a unified view of all (or most of) your workloads, which simplifies the maintenance of your platform. diff --git a/webpages/vm-operator/manager.md b/webpages/vm-operator/manager.md index 8e6ebb4..c1965f1 100644 --- a/webpages/vm-operator/manager.md +++ b/webpages/vm-operator/manager.md @@ -7,13 +7,13 @@ layout: vm-operator The Manager is the program that provides the controller from the [operator pattern](https://github.com/cncf/tag-app-delivery/blob/eece8f7307f2970f46f100f51932db106db46968/operator-wg/whitepaper/Operator-WhitePaper_v1-0.md#operator-components-in-kubernetes) -together with a web user interface. It should be run in a container in the cluster. +together with a web user interface. It should be run in a container in the cluster. ## Installation A manager instance manages the VMs in its own namespace. The only common (and therefore cluster scoped) resource used by all instances -is the CRD. It is available +is the CRD. It is available [here](https://github.com/mnlipp/VM-Operator/raw/main/deploy/crds/vms-crd.yaml) and must be created first. @@ -25,24 +25,24 @@ The example above uses the CRD from the main branch. This is okay if you apply it once. If you want to preserve the link for automatic upgrades, you should use a link that points to one of the release branches. -The next step is to create a namespace for the manager and the VMs, e.g. +The next step is to create a namespace for the manager and the VMs, e.g. `vmop-demo`. ```sh kubectl create namespace vmop-demo ``` -Finally you have to create an account, the role, the binding etc. The -default files for creating these resources using the default namespace -can be found in the +Finally you have to create an account, the role, the binding etc. The +default files for creating these resources using the default namespace +can be found in the [deploy](https://github.com/mnlipp/VM-Operator/tree/main/deploy) -directory. I recommend to use -[kustomize](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/) to create your own configuration. +directory. I recommend to use +[kustomize](https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/) to create your own configuration. ## Initial Configuration Use one of the `kustomize.yaml` files from the -[example](https://github.com/mnlipp/VM-Operator/tree/main/example) directory +[example](https://github.com/mnlipp/VM-Operator/tree/main/example) directory as a starting point. The directory contains two examples. Here's the file from subdirectory `local-path`: @@ -91,9 +91,9 @@ patches: storageClassName: local-path ``` -The sample file adds a namespace (`vmop-demo`) to all resource +The sample file adds a namespace (`vmop-demo`) to all resource definitions and patches the PVC `vmop-image-repository`. This is a volume -that is mounted into all pods that run a VM. The volume is intended +that is mounted into all pods that run a VM. The volume is intended to be used as a common repository for CDROM images. The PVC must exist and it must be bound before any pods can run. @@ -101,13 +101,13 @@ The second patch affects the small volume that is created for each runner and contains the VM's configuration data such as the EFI vars. The manager's default configuration causes the PVC for this volume to be created with no storage class (which causes the default storage -class to be used). The patch provides a new configuration file for -the manager that makes the reconciler use local-path as storage -class for this PVC. Details about the manager configuration can be +class to be used). The patch provides a new configuration file for +the manager that makes the reconciler use local-path as storage +class for this PVC. Details about the manager configuration can be found in the next section. -Note that you need none of the patches if you are fine with using your -cluster's default storage class and this class supports ReadOnlyMany as +Note that you need none of the patches if you are fine with using your +cluster's default storage class and this class supports ReadOnlyMany as access mode. Check that the pod with the manager is running: @@ -121,30 +121,30 @@ for creating your first VM. ## Configuration Details -The [config map](https://github.com/mnlipp/VM-Operator/blob/main/deploy/vmop-config-map.yaml) -for the manager may provide a configuration file (`config.yaml`) and +The [config map](https://github.com/mnlipp/VM-Operator/blob/main/deploy/vmop-config-map.yaml) +for the manager may provide a configuration file (`config.yaml`) and a file with logging properties (`logging.properties`). Both files are mounted into the container that runs the manager and are evaluated by the manager on startup. If no files are provided, the manager uses built-in defaults. The configuration file for the Manager follows the conventions of the [JGrapes](https://jgrapes.org/) component framework. -The keys that start with a slash select the component within the +The keys that start with a slash select the component within the application's component hierarchy. The mapping associated with the selected component configures this component's properties. The available configuration options for the components can be found -in their respective JavaDocs (e.g. +in their respective JavaDocs (e.g. [here](latest-release/javadoc/org/jdrupes/vmoperator/manager/Reconciler.html) for the Reconciler). ## Development Configuration The [dev-example](https://github.com/mnlipp/VM-Operator/tree/main/dev-example) -directory contains a `kustomize.yaml` that uses the development namespace +directory contains a `kustomize.yaml` that uses the development namespace `vmop-dev` and creates a deployment for the manager with 0 replicas. -This environment can be used for running the manager in the IDE. As the +This environment can be used for running the manager in the IDE. As the namespace to manage cannot be detected from the environment, you must use - `-c ../dev-example/config.yaml` as argument when starting the manager. This + `-c ../dev-example/config.yaml` as argument when starting the manager. This configures it to use the namespace `vmop-dev`. diff --git a/webpages/vm-operator/runner.md b/webpages/vm-operator/runner.md index 319a5dc..c72793d 100644 --- a/webpages/vm-operator/runner.md +++ b/webpages/vm-operator/runner.md @@ -5,9 +5,9 @@ layout: vm-operator # The Runner -For most use cases, Qemu needs to be started and controlled by another -program that manages the Qemu process. This program is called the -runner in this context. +For most use cases, Qemu needs to be started and controlled by another +program that manages the Qemu process. This program is called the +runner in this context. The most prominent reason for this second program is that it allows a VM to be shutdown cleanly in response to a TERM signal. Qemu handles @@ -26,38 +26,38 @@ CPUs and the memory. The runner takes care of all these issues. Although it is intended to run in a container (which runs in a Kubernetes pod) it does not require a container. You can start and use it as an ordinary program on any -system, provided that you have the required commands (qemu, swtpm) +system, provided that you have the required commands (qemu, swtpm) installed. ## Stand-alone Configuration -Upon startup, the runner reads its main configuration file +Upon startup, the runner reads its main configuration file which defaults to `/etc/opt/vmrunner/config.yaml` and may be changed using the `-c` (or `--config`) command line option. A sample configuration file with annotated options can be found [here](https://github.com/mnlipp/VM-Operator/blob/main/org.jdrupes.vmoperator.runner.qemu/config-sample.yaml). -As the runner implementation uses the -[JGrapes](https://jgrapes.org/) framework, the file -follows the framework's +As the runner implementation uses the +[JGrapes](https://jgrapes.org/) framework, the file +follows the framework's [conventions](https://jgrapes.org/latest-release/javadoc/org/jgrapes/util/YamlConfigurationStore.html). The top level "`/Runner`" selects the component to be configured. Nested within is the information to be applied to the component. The main entries in the configuration file are the "template" and -the "vm" information. The runner processes the +the "vm" information. The runner processes the [freemarker template](https://freemarker.apache.org/), using the -"vm" information to derive the qemu command. The idea is that +"vm" information to derive the qemu command. The idea is that the "vm" section provides high level information such as the boot mode, the number of CPUs, the RAM size and the disks. The template defines a particular VM type, i.e. it contains the "nasty details" that do not need to be modified for some given set of VM instances. -The templates provided with the runner can be found -[here](https://github.com/mnlipp/VM-Operator/tree/main/org.jdrupes.vmoperator.runner.qemu/templates). When details +The templates provided with the runner can be found +[here](https://github.com/mnlipp/VM-Operator/tree/main/org.jdrupes.vmoperator.runner.qemu/templates). When details of the VM configuration need modification, a new VM type -(i.e. a new template) has to be defined. Authoring a new -template requires some knowledge about the +(i.e. a new template) has to be defined. Authoring a new +template requires some knowledge about the [qemu invocation](https://www.qemu.org/docs/master/system/invocation.html). Despite many "warnings" that you find in the web, configuring the invocation arguments of qemu is only a bit (but not much) more @@ -72,13 +72,13 @@ provided by a If additional templates are required, some ReadOnlyMany PV should be mounted in `/opt/vmrunner/templates`. The PV should contain copies -of the standard templates as well as the additional templates. Of course, +of the standard templates as well as the additional templates. Of course, a ConfigMap can be used for this purpose again. Networking options are rather limited. The assumption is that in general the VM wants full network connectivity. To achieve this, the pod must run with host networking and the host's networking must provide a -bridge that the VM can attach to. The only currently supported +bridge that the VM can attach to. The only currently supported alternative is the less performant "[user networking](https://wiki.qemu.org/Documentation/Networking#User_Networking_(SLIRP))", which may be used in a stand-alone development configuration. @@ -87,7 +87,7 @@ which may be used in a stand-alone development configuration. The runner supports adaption to changes of the RAM size (using the balloon device) and to changes of the number of CPUs. Note that -in order to get new CPUs online on Linux guests, you need a +in order to get new CPUs online on Linux guests, you need a [udev rule](https://docs.kernel.org/core-api/cpu_hotplug.html#user-space-notification) which is not installed by default[^simplest]. The runner also changes the images loaded in CDROM drives. If the @@ -103,6 +103,6 @@ Finally, `powerdownTimeout` can be changed while the qemu process runs. ## Testing with Helm -There is a +There is a [Helm Chart](https://github.com/mnlipp/VM-Operator/tree/main/org.jdrupes.vmoperator.runner.qemu/helm-test) for testing the runner. diff --git a/webpages/vm-operator/upgrading.md b/webpages/vm-operator/upgrading.md index a794ab6..77cacad 100644 --- a/webpages/vm-operator/upgrading.md +++ b/webpages/vm-operator/upgrading.md @@ -13,7 +13,7 @@ The VmViewer conlet has been renamed to VmAccess. This affects the is still accepted for backward compatibility, but should be updated. The change of name also causes conlets added to the overview page by -users to "disappear" from the GUI. They have to be re-added. +users to "disappear" from the GUI. They have to be re-added. The latter behavior also applies to the VmConlet conlet which has been renamed to VmMgmt. @@ -25,14 +25,14 @@ with replica set to 1 to (indirectly) start the pod with the VM. Rather it creates the pod directly. This implies that the PVCs must also be created by the VM-Operator, which needs additional permissions to do so (update of `deploy/vmop-role.yaml). As it would be ridiculous to keep the naming scheme -used by the stateful set when generating PVCs, the VM-Operator uses a +used by the stateful set when generating PVCs, the VM-Operator uses a [different pattern](controller.html#defining-disks) for creating new PVCs. The change is backward compatible: * Running pods created by a stateful set are left alone until stopped. Only then will the stateful set be removed. - + * The VM-Operator looks for existing PVCs generated by a stateful set in the pre 3.4 versions (naming pattern "*name*-disk-*vmName*-0") and reuses them. Only new PVCs are generated using the new pattern. @@ -40,22 +40,22 @@ The change is backward compatible: ## To version 3.0.0 All configuration files are backward compatible to version 2.3.0. -Note that in order to make use of the new viewer component, +Note that in order to make use of the new viewer component, [permissions](https://mnlipp.github.io/VM-Operator/user-gui.html#control-access-to-vms) -must be configured in the CR definition. Also note that +must be configured in the CR definition. Also note that [display secrets](https://mnlipp.github.io/VM-Operator/user-gui.html#securing-access) are automatically created unless explicitly disabled. ## To version 2.3.0 Starting with version 2.3.0, the web GUI uses a login conlet that -supports OIDC providers. This effects the configuration of the +supports OIDC providers. This effects the configuration of the web GUI components. -## To version 2.2.0 +## To version 2.2.0 Version 2.2.0 sets the stateful set's `.spec.updateStrategy.type` to -"OnDelete". This fails for no apparent reason if a definition of +"OnDelete". This fails for no apparent reason if a definition of the stateful set with the default value "RollingUpdate" already exists. In order to fix this, either the stateful set or the complete VM definition must be deleted and the manager must be restarted. diff --git a/webpages/vm-operator/user-gui.md b/webpages/vm-operator/user-gui.md index 416e243..0439db2 100644 --- a/webpages/vm-operator/user-gui.md +++ b/webpages/vm-operator/user-gui.md @@ -19,20 +19,20 @@ requirement are unexpectedly complex. ## Control access to VMs First of all, we have to define which VMs a user can access. This -is done using the optional property `spec.permissions` of the +is done using the optional property `spec.permissions` of the VM definition (CRD). ```yaml spec: permissions: - role: admin - may: + may: - "*" - user: test may: - start - stop - - accessConsole + - accessConsole ``` Permissions can be granted to individual users or to roles. There @@ -104,7 +104,7 @@ spec: ``` The value of `server` is used as value for key "host" in the -connection file, thus overriding the default value. The +connection file, thus overriding the default value. The value of `proxyUrl` is used as value for key "proxy". ## Securing access @@ -123,8 +123,8 @@ in the future or with value "never" or doesn't define a `password-expiry` at all. The automatically generated password is the base64 encoded value -of 16 (strong) random bytes (128 random bits). It is valid for -10 seconds only. This may be challenging on a slower computer +of 16 (strong) random bytes (128 random bits). It is valid for +10 seconds only. This may be challenging on a slower computer or if users may not enable automatic open for connection files in the browser. The validity can therefore be adjusted in the configuration. diff --git a/webpages/vm-operator/webgui.md b/webpages/vm-operator/webgui.md index 1dbb20f..2d6e428 100644 --- a/webpages/vm-operator/webgui.md +++ b/webpages/vm-operator/webgui.md @@ -11,7 +11,7 @@ implemented using components from the project. Configuration of the GUI therefore follows the conventions of that framework. -The structure of the configuration information should be easy to +The structure of the configuration information should be easy to understand from the examples provided. In general, configuration values are applied to the individual components that make up an application. The hierarchy of the components is reflected in the configuration @@ -22,9 +22,9 @@ for information about the complete component structure.) ## Network access -By default, the service is made available at port 8080 of the manager +By default, the service is made available at port 8080 of the manager pod. Of course, a kubernetes service and an ingress configuration must -be added as required by the environment. (See the +be added as required by the environment. (See the [definition](https://github.com/mnlipp/VM-Operator/blob/main/deploy/vmop-service.yaml) from the [sample deployment](https://github.com/mnlipp/VM-Operator/tree/main/deploy)). @@ -49,7 +49,7 @@ and role management. # configure an OIDC provider for user management and # authorization. See the text for details. oidcProviders: {} - + # Support for "local" users is provided as a fallback mechanism. # Note that up to Version 2.2.x "users" was an object with user names # as its properties. Starting with 2.3.0 it is a list as shown. @@ -60,11 +60,11 @@ and role management. - name: test fullName: Test Account password: "Generate hash with bcrypt" - + # Required for using OIDC, see the text for details. "/OidcClient": redirectUri: https://my.server.here/oauth/callback" - + # May be used for assigning roles to both local users and users from # the OIDC provider. Not needed if roles are managed by the OIDC provider. "/RoleConfigurator": @@ -79,7 +79,7 @@ and role management. "*": - other replace: false - + # Manages the permissions for the roles. "/RoleConletFilter": conletTypesByRole: @@ -98,8 +98,8 @@ and role management. ``` How local users can be configured should be obvious from the example. -The configuration of OIDC providers for user authentication (and -optionally for role assignment) is explained in the documentation of the +The configuration of OIDC providers for user authentication (and +optionally for role assignment) is explained in the documentation of the [login conlet](https://jgrapes.org/javadoc-webconsole/org/jgrapes/webconlet/oidclogin/LoginConlet.html). Details about the `RoleConfigurator` and `RoleConletFilter` can also be found in the documentation of the @@ -113,5 +113,5 @@ all users to use the login conlet to log out. ## Views -The configuration of the components that provide the manager and +The configuration of the components that provide the manager and users views is explained in the respective sections. From 4fc0d6fc637cedf06895450ccc31efd0bc0403d3 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 31 Jan 2025 11:15:43 +0100 Subject: [PATCH 163/342] Support both string and boolean for deleteConnectionFile. --- .../src/org/jdrupes/vmoperator/vmaccess/VmAccess.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index 0015d6c..bd9a802 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -198,9 +198,8 @@ public class VmAccess extends FreeMarkerConlet { // Delete connection file deleteConnectionFile = Optional.ofNullable(c.get("deleteConnectionFile")) - .filter(v -> v instanceof String) - .map(v -> (String) v) - .map(Boolean::parseBoolean).orElse(true); + .map(Object::toString).map(Boolean::parseBoolean) + .orElse(true); // Users or roles for which previews should be synchronized syncUsers = ((List>) c.getOrDefault( From 6a1273e7013b8d5fdaef7e65fd6d86092b4df292 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 31 Jan 2025 12:24:21 +0100 Subject: [PATCH 164/342] Prevent concurrent modification exception. --- .../src/org/jdrupes/vmoperator/common/VmPool.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java index 8bf6dee..cfc29ef 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java @@ -140,7 +140,8 @@ public class VmPool { * @return the string */ @Override - @SuppressWarnings("PMD.AvoidLiteralsInIfCondition") + @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", + "PMD.AvoidSynchronizedStatement" }) public String toString() { StringBuilder builder = new StringBuilder(50); builder.append("VmPool [name=").append(name).append(", permissions=") @@ -148,8 +149,11 @@ public class VmPool { if (vms.size() <= 3) { builder.append(vms); } else { - builder.append('[').append(vms.stream().limit(3).map(s -> s + ",") - .collect(Collectors.joining())).append("...]"); + synchronized (vms) { + builder.append('[').append(vms.stream().limit(3) + .map(s -> s + ",").collect(Collectors.joining())) + .append("...]"); + } } builder.append(']'); return builder.toString(); From 23bc41d68d9442ae642c1e75f68599be1f0cc189 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 31 Jan 2025 15:26:25 +0100 Subject: [PATCH 165/342] Prefer running VMs for new assignments. --- .../jdrupes/vmoperator/manager/VmMonitor.java | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) 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 2060109..c2d717a 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 @@ -293,8 +293,9 @@ public class VmMonitor extends var pool = vmPool; assignedVm = channelManager.channels().stream() .filter(c -> isAssignable(pool, c.vmDefinition())) - .sorted(Comparator.comparing(c -> c.vmDefinition() - .assignmentLastUsed().orElse(Instant.ofEpochSecond(0)))) + .sorted(Comparator.comparing((VmChannel c) -> c.vmDefinition() + .assignmentLastUsed().orElse(Instant.ofEpochSecond(0))) + .thenComparing(preferRunning)) .findFirst(); // None found @@ -322,6 +323,19 @@ public class VmMonitor extends } } + private static Comparator preferRunning + = new Comparator<>() { + @Override + public int compare(VmChannel ch1, VmChannel ch2) { + if (ch1.vmDefinition().conditionStatus("Running").orElse(false) + && !ch2.vmDefinition().conditionStatus("Running") + .orElse(false)) { + return -1; + } + return 0; + } + }; + @SuppressWarnings("PMD.SimplifyBooleanReturns") private boolean isAssignable(VmPool pool, VmDefinition vmDef) { // Check if the VM is in the pool From b159bae5dabc696303de543dd09ce7e6f23a5760 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 31 Jan 2025 15:26:42 +0100 Subject: [PATCH 166/342] Allow users to start assigned VMs. --- dev-example/test-pool.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dev-example/test-pool.yaml b/dev-example/test-pool.yaml index 82b9131..a72a623 100644 --- a/dev-example/test-pool.yaml +++ b/dev-example/test-pool.yaml @@ -9,6 +9,8 @@ spec: - user: admin may: - accessConsole + - start - role: user may: - accessConsole + - start From b5ae22a8ead79e376858e91059107d14f1a3b060 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 31 Jan 2025 22:09:17 +0100 Subject: [PATCH 167/342] Avoid duplicate assignment. --- .../jdrupes/vmoperator/manager/VmMonitor.java | 106 +++++++++--------- 1 file changed, 51 insertions(+), 55 deletions(-) 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 c2d717a..84edafc 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 @@ -264,63 +264,59 @@ public class VmMonitor extends @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public void onAssignVm(AssignVm event) throws ApiException, InterruptedException { - VmPool vmPool = null; - while (true) { - // Search for existing assignment. - var assignedVm = channelManager.channels().stream() - .filter(c -> c.vmDefinition().assignedFrom() - .map(p -> p.equals(event.fromPool())).orElse(false)) - .filter(c -> c.vmDefinition().assignedTo() - .map(u -> u.equals(event.toUser())).orElse(false)) - .findFirst(); - if (assignedVm.isPresent()) { - var vmDef = assignedVm.get().vmDefinition(); - event.setResult(new VmData(vmDef, assignedVm.get())); - return; - } - - // Get the pool definition for retention time calculations - if (vmPool == null) { - vmPool = newEventPipeline().fire(new GetPools() - .withName(event.fromPool())).get().stream().findFirst() - .orElse(null); - if (vmPool == null) { - return; - } - } - - // Find available VM. - var pool = vmPool; - assignedVm = channelManager.channels().stream() - .filter(c -> isAssignable(pool, c.vmDefinition())) - .sorted(Comparator.comparing((VmChannel c) -> c.vmDefinition() - .assignmentLastUsed().orElse(Instant.ofEpochSecond(0))) - .thenComparing(preferRunning)) - .findFirst(); - - // None found - if (assignedVm.isEmpty()) { - return; - } - - // Assign to user + // Search for existing assignment. + var assignedVm = channelManager.channels().stream() + .filter(c -> c.vmDefinition().assignedFrom() + .map(p -> p.equals(event.fromPool())).orElse(false)) + .filter(c -> c.vmDefinition().assignedTo() + .map(u -> u.equals(event.toUser())).orElse(false)) + .findFirst(); + if (assignedVm.isPresent()) { var vmDef = assignedVm.get().vmDefinition(); - var vmStub = VmDefinitionStub.get(client(), - new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), - vmDef.namespace(), vmDef.name()); - vmStub.updateStatus(from -> { - JsonObject status = from.status(); - var assignment = GsonPtr.to(status).to("assignment"); - assignment.set("pool", event.fromPool()); - assignment.set("user", event.toUser()); - assignment.set("lastUsed", Instant.now().toString()); - return status; - }); - - // Make sure that a newly assigned VM is running. - fire(new ModifyVm(vmDef.name(), "state", "Running", - assignedVm.get())); + event.setResult(new VmData(vmDef, assignedVm.get())); + return; } + + // Get the pool definition for retention time calculations + VmPool vmPool = newEventPipeline().fire(new GetPools() + .withName(event.fromPool())).get().stream().findFirst() + .orElse(null); + if (vmPool == null) { + return; + } + + // Find available VM. + var pool = vmPool; + assignedVm = channelManager.channels().stream() + .filter(c -> isAssignable(pool, c.vmDefinition())) + .sorted(Comparator.comparing((VmChannel c) -> c.vmDefinition() + .assignmentLastUsed().orElse(Instant.ofEpochSecond(0))) + .thenComparing(preferRunning)) + .findFirst(); + + // None found + if (assignedVm.isEmpty()) { + return; + } + + // Assign to user + var vmDef = assignedVm.get().vmDefinition(); + var vmStub = VmDefinitionStub.get(client(), + new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), + vmDef.namespace(), vmDef.name()); + vmStub.updateStatus(from -> { + JsonObject status = from.status(); + var assignment = GsonPtr.to(status).to("assignment"); + assignment.set("pool", event.fromPool()); + assignment.set("user", event.toUser()); + assignment.set("lastUsed", Instant.now().toString()); + return status; + }); + event.setResult(new VmData(vmDef, assignedVm.get())); + + // Make sure that a newly assigned VM is running. + fire(new ModifyVm(vmDef.name(), "state", "Running", + assignedVm.get())); } private static Comparator preferRunning From 54747b25e8e7fbbe6064989a44c93d11df5386e0 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Feb 2025 18:51:19 +0100 Subject: [PATCH 168/342] Use VmChannel's event pipeline to update assignment. --- .../org/jdrupes/vmoperator/common/VmPool.java | 103 ++++++++++++------ .../manager/events/UpdateAssignment.java | 60 ++++++++++ .../vmoperator/manager/Controller.java | 30 +++++ .../jdrupes/vmoperator/manager/VmMonitor.java | 60 ++-------- 4 files changed, 169 insertions(+), 84 deletions(-) create mode 100644 org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/UpdateAssignment.java diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java index cfc29ef..e0817d5 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java @@ -134,6 +134,78 @@ public class VmPool { return vms; } + /** + * Collect all permissions for the given user with the given roles. + * + * @param user the user + * @param roles the roles + * @return the sets the + */ + public Set permissionsFor(String user, + Collection roles) { + return permissions.stream() + .filter(g -> DataPath.get(g, "user").map(u -> u.equals(user)) + .orElse(false) + || DataPath.get(g, "role").map(roles::contains).orElse(false)) + .map(g -> DataPath.> get(g, "may") + .orElse(Collections.emptySet()).stream()) + .flatMap(Function.identity()).collect(Collectors.toSet()); + } + + /** + * Checks if the given VM belongs to the pool and is not in use. + * + * @param vmDef the vm def + * @return true, if is assignable + */ + @SuppressWarnings("PMD.SimplifyBooleanReturns") + public boolean isAssignable(VmDefinition vmDef) { + // Check if the VM is in the pool + if (!vmDef.pools().contains(name)) { + return false; + } + + // Check if the VM is not in use + if (vmDef.consoleConnected()) { + return false; + } + + // If not assigned, it's usable + if (vmDef.assignedTo().isEmpty()) { + return true; + } + + // Check if it is to be retained + if (vmDef.assignmentLastUsed() + .map(this::retainUntil) + .map(ru -> Instant.now().isBefore(ru)).orElse(false)) { + return false; + } + + // Additional check in case lastUsed has not been updated + // by PoolMonitor#onVmDefChanged() yet ("race condition") + if (vmDef.condition("ConsoleConnected") + .map(cc -> cc.getLastTransitionTime().toInstant()) + .map(this::retainUntil) + .map(ru -> Instant.now().isBefore(ru)).orElse(false)) { + return false; + } + return true; + } + + /** + * Return the instant until which an assignment should be retained. + * + * @param lastUsed the last used + * @return the instant + */ + public Instant retainUntil(Instant lastUsed) { + if (retention.startsWith("P")) { + return lastUsed.plus(Duration.parse(retention)); + } + return Instant.parse(retention); + } + /** * To string. * @@ -158,35 +230,4 @@ public class VmPool { builder.append(']'); return builder.toString(); } - - /** - * Collect all permissions for the given user with the given roles. - * - * @param user the user - * @param roles the roles - * @return the sets the - */ - public Set permissionsFor(String user, - Collection roles) { - return permissions.stream() - .filter(g -> DataPath.get(g, "user").map(u -> u.equals(user)) - .orElse(false) - || DataPath.get(g, "role").map(roles::contains).orElse(false)) - .map(g -> DataPath.> get(g, "may") - .orElse(Collections.emptySet()).stream()) - .flatMap(Function.identity()).collect(Collectors.toSet()); - } - - /** - * Return the instant until which an assignment should be retained. - * - * @param lastUsed the last used - * @return the instant - */ - public Instant retainUntil(Instant lastUsed) { - if (retention.startsWith("P")) { - return lastUsed.plus(Duration.parse(retention)); - } - return Instant.parse(retention); - } } diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/UpdateAssignment.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/UpdateAssignment.java new file mode 100644 index 0000000..676af3d --- /dev/null +++ b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/UpdateAssignment.java @@ -0,0 +1,60 @@ +/* + * 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; + +/** + * Note the assignment to a user in the VM status. + */ +@SuppressWarnings("PMD.DataClass") +public class UpdateAssignment extends Event { + + private final String usedPool; + private final String toUser; + + /** + * Instantiates a new event. + * + * @param usedPool the used pool + * @param toUser the to user + */ + public UpdateAssignment(String usedPool, String toUser) { + this.usedPool = usedPool; + this.toUser = toUser; + } + + /** + * Gets the pool to assign from. + * + * @return the pool + */ + public String usedPool() { + return usedPool; + } + + /** + * Gets the user to assign to. + * + * @return the to user + */ + public String toUser() { + return toUser; + } +} 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 1ef17f7..32b3ac4 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 @@ -18,6 +18,7 @@ package org.jdrupes.vmoperator.manager; +import com.google.gson.JsonObject; import io.kubernetes.client.apimachinery.GroupVersionKind; import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; @@ -25,16 +26,20 @@ import io.kubernetes.client.openapi.Configuration; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.time.Instant; import java.util.logging.Level; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import org.jdrupes.vmoperator.common.K8sClient; import org.jdrupes.vmoperator.common.K8sDynamicStub; +import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.manager.events.ChannelManager; import org.jdrupes.vmoperator.manager.events.Exit; import org.jdrupes.vmoperator.manager.events.ModifyVm; +import org.jdrupes.vmoperator.manager.events.UpdateAssignment; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; +import org.jdrupes.vmoperator.util.GsonPtr; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; import org.jgrapes.core.annotation.Handler; @@ -204,4 +209,29 @@ public class Controller extends Component { () -> "Cannot patch definition for Vm " + vmStub.name()); } } + + /** + * Update the assignment information in the status of the VM CR. + * + * @param event the event + * @param channel the channel + * @throws ApiException the api exception + */ + @Handler + public void onUpdatedAssignment(UpdateAssignment event, VmChannel channel) + throws ApiException { + var vmDef = channel.vmDefinition(); + var vmStub = VmDefinitionStub.get(channel.client(), + new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), + vmDef.namespace(), vmDef.name()); + vmStub.updateStatus(from -> { + JsonObject status = from.status(); + var assignment = GsonPtr.to(status).to("assignment"); + assignment.set("pool", event.usedPool()); + assignment.set("user", event.toUser()); + assignment.set("lastUsed", Instant.now().toString()); + return status; + }); + event.setResult(true); + } } 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 84edafc..f0368a7 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 @@ -18,8 +18,6 @@ package org.jdrupes.vmoperator.manager; -import com.google.gson.JsonObject; -import io.kubernetes.client.apimachinery.GroupVersionKind; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.util.Watch; @@ -55,9 +53,9 @@ import org.jdrupes.vmoperator.manager.events.GetPools; import org.jdrupes.vmoperator.manager.events.GetVms; import org.jdrupes.vmoperator.manager.events.GetVms.VmData; import org.jdrupes.vmoperator.manager.events.ModifyVm; +import org.jdrupes.vmoperator.manager.events.UpdateAssignment; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; -import org.jdrupes.vmoperator.util.GsonPtr; import org.jgrapes.core.Channel; import org.jgrapes.core.Event; import org.jgrapes.core.annotation.Handler; @@ -277,7 +275,7 @@ public class VmMonitor extends return; } - // Get the pool definition for retention time calculations + // Get the pool definition assignability check VmPool vmPool = newEventPipeline().fire(new GetPools() .withName(event.fromPool())).get().stream().findFirst() .orElse(null); @@ -286,9 +284,8 @@ public class VmMonitor extends } // Find available VM. - var pool = vmPool; assignedVm = channelManager.channels().stream() - .filter(c -> isAssignable(pool, c.vmDefinition())) + .filter(c -> vmPool.isAssignable(c.vmDefinition())) .sorted(Comparator.comparing((VmChannel c) -> c.vmDefinition() .assignmentLastUsed().orElse(Instant.ofEpochSecond(0))) .thenComparing(preferRunning)) @@ -300,23 +297,14 @@ public class VmMonitor extends } // Assign to user + assignedVm.get().pipeline().fire(new UpdateAssignment(vmPool.name(), + event.toUser()), assignedVm.get()).get(); var vmDef = assignedVm.get().vmDefinition(); - var vmStub = VmDefinitionStub.get(client(), - new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), - vmDef.namespace(), vmDef.name()); - vmStub.updateStatus(from -> { - JsonObject status = from.status(); - var assignment = GsonPtr.to(status).to("assignment"); - assignment.set("pool", event.fromPool()); - assignment.set("user", event.toUser()); - assignment.set("lastUsed", Instant.now().toString()); - return status; - }); event.setResult(new VmData(vmDef, assignedVm.get())); // Make sure that a newly assigned VM is running. - fire(new ModifyVm(vmDef.name(), "state", "Running", - assignedVm.get())); + assignedVm.get().pipeline().fire(new ModifyVm(vmDef.name(), + "state", "Running", assignedVm.get())); } private static Comparator preferRunning @@ -332,38 +320,4 @@ public class VmMonitor extends } }; - @SuppressWarnings("PMD.SimplifyBooleanReturns") - private boolean isAssignable(VmPool pool, VmDefinition vmDef) { - // Check if the VM is in the pool - if (!vmDef.pools().contains(pool.name())) { - return false; - } - - // Check if the VM is not in use - if (vmDef.consoleConnected()) { - return false; - } - - // If not assigned, it's usable - if (vmDef.assignedTo().isEmpty()) { - return true; - } - - // Check if it is to be retained - if (vmDef.assignmentLastUsed() - .map(lu -> pool.retainUntil(lu)) - .map(ru -> Instant.now().isBefore(ru)).orElse(false)) { - return false; - } - - // Additional check in case lastUsed has not been updated - // by PoolMonitor#onVmDefChanged() yet ("race condition") - if (vmDef.condition("ConsoleConnected") - .map(cc -> cc.getLastTransitionTime().toInstant()) - .map(t -> pool.retainUntil(t)) - .map(ru -> Instant.now().isBefore(ru)).orElse(false)) { - return false; - } - return true; - } } From 85a4521299f6ae693546927a1af82a44c3a6cee1 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Feb 2025 22:06:30 +0100 Subject: [PATCH 169/342] Combine VmDefinitionModel and VmDefinition. --- .../vmoperator/common/K8sDynamicModel.java | 2 +- .../vmoperator/common/VmDefinition.java | 201 +++++++----------- .../vmoperator/common/VmDefinitionModel.java | 39 ---- .../vmoperator/common/VmDefinitionModels.java | 4 +- .../vmoperator/common/VmDefinitionStub.java | 16 +- .../vmoperator/manager/runnerConfig.ftl.yaml | 2 +- .../manager/runnerLoadBalancer.ftl.yaml | 2 +- .../vmoperator/manager/runnerPod.ftl.yaml | 2 +- .../vmoperator/manager/Controller.java | 2 +- .../manager/DisplaySecretMonitor.java | 2 +- .../vmoperator/manager/PoolMonitor.java | 3 +- .../jdrupes/vmoperator/manager/VmMonitor.java | 24 +-- .../runner/qemu/ConsoleTracker.java | 4 +- .../vmoperator/runner/qemu/StatusUpdater.java | 18 +- .../vmoperator/runner/qemu/VmDefUpdater.java | 4 +- .../jdrupes/vmoperator/vmaccess/VmAccess.java | 2 +- 16 files changed, 121 insertions(+), 206 deletions(-) delete mode 100644 org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModel.java diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sDynamicModel.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sDynamicModel.java index 6a4410f..dd2bdd5 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sDynamicModel.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sDynamicModel.java @@ -102,7 +102,7 @@ public class K8sDynamicModel implements KubernetesObject { * * @return the JSON object describing the status */ - public JsonObject status() { + public JsonObject statusJson() { return data.getAsJsonObject("status"); } diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java index ffb1bf2..e677642 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java @@ -20,8 +20,10 @@ package org.jdrupes.vmoperator.common; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import io.kubernetes.client.openapi.JSON; import io.kubernetes.client.openapi.models.V1Condition; -import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.util.Strings; import java.net.InetAddress; import java.net.UnknownHostException; @@ -46,21 +48,20 @@ import org.jdrupes.vmoperator.util.DataPath; /** * Represents a VM definition. */ -@SuppressWarnings({ "PMD.DataClass", "PMD.TooManyMethods" }) -public class VmDefinition { +@SuppressWarnings({ "PMD.DataClass", "PMD.TooManyMethods", + "PMD.CouplingBetweenObjects" }) +public class VmDefinition extends K8sDynamicModel { @SuppressWarnings("PMD.FieldNamingConventions") private static final Logger logger = Logger.getLogger(VmDefinition.class.getName()); @SuppressWarnings("PMD.FieldNamingConventions") + private static final Gson gson = new JSON().getGson(); + @SuppressWarnings("PMD.FieldNamingConventions") private static final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule()); - private String kind; - private String apiVersion; - private V1ObjectMeta metadata; - private Map spec; - private Map status; + private final Model model; private final Map extra = new ConcurrentHashMap<>(); /** @@ -145,66 +146,34 @@ public class VmDefinition { } /** - * Gets the kind. + * Instantiates a new vm definition. * - * @return the kind + * @param delegate the delegate + * @param json the json */ - public String getKind() { - return kind; + public VmDefinition(Gson delegate, JsonObject json) { + super(delegate, json); + model = gson.fromJson(json, Model.class); } /** - * Sets the kind. + * Gets the spec. * - * @param kind the kind to set + * @return the spec */ - public void setKind(String kind) { - this.kind = kind; + public Map spec() { + return model.getSpec(); } /** - * Gets the api version. + * Get a value from the spec using {@link DataPath#get}. * - * @return the apiVersion + * @param the generic type + * @param selectors the selectors + * @return the value, if found */ - public String getApiVersion() { - return apiVersion; - } - - /** - * Sets the api version. - * - * @param apiVersion the apiVersion to set - */ - public void setApiVersion(String apiVersion) { - this.apiVersion = apiVersion; - } - - /** - * Gets the metadata. - * - * @return the metadata - */ - public V1ObjectMeta getMetadata() { - return metadata; - } - - /** - * Gets the metadata. - * - * @return the metadata - */ - public V1ObjectMeta metadata() { - return metadata; - } - - /** - * Sets the metadata. - * - * @param metadata the metadata to set - */ - public void setMetadata(V1ObjectMeta metadata) { - this.metadata = metadata; + public Optional fromSpec(Object... selectors) { + return DataPath.get(spec(), selectors); } /** @@ -217,35 +186,6 @@ public class VmDefinition { .orElse(Collections.emptyList()); } - /** - * Gets the spec. - * - * @return the spec - */ - public Map getSpec() { - return spec; - } - - /** - * Gets the spec. - * - * @return the spec - */ - public Map spec() { - return spec; - } - - /** - * Get a value from the spec using {@link DataPath#get}. - * - * @param the generic type - * @param selectors the selectors - * @return the value, if found - */ - public Optional fromSpec(Object... selectors) { - return DataPath.get(spec, selectors); - } - /** * Get a value from the `spec().get("vm")` using {@link DataPath#get}. * @@ -254,35 +194,17 @@ public class VmDefinition { * @return the value, if found */ public Optional fromVm(Object... selectors) { - return DataPath.get(spec, "vm") + return DataPath.get(spec(), "vm") .flatMap(vm -> DataPath.get(vm, selectors)); } - /** - * Sets the spec. - * - * @param spec the spec to set - */ - public void setSpec(Map spec) { - this.spec = spec; - } - - /** - * Gets the status. - * - * @return the status - */ - public Map getStatus() { - return status; - } - /** * Gets the status. * * @return the status */ public Map status() { - return status; + return model.getStatus(); } /** @@ -293,16 +215,7 @@ public class VmDefinition { * @return the value, if found */ public Optional fromStatus(Object... selectors) { - return DataPath.get(status, selectors); - } - - /** - * Sets the status. - * - * @param status the status to set - */ - public void setStatus(Map status) { - this.status = status; + return DataPath.get(status(), selectors); } /** @@ -411,7 +324,7 @@ public class VmDefinition { * @return the string */ public String name() { - return metadata.getName(); + return metadata().getName(); } /** @@ -420,7 +333,7 @@ public class VmDefinition { * @return the string */ public String namespace() { - return metadata.getNamespace(); + return metadata().getNamespace(); } /** @@ -569,7 +482,7 @@ public class VmDefinition { */ @Override public int hashCode() { - return Objects.hash(metadata.getNamespace(), metadata.getName()); + return Objects.hash(metadata().getNamespace(), metadata().getName()); } /** @@ -590,9 +503,55 @@ public class VmDefinition { return false; } VmDefinition other = (VmDefinition) obj; - return Objects.equals(metadata.getNamespace(), - other.metadata.getNamespace()) - && Objects.equals(metadata.getName(), other.metadata.getName()); + return Objects.equals(metadata().getNamespace(), + other.metadata().getNamespace()) + && Objects.equals(metadata().getName(), other.metadata().getName()); + } + + /** + * The Class Model. + */ + public static class Model { + + private Map spec; + private Map status; + + /** + * Gets the spec. + * + * @return the spec + */ + public Map getSpec() { + return spec; + } + + /** + * Sets the spec. + * + * @param spec the spec to set + */ + public void setSpec(Map spec) { + this.spec = spec; + } + + /** + * Gets the status. + * + * @return the status + */ + public Map getStatus() { + return status; + } + + /** + * Sets the status. + * + * @param status the status to set + */ + public void setStatus(Map status) { + this.status = status; + } + } } 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 deleted file mode 100644 index d4ae5da..0000000 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModel.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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.common; - -import com.google.gson.Gson; -import com.google.gson.JsonObject; - -/** - * Represents a VM definition. - */ -@SuppressWarnings("PMD.DataClass") -public class VmDefinitionModel extends K8sDynamicModel { - - /** - * Instantiates a new model from the JSON representation. - * - * @param delegate the gson instance to use for extracting structured data - * @param json the JSON - */ - public VmDefinitionModel(Gson delegate, JsonObject json) { - super(delegate, json); - } -} diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModels.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModels.java index 5ac412f..22e5bd7 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModels.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModels.java @@ -25,7 +25,7 @@ import com.google.gson.JsonObject; * Represents a list of {@link VmDefinitionModel}s. */ public class VmDefinitionModels - extends K8sDynamicModelsBase { + extends K8sDynamicModelsBase { /** * Initialize the object list using the given JSON data. @@ -34,6 +34,6 @@ public class VmDefinitionModels * @param data the data */ public VmDefinitionModels(Gson delegate, JsonObject data) { - super(VmDefinitionModel.class, delegate, data); + super(VmDefinition.class, delegate, data); } } diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionStub.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionStub.java index 49da3e0..e2e71da 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionStub.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionStub.java @@ -33,9 +33,9 @@ import java.util.Collection; */ @SuppressWarnings("PMD.DataflowAnomalyAnalysis") public class VmDefinitionStub - extends K8sDynamicStubBase { + extends K8sDynamicStubBase { - private static DynamicTypeAdapterFactory taf = new VmDefintionModelTypeAdapterFactory(); /** @@ -48,7 +48,7 @@ public class VmDefinitionStub */ public VmDefinitionStub(K8sClient client, APIResource context, String namespace, String name) { - super(VmDefinitionModel.class, VmDefinitionModels.class, taf, client, + super(VmDefinition.class, VmDefinitionModels.class, taf, client, context, namespace, name); } @@ -101,9 +101,9 @@ public class VmDefinitionStub */ public static VmDefinitionStub createFromYaml(K8sClient client, APIResource context, Reader yaml) throws ApiException { - var model = new VmDefinitionModel(client.getJSON().getGson(), + var model = new VmDefinition(client.getJSON().getGson(), K8s.yamlToJson(client, yaml)); - return K8sGenericStub.create(VmDefinitionModel.class, + return K8sGenericStub.create(VmDefinition.class, VmDefinitionModels.class, client, context, model, (c, ns, n) -> new VmDefinitionStub(c, context, ns, n)); } @@ -121,7 +121,7 @@ public class VmDefinitionStub public static Collection list(K8sClient client, APIResource context, String namespace, ListOptions options) throws ApiException { - return K8sGenericStub.list(VmDefinitionModel.class, + return K8sGenericStub.list(VmDefinition.class, VmDefinitionModels.class, client, context, namespace, options, (c, ns, n) -> new VmDefinitionStub(c, context, ns, n)); } @@ -144,13 +144,13 @@ public class VmDefinitionStub * A factory for creating VmDefinitionModel(s) objects. */ public static class VmDefintionModelTypeAdapterFactory extends - DynamicTypeAdapterFactory { + DynamicTypeAdapterFactory { /** * Instantiates a new dynamic model type adapter factory. */ public VmDefintionModelTypeAdapterFactory() { - super(VmDefinitionModel.class, VmDefinitionModels.class); + super(VmDefinition.class, VmDefinitionModels.class); } } 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 8a50a5e..f348244 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 @@ -10,7 +10,7 @@ metadata: annotations: vmoperator.jdrupes.org/version: ${ managerVersion } ownerReferences: - - apiVersion: ${ cr.apiVersion } + - apiVersion: ${ cr.apiVersion() } kind: ${ constants.VM_OP_KIND_VM } name: ${ cr.name() } uid: ${ cr.metadata().getUid() } diff --git a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerLoadBalancer.ftl.yaml b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerLoadBalancer.ftl.yaml index 9a70e19..c25d7f4 100644 --- a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerLoadBalancer.ftl.yaml +++ b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerLoadBalancer.ftl.yaml @@ -10,7 +10,7 @@ metadata: annotations: vmoperator.jdrupes.org/version: ${ managerVersion } ownerReferences: - - apiVersion: ${ cr.apiVersion } + - apiVersion: ${ cr.apiVersion() } kind: ${ constants.VM_OP_KIND_VM } name: ${ cr.name() } uid: ${ cr.metadata().getUid() } diff --git a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerPod.ftl.yaml b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerPod.ftl.yaml index e62ac70..917d790 100644 --- a/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerPod.ftl.yaml +++ b/org.jdrupes.vmoperator.manager/resources/org/jdrupes/vmoperator/manager/runnerPod.ftl.yaml @@ -14,7 +14,7 @@ metadata: vmrunner.jdrupes.org/cmVersion: "${ cm.metadata.resourceVersion }" vmoperator.jdrupes.org/version: ${ managerVersion } ownerReferences: - - apiVersion: ${ cr.apiVersion } + - apiVersion: ${ cr.apiVersion() } kind: ${ constants.VM_OP_KIND_VM } name: ${ cr.name() } uid: ${ cr.metadata().getUid() } 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 32b3ac4..3e25a08 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 @@ -225,7 +225,7 @@ public class Controller extends Component { new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), vmDef.namespace(), vmDef.name()); vmStub.updateStatus(from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); var assignment = GsonPtr.to(status).to("assignment"); assignment.set("pool", event.usedPool()); assignment.set("user", event.toUser()); 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 141c806..a0809e9 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 @@ -185,7 +185,7 @@ public class DisplaySecretMonitor new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), event.vmDefinition().namespace(), event.vmDefinition().name()); vmStub.updateStatus(from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); status.addProperty("consoleUser", event.user()); return status; }); diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java index b83c0f5..25fb10b 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolMonitor.java @@ -187,7 +187,8 @@ public class PoolMonitor extends new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), vmDef.namespace(), vmDef.name()); vmStub.updateStatus(from -> { - JsonObject status = from.status(); + // TODO + JsonObject status = from.statusJson(); var assignment = GsonPtr.to(status).to("assignment"); assignment.set("lastUsed", ccChange.get().toString()); return status; 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 f0368a7..b458628 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 @@ -41,7 +41,6 @@ import org.jdrupes.vmoperator.common.K8sV1ConfigMapStub; import org.jdrupes.vmoperator.common.K8sV1PodStub; import org.jdrupes.vmoperator.common.K8sV1StatefulSetStub; import org.jdrupes.vmoperator.common.VmDefinition; -import org.jdrupes.vmoperator.common.VmDefinitionModel; import org.jdrupes.vmoperator.common.VmDefinitionModels; import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.common.VmPool; @@ -65,7 +64,7 @@ import org.jgrapes.core.annotation.Handler; */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports" }) public class VmMonitor extends - AbstractMonitor { + AbstractMonitor { private final ChannelManager channelManager; @@ -77,7 +76,7 @@ public class VmMonitor extends */ public VmMonitor(Channel componentChannel, ChannelManager channelManager) { - super(componentChannel, VmDefinitionModel.class, + super(componentChannel, VmDefinition.class, VmDefinitionModels.class); this.channelManager = channelManager; } @@ -122,7 +121,7 @@ public class VmMonitor extends @Override protected void handleChange(K8sClient client, - Watch.Response response) { + Watch.Response response) { V1ObjectMeta metadata = response.object.getMetadata(); AtomicBoolean toBeAdded = new AtomicBoolean(false); VmChannel channel = channelManager.channel(metadata.getName()) @@ -132,21 +131,17 @@ public class VmMonitor extends }); // Get full definition and associate with channel as backup - var vmModel = response.object; - if (vmModel.data() == null) { + var vmDef = response.object; + if (vmDef.data() == null) { // ADDED event does not provide data, see // https://github.com/kubernetes-client/java/issues/3215 - vmModel = getModel(client, vmModel); + vmDef = getModel(client, vmDef); } - VmDefinition vmDef = null; - if (vmModel.data() != null) { + if (vmDef.data() != null) { // New data, augment and save - vmDef = client.getJSON().getGson().fromJson(vmModel.data(), - VmDefinition.class); addDynamicData(channel.client(), vmDef, channel.vmDefinition()); channel.setVmDefinition(vmDef); - } - if (vmDef == null) { + } else { // Reuse cached (e.g. if deleted) vmDef = channel.vmDefinition(); } @@ -173,8 +168,7 @@ public class VmMonitor extends channel.pipeline().fire(chgEvt, channel); } - private VmDefinitionModel getModel(K8sClient client, - VmDefinitionModel vmDef) { + private VmDefinition getModel(K8sClient client, VmDefinition vmDef) { try { return VmDefinitionStub.get(client, context(), namespace(), vmDef.metadata().getName()).model().orElse(null); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java index f2309df..b91b5df 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/ConsoleTracker.java @@ -106,7 +106,7 @@ public class ConsoleTracker extends VmDefUpdater { mainChannelClientHost = event.clientHost(); mainChannelClientPort = event.clientPort(); vmStub.updateStatus(from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); status.addProperty("consoleClient", event.clientHost()); updateCondition(from, status, "ConsoleConnected", true, "Connected", "Connection from " + event.clientHost()); @@ -141,7 +141,7 @@ public class ConsoleTracker extends VmDefUpdater { return; } vmStub.updateStatus(from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); status.addProperty("consoleClient", ""); updateCondition(from, status, "ConsoleConnected", false, "Disconnected", event.clientHost() + " has disconnected"); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index 0b18df0..d33358b 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -33,7 +33,7 @@ import static org.jdrupes.vmoperator.common.Constants.APP_NAME; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import org.jdrupes.vmoperator.common.K8s; -import org.jdrupes.vmoperator.common.VmDefinitionModel; +import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.runner.qemu.events.BalloonChangeEvent; import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu; @@ -140,12 +140,12 @@ public class StatusUpdater extends VmDefUpdater { if (vmDef.isPresent() && vmDef.get().metadata().getGeneration() == observedGeneration && (event.configuration().hasDisplayPassword - || vmDef.get().status().getAsJsonPrimitive( + || vmDef.get().statusJson().getAsJsonPrimitive( "displayPasswordSerial").getAsInt() == -1)) { return; } vmStub.updateStatus(vmDef.get(), from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); if (!event.configuration().hasDisplayPassword) { status.addProperty("displayPasswordSerial", -1); } @@ -169,14 +169,14 @@ public class StatusUpdater extends VmDefUpdater { "PMD.AvoidLiteralsInIfCondition" }) public void onRunnerStateChanged(RunnerStateChange event) throws ApiException { - VmDefinitionModel vmDef; + VmDefinition vmDef; if (vmStub == null || (vmDef = vmStub.model().orElse(null)) == null) { return; } vmStub.updateStatus(vmDef, from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); boolean running = RUNNING_STATES.contains(event.runState()); - updateCondition(vmDef, vmDef.status(), "Running", running, + updateCondition(vmDef, vmDef.statusJson(), "Running", running, event.reason(), event.message()); if (event.runState() == RunState.STARTING) { status.addProperty("ram", GsonPtr.to(from.data()) @@ -230,7 +230,7 @@ public class StatusUpdater extends VmDefUpdater { return; } vmStub.updateStatus(from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); status.addProperty("ram", new Quantity(new BigDecimal(event.size()), Format.BINARY_SI) .toSuffixedString()); @@ -250,7 +250,7 @@ public class StatusUpdater extends VmDefUpdater { return; } vmStub.updateStatus(from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); status.addProperty("cpus", event.usedCpus().size()); return status; }); @@ -269,7 +269,7 @@ public class StatusUpdater extends VmDefUpdater { return; } vmStub.updateStatus(from -> { - JsonObject status = from.status(); + JsonObject status = from.statusJson(); status.addProperty("displayPasswordSerial", status.get("displayPasswordSerial").getAsLong() + 1); return status; diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java index 9683457..f04b478 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmDefUpdater.java @@ -31,7 +31,7 @@ import java.util.Optional; import java.util.logging.Level; import java.util.stream.Collectors; import org.jdrupes.vmoperator.common.K8sClient; -import org.jdrupes.vmoperator.common.VmDefinitionModel; +import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.runner.qemu.events.Exit; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; @@ -118,7 +118,7 @@ public class VmDefUpdater extends Component { * @param reason the reason for the change * @param message the message */ - protected void updateCondition(VmDefinitionModel from, JsonObject status, + protected void updateCondition(VmDefinition from, JsonObject status, String type, boolean state, String reason, String message) { // Optimize, as we can get this several times var current = status.getAsJsonArray("conditions").asList().stream() diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index bd9a802..d6c385e 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -593,7 +593,7 @@ public class VmAccess extends FreeMarkerConlet { Map.of("namespace", vmDef.namespace(), "name", vmDef.name()), "spec", vmDef.spec(), - "status", vmDef.getStatus()); + "status", vmDef.status()); } catch (JsonSyntaxException e) { logger.log(Level.SEVERE, e, () -> "Failed to serialize VM definition"); From b7ea6860ff8a7e0496ae6e4374986edb8150c1e0 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Feb 2025 22:08:57 +0100 Subject: [PATCH 170/342] Adapt name to previous change. --- .../vmoperator/common/VmDefinitionStub.java | 14 +++++++------- ...{VmDefinitionModels.java => VmDefinitions.java} | 6 +++--- .../org/jdrupes/vmoperator/manager/VmMonitor.java | 6 +++--- 3 files changed, 13 insertions(+), 13 deletions(-) rename org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/{VmDefinitionModels.java => VmDefinitions.java} (88%) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionStub.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionStub.java index e2e71da..72194da 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionStub.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionStub.java @@ -33,10 +33,10 @@ import java.util.Collection; */ @SuppressWarnings("PMD.DataflowAnomalyAnalysis") public class VmDefinitionStub - extends K8sDynamicStubBase { + extends K8sDynamicStubBase { private static DynamicTypeAdapterFactory taf = new VmDefintionModelTypeAdapterFactory(); + VmDefinitions> taf = new VmDefintionModelTypeAdapterFactory(); /** * Instantiates a new stub for VM defintions. @@ -48,7 +48,7 @@ public class VmDefinitionStub */ public VmDefinitionStub(K8sClient client, APIResource context, String namespace, String name) { - super(VmDefinition.class, VmDefinitionModels.class, taf, client, + super(VmDefinition.class, VmDefinitions.class, taf, client, context, namespace, name); } @@ -104,7 +104,7 @@ public class VmDefinitionStub var model = new VmDefinition(client.getJSON().getGson(), K8s.yamlToJson(client, yaml)); return K8sGenericStub.create(VmDefinition.class, - VmDefinitionModels.class, client, context, model, + VmDefinitions.class, client, context, model, (c, ns, n) -> new VmDefinitionStub(c, context, ns, n)); } @@ -122,7 +122,7 @@ public class VmDefinitionStub APIResource context, String namespace, ListOptions options) throws ApiException { return K8sGenericStub.list(VmDefinition.class, - VmDefinitionModels.class, client, context, namespace, options, + VmDefinitions.class, client, context, namespace, options, (c, ns, n) -> new VmDefinitionStub(c, context, ns, n)); } @@ -144,13 +144,13 @@ public class VmDefinitionStub * A factory for creating VmDefinitionModel(s) objects. */ public static class VmDefintionModelTypeAdapterFactory extends - DynamicTypeAdapterFactory { + DynamicTypeAdapterFactory { /** * Instantiates a new dynamic model type adapter factory. */ public VmDefintionModelTypeAdapterFactory() { - super(VmDefinition.class, VmDefinitionModels.class); + super(VmDefinition.class, VmDefinitions.class); } } diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModels.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitions.java similarity index 88% rename from org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModels.java rename to org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitions.java index 22e5bd7..c79654e 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitionModels.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinitions.java @@ -22,9 +22,9 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; /** - * Represents a list of {@link VmDefinitionModel}s. + * Represents a list of {@link VmDefinition}s. */ -public class VmDefinitionModels +public class VmDefinitions extends K8sDynamicModelsBase { /** @@ -33,7 +33,7 @@ public class VmDefinitionModels * @param delegate the gson instance to use for extracting structured data * @param data the data */ - public VmDefinitionModels(Gson delegate, JsonObject data) { + public VmDefinitions(Gson delegate, JsonObject data) { super(VmDefinition.class, delegate, data); } } 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 b458628..79ce631 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 @@ -41,7 +41,7 @@ import org.jdrupes.vmoperator.common.K8sV1ConfigMapStub; import org.jdrupes.vmoperator.common.K8sV1PodStub; import org.jdrupes.vmoperator.common.K8sV1StatefulSetStub; import org.jdrupes.vmoperator.common.VmDefinition; -import org.jdrupes.vmoperator.common.VmDefinitionModels; +import org.jdrupes.vmoperator.common.VmDefinitions; import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.common.VmPool; import static org.jdrupes.vmoperator.manager.Constants.APP_NAME; @@ -64,7 +64,7 @@ import org.jgrapes.core.annotation.Handler; */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports" }) public class VmMonitor extends - AbstractMonitor { + AbstractMonitor { private final ChannelManager channelManager; @@ -77,7 +77,7 @@ public class VmMonitor extends public VmMonitor(Channel componentChannel, ChannelManager channelManager) { super(componentChannel, VmDefinition.class, - VmDefinitionModels.class); + VmDefinitions.class); this.channelManager = channelManager; } From 21108771d9ed27de392f334f7516fce3017a65f5 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 1 Feb 2025 22:10:47 +0100 Subject: [PATCH 171/342] Fix warning. --- .../src/org/jdrupes/vmoperator/manager/VmMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 79ce631..e506d44 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 @@ -41,8 +41,8 @@ import org.jdrupes.vmoperator.common.K8sV1ConfigMapStub; import org.jdrupes.vmoperator.common.K8sV1PodStub; import org.jdrupes.vmoperator.common.K8sV1StatefulSetStub; import org.jdrupes.vmoperator.common.VmDefinition; -import org.jdrupes.vmoperator.common.VmDefinitions; import org.jdrupes.vmoperator.common.VmDefinitionStub; +import org.jdrupes.vmoperator.common.VmDefinitions; import org.jdrupes.vmoperator.common.VmPool; import static org.jdrupes.vmoperator.manager.Constants.APP_NAME; import static org.jdrupes.vmoperator.manager.Constants.VM_OP_NAME; From d5e589709fb96d106af137c57ffb59dca2b893c6 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Feb 2025 12:10:22 +0100 Subject: [PATCH 172/342] Handle conflict properly. --- .../vmoperator/common/K8sGenericStub.java | 50 +++++----- .../vmoperator/manager/Controller.java | 41 ++++++--- .../jdrupes/vmoperator/manager/VmMonitor.java | 91 ++++++++++--------- 3 files changed, 100 insertions(+), 82 deletions(-) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java index 0689a97..688f43f 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java @@ -193,42 +193,41 @@ public class K8sGenericStub updateStatus(O object, - Function status, int retries) throws ApiException { - while (true) { - try { - return K8s.optional(api.updateStatus(object, status)); - } catch (ApiException e) { - if (HttpURLConnection.HTTP_CONFLICT != e.getCode() - || retries-- <= 0) { - throw e; - } - } - } + public Optional updateStatus(O object, Function status) + throws ApiException { + return K8s.optional(api.updateStatus(object, status)); } /** - * Updates the object's status, retrying up to 16 times if there - * is a conflict. + * Gets the object and updates the status. In case of conflict, retries + * up to `retries` times. * - * @param object the current state of the object (passed to `status`) - * @param status function that returns the new status - * @return the updated model or empty if not successful + * @param status the status + * @param retries the retries in case of conflict + * @return the updated model or empty if the object was not found * @throws ApiException the api exception */ - public Optional updateStatus(O object, - Function status) throws ApiException { - return updateStatus(object, status, 16); + @SuppressWarnings({ "PMD.AssignmentInOperand", "PMD.UnusedAssignment" }) + public Optional updateStatus(Function status, int retries) + throws ApiException { + try { + return updateStatus(api.get(namespace, name).throwsApiException() + .getObject(), status); + } catch (ApiException e) { + if (HttpURLConnection.HTTP_CONFLICT != e.getCode() + || retries-- <= 0) { + throw e; + } + } + return Optional.empty(); } /** @@ -241,8 +240,7 @@ public class K8sGenericStub updateStatus(Function status) throws ApiException { - return updateStatus( - api.get(namespace, name).throwsApiException().getObject(), status); + return updateStatus(status, 16); } /** 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 3e25a08..80ff0f7 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 @@ -24,6 +24,7 @@ import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.Configuration; import java.io.IOException; +import java.net.HttpURLConnection; import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; @@ -211,7 +212,10 @@ public class Controller extends Component { } /** - * Update the assignment information in the status of the VM CR. + * Attempt to Update the assignment information in the status of the + * VM CR. Returns true if successful. The handler does not attempt + * retries, because in case of failure it will be necessary to + * re-evaluate the chosen VM. * * @param event the event * @param channel the channel @@ -220,18 +224,27 @@ public class Controller extends Component { @Handler public void onUpdatedAssignment(UpdateAssignment event, VmChannel channel) throws ApiException { - var vmDef = channel.vmDefinition(); - var vmStub = VmDefinitionStub.get(channel.client(), - new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), - vmDef.namespace(), vmDef.name()); - vmStub.updateStatus(from -> { - JsonObject status = from.statusJson(); - var assignment = GsonPtr.to(status).to("assignment"); - assignment.set("pool", event.usedPool()); - assignment.set("user", event.toUser()); - assignment.set("lastUsed", Instant.now().toString()); - return status; - }); - event.setResult(true); + try { + var vmDef = channel.vmDefinition(); + var vmStub = VmDefinitionStub.get(channel.client(), + new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), + vmDef.namespace(), vmDef.name()); + if (vmStub.updateStatus(vmDef, from -> { + JsonObject status = from.statusJson(); + var assignment = GsonPtr.to(status).to("assignment"); + assignment.set("pool", event.usedPool()); + assignment.set("user", event.toUser()); + assignment.set("lastUsed", Instant.now().toString()); + return status; + }).isPresent()) { + event.setResult(true); + } + } catch (ApiException e) { + // Log exceptions except for conflict, which can be expected + if (HttpURLConnection.HTTP_CONFLICT != e.getCode()) { + throw e; + } + } + event.setResult(false); } } 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 e506d44..17e3c58 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 @@ -256,49 +256,56 @@ public class VmMonitor extends @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public void onAssignVm(AssignVm event) throws ApiException, InterruptedException { - // Search for existing assignment. - var assignedVm = channelManager.channels().stream() - .filter(c -> c.vmDefinition().assignedFrom() - .map(p -> p.equals(event.fromPool())).orElse(false)) - .filter(c -> c.vmDefinition().assignedTo() - .map(u -> u.equals(event.toUser())).orElse(false)) - .findFirst(); - if (assignedVm.isPresent()) { - var vmDef = assignedVm.get().vmDefinition(); - event.setResult(new VmData(vmDef, assignedVm.get())); - return; + while (true) { + // Search for existing assignment. + var vmQuery = channelManager.channels().stream() + .filter(c -> c.vmDefinition().assignedFrom() + .map(p -> p.equals(event.fromPool())).orElse(false)) + .filter(c -> c.vmDefinition().assignedTo() + .map(u -> u.equals(event.toUser())).orElse(false)) + .findFirst(); + if (vmQuery.isPresent()) { + var vmDef = vmQuery.get().vmDefinition(); + event.setResult(new VmData(vmDef, vmQuery.get())); + return; + } + + // Get the pool definition for checking possible assignment + VmPool vmPool = newEventPipeline().fire(new GetPools() + .withName(event.fromPool())).get().stream().findFirst() + .orElse(null); + if (vmPool == null) { + return; + } + + // Find available VM. + vmQuery = channelManager.channels().stream() + .filter(c -> vmPool.isAssignable(c.vmDefinition())) + .sorted(Comparator.comparing((VmChannel c) -> c.vmDefinition() + .assignmentLastUsed().orElse(Instant.ofEpochSecond(0))) + .thenComparing(preferRunning)) + .findFirst(); + + // None found + if (vmQuery.isEmpty()) { + return; + } + + // Assign to user + var chosenVm = vmQuery.get(); + var vmPipeline = chosenVm.pipeline(); + if (Optional.ofNullable(vmPipeline.fire(new UpdateAssignment( + vmPool.name(), event.toUser()), chosenVm).get()) + .orElse(false)) { + var vmDef = chosenVm.vmDefinition(); + event.setResult(new VmData(vmDef, chosenVm)); + + // Make sure that a newly assigned VM is running. + chosenVm.pipeline().fire(new ModifyVm(vmDef.name(), + "state", "Running", chosenVm)); + return; + } } - - // Get the pool definition assignability check - VmPool vmPool = newEventPipeline().fire(new GetPools() - .withName(event.fromPool())).get().stream().findFirst() - .orElse(null); - if (vmPool == null) { - return; - } - - // Find available VM. - assignedVm = channelManager.channels().stream() - .filter(c -> vmPool.isAssignable(c.vmDefinition())) - .sorted(Comparator.comparing((VmChannel c) -> c.vmDefinition() - .assignmentLastUsed().orElse(Instant.ofEpochSecond(0))) - .thenComparing(preferRunning)) - .findFirst(); - - // None found - if (assignedVm.isEmpty()) { - return; - } - - // Assign to user - assignedVm.get().pipeline().fire(new UpdateAssignment(vmPool.name(), - event.toUser()), assignedVm.get()).get(); - var vmDef = assignedVm.get().vmDefinition(); - event.setResult(new VmData(vmDef, assignedVm.get())); - - // Make sure that a newly assigned VM is running. - assignedVm.get().pipeline().fire(new ModifyVm(vmDef.name(), - "state", "Running", assignedVm.get())); } private static Comparator preferRunning From d27339b1e9cdc3ee23a02e53078a808846ba2024 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Feb 2025 13:54:10 +0100 Subject: [PATCH 173/342] Make VM extra data a class. --- .../vmoperator/common/VmDefinition.java | 101 +---------- .../vmoperator/common/VmExtraData.java | 171 ++++++++++++++++++ .../vmoperator/manager/runnerConfig.ftl.yaml | 2 +- .../vmoperator/manager/Reconciler.java | 2 +- .../jdrupes/vmoperator/manager/VmMonitor.java | 27 ++- .../jdrupes/vmoperator/vmaccess/VmAccess.java | 13 +- .../org/jdrupes/vmoperator/vmmgmt/VmMgmt.java | 15 +- 7 files changed, 208 insertions(+), 123 deletions(-) create mode 100644 org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmExtraData.java diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java index e677642..ec79b80 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmDefinition.java @@ -24,9 +24,6 @@ import com.google.gson.Gson; import com.google.gson.JsonObject; import io.kubernetes.client.openapi.JSON; import io.kubernetes.client.openapi.models.V1Condition; -import io.kubernetes.client.util.Strings; -import java.net.InetAddress; -import java.net.UnknownHostException; import java.time.Instant; import java.util.Collection; import java.util.Collections; @@ -38,9 +35,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; -import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; import org.jdrupes.vmoperator.util.DataPath; @@ -52,7 +47,7 @@ import org.jdrupes.vmoperator.util.DataPath; "PMD.CouplingBetweenObjects" }) public class VmDefinition extends K8sDynamicModel { - @SuppressWarnings("PMD.FieldNamingConventions") + @SuppressWarnings({ "PMD.FieldNamingConventions", "unused" }) private static final Logger logger = Logger.getLogger(VmDefinition.class.getName()); @SuppressWarnings("PMD.FieldNamingConventions") @@ -62,7 +57,7 @@ public class VmDefinition extends K8sDynamicModel { = new ObjectMapper().registerModule(new JavaTimeModule()); private final Model model; - private final Map extra = new ConcurrentHashMap<>(); + private VmExtraData extraData; /** * The VM state from the VM definition. @@ -295,27 +290,21 @@ public class VmDefinition extends K8sDynamicModel { } /** - * Set extra data (locally used, unknown to kubernetes). - * - * @param property the property - * @param value the value + * Set extra data (unknown to kubernetes). * @return the VM definition */ - public VmDefinition extra(String property, Object value) { - extra.put(property, value); + /* default */ VmDefinition extra(VmExtraData extraData) { + this.extraData = extraData; return this; } /** - * Return extra data. + * Return the extra data. * - * @param the generic type - * @param property the property - * @return the object + * @return the data */ - @SuppressWarnings("unchecked") - public T extra(String property) { - return (T) extra.get(property); + public Optional extra() { + return Optional.ofNullable(extraData); } /** @@ -403,78 +392,6 @@ public class VmDefinition extends K8sDynamicModel { .map(Number::longValue); } - /** - * Create a connection file. - * - * @param password the password - * @param preferredIpVersion the preferred IP version - * @param deleteConnectionFile the delete connection file - * @return the string - */ - public String connectionFile(String password, - Class preferredIpVersion, boolean deleteConnectionFile) { - var addr = displayIp(preferredIpVersion); - if (addr.isEmpty()) { - logger.severe(() -> "Failed to find display IP for " + name()); - return null; - } - var port = this. fromVm("display", "spice", "port") - .map(Number::longValue); - if (port.isEmpty()) { - logger.severe(() -> "No port defined for display of " + name()); - return null; - } - StringBuffer data = new StringBuffer(100) - .append("[virt-viewer]\ntype=spice\nhost=") - .append(addr.get().getHostAddress()).append("\nport=") - .append(port.get().toString()) - .append('\n'); - if (password != null) { - data.append("password=").append(password).append('\n'); - } - this. fromVm("display", "spice", "proxyUrl") - .ifPresent(u -> { - if (!Strings.isNullOrEmpty(u)) { - data.append("proxy=").append(u).append('\n'); - } - }); - if (deleteConnectionFile) { - data.append("delete-this-file=1\n"); - } - return data.toString(); - } - - private Optional displayIp(Class preferredIpVersion) { - Optional server = fromVm("display", "spice", "server"); - if (server.isPresent()) { - var srv = server.get(); - try { - var addr = InetAddress.getByName(srv); - logger.fine(() -> "Using IP address from CRD for " - + getMetadata().getName() + ": " + addr); - return Optional.of(addr); - } catch (UnknownHostException e) { - logger.log(Level.SEVERE, e, () -> "Invalid server address " - + srv + ": " + e.getMessage()); - return Optional.empty(); - } - } - var addrs = Optional.> ofNullable( - extra("nodeAddresses")).orElse(Collections.emptyList()).stream() - .map(a -> { - try { - return InetAddress.getByName(a); - } catch (UnknownHostException e) { - logger.warning(() -> "Invalid IP address: " + a); - return null; - } - }).filter(a -> a != null).toList(); - logger.fine(() -> "Known IP addresses for " + name() + ": " + addrs); - return addrs.stream() - .filter(a -> preferredIpVersion.isAssignableFrom(a.getClass())) - .findFirst().or(() -> addrs.stream().findFirst()); - } - /** * Hash code. * diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmExtraData.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmExtraData.java new file mode 100644 index 0000000..85913c2 --- /dev/null +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmExtraData.java @@ -0,0 +1,171 @@ +/* + * VM-Operator + * Copyright (C) 2025 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.common; + +import io.kubernetes.client.util.Strings; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Represents internally used dynamic data associated with a + * {@link VmDefinition}. + */ +public class VmExtraData { + + @SuppressWarnings("PMD.FieldNamingConventions") + private static final Logger logger + = Logger.getLogger(VmExtraData.class.getName()); + + private final VmDefinition vmDef; + private String nodeName = ""; + private List nodeAddresses = Collections.emptyList(); + private long resetCount; + + /** + * Initializes a new instance. + * + * @param vmDef the VM definition + */ + public VmExtraData(VmDefinition vmDef) { + this.vmDef = vmDef; + vmDef.extra(this); + } + + /** + * Sets the node info. + * + * @param name the name + * @param addresses the addresses + * @return the VM extra data + */ + public VmExtraData nodeInfo(String name, List addresses) { + nodeName = name; + nodeAddresses = addresses; + return this; + } + + /** + * Return the node name. + * + * @return the string + */ + public String nodeName() { + return nodeName; + } + + /** + * Sets the reset count. + * + * @param resetCount the reset count + * @return the vm extra data + */ + public VmExtraData resetCount(long resetCount) { + this.resetCount = resetCount; + return this; + } + + /** + * Returns the reset count. + * + * @return the long + */ + public long resetCount() { + return resetCount; + } + + /** + * Create a connection file. + * + * @param password the password + * @param preferredIpVersion the preferred IP version + * @param deleteConnectionFile the delete connection file + * @return the string + */ + public String connectionFile(String password, + Class preferredIpVersion, boolean deleteConnectionFile) { + var addr = displayIp(preferredIpVersion); + if (addr.isEmpty()) { + logger + .severe(() -> "Failed to find display IP for " + vmDef.name()); + return null; + } + var port = vmDef. fromVm("display", "spice", "port") + .map(Number::longValue); + if (port.isEmpty()) { + logger + .severe(() -> "No port defined for display of " + vmDef.name()); + return null; + } + StringBuffer data = new StringBuffer(100) + .append("[virt-viewer]\ntype=spice\nhost=") + .append(addr.get().getHostAddress()).append("\nport=") + .append(port.get().toString()) + .append('\n'); + if (password != null) { + data.append("password=").append(password).append('\n'); + } + vmDef. fromVm("display", "spice", "proxyUrl") + .ifPresent(u -> { + if (!Strings.isNullOrEmpty(u)) { + data.append("proxy=").append(u).append('\n'); + } + }); + if (deleteConnectionFile) { + data.append("delete-this-file=1\n"); + } + return data.toString(); + } + + private Optional displayIp(Class preferredIpVersion) { + Optional server = vmDef.fromVm("display", "spice", "server"); + if (server.isPresent()) { + var srv = server.get(); + try { + var addr = InetAddress.getByName(srv); + logger.fine(() -> "Using IP address from CRD for " + + vmDef.metadata().getName() + ": " + addr); + return Optional.of(addr); + } catch (UnknownHostException e) { + logger.log(Level.SEVERE, e, () -> "Invalid server address " + + srv + ": " + e.getMessage()); + return Optional.empty(); + } + } + var addrs = nodeAddresses.stream().map(a -> { + try { + return InetAddress.getByName(a); + } catch (UnknownHostException e) { + logger.warning(() -> "Invalid IP address: " + a); + return null; + } + }).filter(Objects::nonNull).toList(); + logger.fine( + () -> "Known IP addresses for " + vmDef.name() + ": " + addrs); + return addrs.stream() + .filter(a -> preferredIpVersion.isAssignableFrom(a.getClass())) + .findFirst().or(() -> addrs.stream().findFirst()); + } + +} 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 f348244..f5aabc5 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 @@ -53,7 +53,7 @@ data: # 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.extra("resetCount")?c } + resetCounter: ${ cr.extra().get().resetCount()?c } # Forward the cloud-init data if provided <#if spec.cloudInit??> 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 641247a..7dbb410 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 @@ -248,7 +248,7 @@ public class Reconciler extends Component { public void onResetVm(ResetVm event, VmChannel channel) throws ApiException, IOException, TemplateException { var vmDef = channel.vmDefinition(); - vmDef.extra("resetCount", vmDef. extra("resetCount") + 1); + vmDef.extra().ifPresent(e -> e.resetCount(e.resetCount() + 1)); Map model = prepareModel(channel.client(), channel.vmDefinition()); cmReconciler.reconcile(model, channel); 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 17e3c58..5c1ae77 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 @@ -43,6 +43,7 @@ import org.jdrupes.vmoperator.common.K8sV1StatefulSetStub; import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.common.VmDefinitionStub; import org.jdrupes.vmoperator.common.VmDefinitions; +import org.jdrupes.vmoperator.common.VmExtraData; import org.jdrupes.vmoperator.common.VmPool; import static org.jdrupes.vmoperator.manager.Constants.APP_NAME; import static org.jdrupes.vmoperator.manager.Constants.VM_OP_NAME; @@ -139,7 +140,7 @@ public class VmMonitor extends } if (vmDef.data() != null) { // New data, augment and save - addDynamicData(channel.client(), vmDef, channel.vmDefinition()); + addExtraData(channel.client(), vmDef, channel.vmDefinition()); channel.setVmDefinition(vmDef); } else { // Reuse cached (e.g. if deleted) @@ -178,17 +179,14 @@ public class VmMonitor extends } @SuppressWarnings("PMD.AvoidDuplicateLiterals") - private void addDynamicData(K8sClient client, VmDefinition vmDef, + private void addExtraData(K8sClient client, VmDefinition vmDef, VmDefinition prevState) { - // Maintain (or initialize) the resetCount - vmDef.extra("resetCount", - Optional.ofNullable(prevState).map(d -> d.extra("resetCount")) - .orElse(0L)); + var extra = new VmExtraData(vmDef); - // Node information - // Add defaults in case the VM is not running - vmDef.extra("nodeName", ""); - vmDef.extra("nodeAddress", ""); + // Maintain (or initialize) the resetCount + extra.resetCount( + Optional.ofNullable(prevState).flatMap(VmDefinition::extra) + .map(VmExtraData::resetCount).orElse(0L)); // VM definition status changes before the pod terminates. // This results in pod information being shown for a stopped @@ -196,6 +194,8 @@ public class VmMonitor extends if (!vmDef.conditionStatus("Running").orElse(false)) { return; } + + // Get pod and extract node information. var podSearch = new ListOptions(); podSearch.setLabelSelector("app.kubernetes.io/name=" + APP_NAME + ",app.kubernetes.io/component=" + APP_NAME @@ -205,16 +205,15 @@ public class VmMonitor extends = K8sV1PodStub.list(client, namespace(), podSearch); for (var podStub : podList) { var nodeName = podStub.model().get().getSpec().getNodeName(); - vmDef.extra("nodeName", nodeName); - logger.fine(() -> "Added node name " + nodeName + logger.fine(() -> "Adding node name " + nodeName + " to VM info for " + vmDef.name()); @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") var addrs = new ArrayList(); podStub.model().get().getStatus().getPodIPs().stream() .map(ip -> ip.getIp()).forEach(addrs::add); - vmDef.extra("nodeAddresses", addrs); - logger.fine(() -> "Added node addresses " + addrs + logger.fine(() -> "Adding node addresses " + addrs + " to VM info for " + vmDef.name()); + extra.nodeInfo(nodeName, addrs); } } catch (ApiException e) { logger.log(Level.WARNING, e, diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index d6c385e..e283504 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -810,13 +810,12 @@ public class VmAccess extends FreeMarkerConlet { } var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef, user), e -> { - var data = vmDef.connectionFile(e.password().orElse(null), - preferredIpVersion, deleteConnectionFile); - if (data == null) { - return; - } - channel.respond(new NotifyConletView(type(), - model.getConletId(), "openConsole", data)); + vmDef.extra() + .map(xtra -> xtra.connectionFile(e.password().orElse(null), + preferredIpVersion, deleteConnectionFile)) + .ifPresent( + cf -> channel.respond(new NotifyConletView(type(), + model.getConletId(), "openConsole", cf))); }); fire(pwQuery, vmChannel); } diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java index 819a0d4..4cc63fa 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java @@ -41,6 +41,7 @@ import java.util.Set; import org.jdrupes.vmoperator.common.K8sObserver; import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.common.VmDefinition.Permission; +import org.jdrupes.vmoperator.common.VmExtraData; import org.jdrupes.vmoperator.manager.events.ChannelTracker; import org.jdrupes.vmoperator.manager.events.GetDisplayPassword; import org.jdrupes.vmoperator.manager.events.ModifyVm; @@ -252,7 +253,7 @@ public class VmMgmt extends FreeMarkerConlet { "name", vmDef.name()), "spec", spec, "status", status, - "nodeName", vmDef.extra("nodeName"), + "nodeName", vmDef.extra().map(VmExtraData::nodeName).orElse(""), "permissions", vmDef.permissionsFor(user, roles).stream() .map(VmDefinition.Permission::toString).toList()); } @@ -484,13 +485,11 @@ public class VmMgmt extends FreeMarkerConlet { } var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef, user), e -> { - var data = vmDef.connectionFile(e.password().orElse(null), - preferredIpVersion, deleteConnectionFile); - if (data == null) { - return; - } - channel.respond(new NotifyConletView(type(), - model.getConletId(), "openConsole", data)); + vmDef.extra().map(xtra -> xtra.connectionFile( + e.password().orElse(null), preferredIpVersion, + deleteConnectionFile)).ifPresent( + cf -> channel.respond(new NotifyConletView(type(), + model.getConletId(), "openConsole", cf))); }); fire(pwQuery, vmChannel); } From 1fc26647b615ac94f468a45c208005f1b9066b38 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Feb 2025 16:50:52 +0100 Subject: [PATCH 174/342] Add maintenance script. --- dev-example/.gitignore | 1 + dev-example/pool-action.sh | 62 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100755 dev-example/pool-action.sh diff --git a/dev-example/.gitignore b/dev-example/.gitignore index 16e0d04..1e31cc5 100644 --- a/dev-example/.gitignore +++ b/dev-example/.gitignore @@ -1,3 +1,4 @@ /test-vm-ci.yaml /kubeconfig.yaml /crds/ +/.vm-operator-cmd.rc diff --git a/dev-example/pool-action.sh b/dev-example/pool-action.sh new file mode 100755 index 0000000..b605479 --- /dev/null +++ b/dev-example/pool-action.sh @@ -0,0 +1,62 @@ +#!/bin/bash + +function usage() { + cat >&2 <&2 "Unknown option: $1"; exit 1;; + *) if [ ! -v pool ]; then + pool="$1" + elif [ ! -v action ]; then + action="$1" + else + usage + fi;; + esac + shift +done + +if [ ! -v pool -o ! -v "action" -o ! -v context ]; then + echo >&2 "Missing arguments or context not set." + echo >&2 + usage +fi +case "$action" in + "start"|"stop"|"delete"|"delete-disks") ;; + *) usage;; +esac + +kubectl --context="$context" -n "$namespace" get vms -o json \ + | jq -r '.items[] | select(.spec.pools | contains(["'${pool}'"])) | .metadata.name' \ +| while read vmName; do + case "$action" in + start) kubectl --context="$context" -n "$namespace" patch vms "$vmName" \ + --type='merge' -p '{"spec":{"vm":{"state":"Running"}}}';; + stop) kubectl --context="$context" -n "$namespace" patch vms "$vmName" \ + --type='merge' -p '{"spec":{"vm":{"state":"Stopped"}}}';; + delete) kubectl --context="$context" -n "$namespace" delete vm/"$vmName";; + delete-disks) kubectl --context="$context" -n "$namespace" delete \ + pvc -l app.kubernetes.io/instance="$vmName" ;; + esac +done From 5078001f4bfbb0fe9b35afa05c04c9edba504d74 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 10 Feb 2025 22:24:10 +0100 Subject: [PATCH 175/342] Add guest agent client and retrieve OS info. --- deploy/crds/vms-crd.yaml | 4 + dev-example/test-vm.yaml | 9 +- .../vmoperator/runner/qemu/Configuration.java | 4 + .../runner/qemu/GuestAgentClient.java | 254 ++++++++++++++++++ .../vmoperator/runner/qemu/Runner.java | 3 + .../vmoperator/runner/qemu/StatusUpdater.java | 33 +++ .../qemu/commands/QmpGuestGetOsinfo.java | 41 +++ .../runner/qemu/commands/QmpGuestInfo.java | 41 +++ .../runner/qemu/commands/QmpGuestPing.java | 41 +++ .../runner/qemu/events/GuestAgentCommand.java | 63 +++++ .../runner/qemu/events/MonitorEvent.java | 5 +- .../runner/qemu/events/OsinfoEvent.java | 43 +++ .../qemu/events/VserportChangeEvent.java | 56 ++++ .../templates/Standard-VM-latest.ftl.yaml | 2 +- 14 files changed, 592 insertions(+), 7 deletions(-) create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestGetOsinfo.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestInfo.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestPing.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/GuestAgentCommand.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/OsinfoEvent.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/VserportChangeEvent.java diff --git a/deploy/crds/vms-crd.yaml b/deploy/crds/vms-crd.yaml index 7b46dc7..749b896 100644 --- a/deploy/crds/vms-crd.yaml +++ b/deploy/crds/vms-crd.yaml @@ -1491,6 +1491,10 @@ spec: by the runner if password protection is not enabled. type: integer default: 0 + osinfo: + description: Copy of the OS info provided by the guest agent. + type: object + x-kubernetes-preserve-unknown-fields: true assignment: description: >- The assignment of this VM to a a particular user. diff --git a/dev-example/test-vm.yaml b/dev-example/test-vm.yaml index 7ee2793..aa75bc3 100644 --- a/dev-example/test-vm.yaml +++ b/dev-example/test-vm.yaml @@ -5,9 +5,7 @@ metadata: name: test-vm spec: image: - repository: docker-registry.lan.mnl.de - path: vmoperator/org.jdrupes.vmoperator.runner.qemu-alpine - version: latest + source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:testing pullPolicy: Always permissions: @@ -34,8 +32,9 @@ spec: currentCpus: 4 networks: - - tap: - mac: "02:16:3e:33:58:10" + # No bridge on test cluster + - user: {} + disks: - volumeClaimTemplate: metadata: 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 dd45147..086f085 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 @@ -67,6 +67,9 @@ public class Configuration implements Dto { /** The monitor socket. */ public Path monitorSocket; + /** The guest agent socket socket. */ + public Path guestAgentSocket; + /** The firmware rom. */ public Path firmwareRom; @@ -341,6 +344,7 @@ public class Configuration implements Dto { runtimeDir.toFile().mkdir(); swtpmSocket = runtimeDir.resolve("swtpm-sock"); monitorSocket = runtimeDir.resolve("monitor.sock"); + guestAgentSocket = runtimeDir.resolve("org.qemu.guest_agent.0"); } if (!Files.isDirectory(runtimeDir) || !Files.isWritable(runtimeDir)) { logger.severe(() -> String.format( diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java new file mode 100644 index 0000000..4d1c764 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java @@ -0,0 +1,254 @@ +/* + * VM-Operator + * Copyright (C) 2025 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; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.UnixDomainSocketAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.LinkedList; +import java.util.Queue; +import java.util.logging.Level; +import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand; +import org.jdrupes.vmoperator.runner.qemu.commands.QmpGuestGetOsinfo; +import org.jdrupes.vmoperator.runner.qemu.events.GuestAgentCommand; +import org.jdrupes.vmoperator.runner.qemu.events.MonitorReady; +import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent; +import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent; +import org.jgrapes.core.Channel; +import org.jgrapes.core.Component; +import org.jgrapes.core.EventPipeline; +import org.jgrapes.core.annotation.Handler; +import org.jgrapes.core.events.Start; +import org.jgrapes.core.events.Stop; +import org.jgrapes.io.events.Closed; +import org.jgrapes.io.events.ConnectError; +import org.jgrapes.io.events.Input; +import org.jgrapes.io.events.OpenSocketConnection; +import org.jgrapes.io.util.ByteBufferWriter; +import org.jgrapes.io.util.LineCollector; +import org.jgrapes.net.SocketIOChannel; +import org.jgrapes.net.events.ClientConnected; +import org.jgrapes.util.events.ConfigurationUpdate; + +/** + * A component that handles the communication over the guest agent + * socket. + * + * If the log level for this class is set to fine, the messages + * exchanged on the monitor socket are logged. + */ +@SuppressWarnings("PMD.DataflowAnomalyAnalysis") +public class GuestAgentClient extends Component { + + private static ObjectMapper mapper = new ObjectMapper(); + + private EventPipeline rep; + private Path socketPath; + private SocketIOChannel gaChannel; + private final Queue executing = new LinkedList<>(); + + /** + * Instantiates a new guest agent client. + * + * @param componentChannel the component channel + * @throws IOException Signals that an I/O exception has occurred. + */ + @SuppressWarnings({ "PMD.AssignmentToNonFinalStatic", + "PMD.ConstructorCallsOverridableMethod" }) + public GuestAgentClient(Channel componentChannel) throws IOException { + super(componentChannel); + } + + /** + * As the initial configuration of this component depends on the + * configuration of the {@link Runner}, it doesn't have a handler + * for the {@link ConfigurationUpdate} event. The values are + * forwarded from the {@link Runner} instead. + * + * @param socketPath the socket path + * @param powerdownTimeout + */ + /* default */ void configure(Path socketPath) { + this.socketPath = socketPath; + } + + /** + * Handle the start event. + * + * @param event the event + * @throws IOException Signals that an I/O exception has occurred. + */ + @Handler + public void onStart(Start event) throws IOException { + rep = event.associated(EventPipeline.class).get(); + if (socketPath == null) { + return; + } + Files.deleteIfExists(socketPath); + } + + /** + * When the virtual serial port "channel0" has been opened, + * establish the connection by opening the socket. + * + * @param event the event + */ + @Handler + public void onVserportChanged(VserportChangeEvent event) { + if ("channel0".equals(event.id()) && event.isOpen()) { + fire(new OpenSocketConnection( + UnixDomainSocketAddress.of(socketPath)) + .setAssociated(GuestAgentClient.class, this)); + } + } + + /** + * Check if this is from opening the monitor socket and if true, + * save the socket in the context and associate the channel with + * the context. Then send the initial message to the socket. + * + * @param event the event + * @param channel the channel + */ + @SuppressWarnings("resource") + @Handler + public void onClientConnected(ClientConnected event, + SocketIOChannel channel) { + event.openEvent().associated(GuestAgentClient.class).ifPresent(qm -> { + gaChannel = channel; + channel.setAssociated(GuestAgentClient.class, this); + channel.setAssociated(Writer.class, new ByteBufferWriter( + channel).nativeCharset()); + channel.setAssociated(LineCollector.class, + new LineCollector() + .consumer(line -> { + try { + processGuestAgentInput(line); + } catch (IOException e) { + throw new UndeclaredThrowableException(e); + } + })); + fire(new GuestAgentCommand(new QmpGuestGetOsinfo())); + }); + } + + /** + * Called when a connection attempt fails. + * + * @param event the event + * @param channel the channel + */ + @Handler + public void onConnectError(ConnectError event, SocketIOChannel channel) { + event.event().associated(GuestAgentClient.class).ifPresent(qm -> { + rep.fire(new Stop()); + }); + } + + /** + * Handle data from qemu monitor connection. + * + * @param event the event + * @param channel the channel + */ + @Handler + public void onInput(Input event, SocketIOChannel channel) { + if (channel.associated(GuestAgentClient.class).isEmpty()) { + return; + } + channel.associated(LineCollector.class).ifPresent(collector -> { + collector.feed(event); + }); + } + + private void processGuestAgentInput(String line) + throws IOException { + logger.fine(() -> "guest agent(in): " + line); + try { + var response = mapper.readValue(line, ObjectNode.class); + if (response.has("QMP")) { + rep.fire(new MonitorReady()); + return; + } + if (response.has("return") || response.has("error")) { + QmpCommand executed = executing.poll(); + logger.fine( + () -> String.format("(Previous \"guest agent(in)\" is " + + "result from executing %s)", executed)); + if (executed instanceof QmpGuestGetOsinfo) { + rep.fire(new OsinfoEvent(response.get("return"))); + } + } + } catch (JsonProcessingException e) { + throw new IOException(e); + } + } + + /** + * On closed. + * + * @param event the event + */ + @Handler + @SuppressWarnings({ "PMD.AvoidSynchronizedStatement", + "PMD.AvoidDuplicateLiterals" }) + public void onClosed(Closed event, SocketIOChannel channel) { + channel.associated(QemuMonitor.class).ifPresent(qm -> { + gaChannel = null; + }); + } + + /** + * On guest agent command. + * + * @param event the event + */ + @Handler + @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", + "PMD.AvoidSynchronizedStatement" }) + public void onGuestAgentCommand(GuestAgentCommand event) { + var command = event.command(); + logger.fine(() -> "guest agent(out): " + command.toString()); + String asText; + try { + asText = command.asText(); + } catch (JsonProcessingException e) { + logger.log(Level.SEVERE, e, + () -> "Cannot serialize Json: " + e.getMessage()); + return; + } + synchronized (executing) { + gaChannel.associated(Writer.class).ifPresent(writer -> { + try { + executing.add(command); + writer.append(asText).append('\n').flush(); + } catch (IOException e) { + // Cannot happen, but... + logger.log(Level.WARNING, e, e::getMessage); + } + }); + } + } +} 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 52db0ce..c8b9f44 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 @@ -218,6 +218,7 @@ public class Runner extends Component { private CommandDefinition cloudInitImgDefinition; private CommandDefinition qemuDefinition; private final QemuMonitor qemuMonitor; + private final GuestAgentClient guestAgentClient; private Integer resetCounter; private RunState state = RunState.INITIALIZING; @@ -275,6 +276,7 @@ public class Runner extends Component { attach(new ProcessManager(channel())); attach(new SocketConnector(channel())); attach(qemuMonitor = new QemuMonitor(channel(), configDir)); + attach(guestAgentClient = new GuestAgentClient(channel())); attach(new StatusUpdater(channel())); attach(new YamlConfigurationStore(channel(), configFile, false)); fire(new WatchFile(configFile.toPath())); @@ -349,6 +351,7 @@ public class Runner extends Component { // Forward some values to child components qemuMonitor.configure(config.monitorSocket, config.vm.powerdownTimeout); + guestAgentClient.configure(config.guestAgentSocket); } catch (IllegalArgumentException | IOException | TemplateException e) { logger.log(Level.SEVERE, e, () -> "Invalid configuration: " + e.getMessage()); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index d33358b..d4548bf 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -18,12 +18,16 @@ package org.jdrupes.vmoperator.runner.qemu; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.google.gson.Gson; import com.google.gson.JsonObject; import io.kubernetes.client.apimachinery.GroupVersionKind; import io.kubernetes.client.custom.Quantity; import io.kubernetes.client.custom.Quantity.Format; import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; +import io.kubernetes.client.openapi.JSON; import io.kubernetes.client.openapi.models.EventsV1Event; import java.io.IOException; import java.math.BigDecimal; @@ -40,6 +44,7 @@ import org.jdrupes.vmoperator.runner.qemu.events.ConfigureQemu; import org.jdrupes.vmoperator.runner.qemu.events.DisplayPasswordChanged; import org.jdrupes.vmoperator.runner.qemu.events.Exit; import org.jdrupes.vmoperator.runner.qemu.events.HotpluggableCpuStatus; +import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; import org.jdrupes.vmoperator.runner.qemu.events.ShutdownEvent; @@ -55,6 +60,12 @@ import org.jgrapes.core.events.Start; @SuppressWarnings("PMD.DataflowAnomalyAnalysis") public class StatusUpdater extends VmDefUpdater { + @SuppressWarnings("PMD.FieldNamingConventions") + private static final Gson gson = new JSON().getGson(); + @SuppressWarnings("PMD.FieldNamingConventions") + private static final ObjectMapper objectMapper + = new ObjectMapper().registerModule(new JavaTimeModule()); + private static final Set RUNNING_STATES = Set.of(RunState.RUNNING, RunState.TERMINATING); @@ -286,4 +297,26 @@ public class StatusUpdater extends VmDefUpdater { public void onShutdown(ShutdownEvent event) throws ApiException { shutdownByGuest = event.byGuest(); } + + /** + * On osinfo. + * + * @param event the event + * @throws ApiException + */ + @Handler + public void onOsinfo(OsinfoEvent event) throws ApiException { + if (vmStub == null) { + return; + } + var asGson = gson.toJsonTree( + objectMapper.convertValue(event.osinfo(), Object.class)); + + vmStub.updateStatus(from -> { + JsonObject status = from.statusJson(); + status.add("osinfo", asGson); + return status; + }); + + } } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestGetOsinfo.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestGetOsinfo.java new file mode 100644 index 0000000..cf4ba72 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestGetOsinfo.java @@ -0,0 +1,41 @@ +/* + * VM-Operator + * Copyright (C) 2025 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; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * A {@link QmpCommand} that pings the guest agent. + */ +public class QmpGuestGetOsinfo extends QmpCommand { + + @Override + public JsonNode toJson() { + ObjectNode cmd = mapper.createObjectNode(); + cmd.put("execute", "guest-get-osinfo"); + return cmd; + } + + @Override + public String toString() { + return "QmpGuestGetOsinfo()"; + } + +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestInfo.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestInfo.java new file mode 100644 index 0000000..75fdf73 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestInfo.java @@ -0,0 +1,41 @@ +/* + * VM-Operator + * Copyright (C) 2025 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; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * A {@link QmpCommand} that requests the guest info. + */ +public class QmpGuestInfo extends QmpCommand { + + @Override + public JsonNode toJson() { + ObjectNode cmd = mapper.createObjectNode(); + cmd.put("execute", "guest-info"); + return cmd; + } + + @Override + public String toString() { + return "QmpGuestInfo()"; + } + +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestPing.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestPing.java new file mode 100644 index 0000000..257c838 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/commands/QmpGuestPing.java @@ -0,0 +1,41 @@ +/* + * 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; +import com.fasterxml.jackson.databind.node.ObjectNode; + +/** + * A {@link QmpCommand} that pings the guest agent. + */ +public class QmpGuestPing extends QmpCommand { + + @Override + public JsonNode toJson() { + ObjectNode cmd = mapper.createObjectNode(); + cmd.put("execute", "guest-ping"); + return cmd; + } + + @Override + public String toString() { + return "QmpGuestPing()"; + } + +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/GuestAgentCommand.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/GuestAgentCommand.java new file mode 100644 index 0000000..a1b585d --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/GuestAgentCommand.java @@ -0,0 +1,63 @@ +/* + * VM-Operator + * Copyright (C) 2025 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.events; + +import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand; +import org.jgrapes.core.Channel; +import org.jgrapes.core.Components; +import org.jgrapes.core.Event; + +/** + * An {@link Event} that causes some component to send a QMP + * command to the guest agent process. + */ +public class GuestAgentCommand extends Event { + + private final QmpCommand command; + + /** + * Instantiates a new exec qmp command. + * + * @param command the command + */ + public GuestAgentCommand(QmpCommand command) { + this.command = command; + } + + /** + * Gets the command. + * + * @return the command + */ + public QmpCommand command() { + return command; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(Components.objectName(this)) + .append(" [").append(command); + if (channels() != null) { + builder.append(", channels=").append(Channel.toString(channels())); + } + builder.append(']'); + return builder.toString(); + } +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java index df981c8..e35a172 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java @@ -35,7 +35,7 @@ public class MonitorEvent extends Event { */ public enum Kind { READY, POWERDOWN, DEVICE_TRAY_MOVED, BALLOON_CHANGE, SHUTDOWN, - SPICE_CONNECTED, SPICE_INITIALIZED, SPICE_DISCONNECTED + SPICE_CONNECTED, SPICE_INITIALIZED, SPICE_DISCONNECTED, VSERPORT_CHANGE } private final Kind kind; @@ -72,6 +72,9 @@ public class MonitorEvent extends Event { case SPICE_DISCONNECTED: return Optional.of(new SpiceDisconnectedEvent(kind, response.get(EVENT_DATA))); + case VSERPORT_CHANGE: + return Optional.of(new VserportChangeEvent(kind, + response.get(EVENT_DATA))); default: return Optional .of(new MonitorEvent(kind, response.get(EVENT_DATA))); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/OsinfoEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/OsinfoEvent.java new file mode 100644 index 0000000..294ac7b --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/OsinfoEvent.java @@ -0,0 +1,43 @@ +/* + * VM-Operator + * Copyright (C) 2025 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.events; + +import com.fasterxml.jackson.databind.JsonNode; +import org.jgrapes.core.Event; + +/** + * Signals information about the guest OS. + */ +public class OsinfoEvent extends Event { + + private final JsonNode osinfo; + + /** + * Instantiates a new osinfo event. + * + * @param data the data + */ + public OsinfoEvent(JsonNode data) { + osinfo = data; + } + + public JsonNode osinfo() { + return osinfo; + } +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/VserportChangeEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/VserportChangeEvent.java new file mode 100644 index 0000000..b590cd3 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/VserportChangeEvent.java @@ -0,0 +1,56 @@ +/* + * 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.events; + +import com.fasterxml.jackson.databind.JsonNode; + +/** + * Signals a virtual serial port's open state change. + */ +public class VserportChangeEvent extends MonitorEvent { + + /** + * Initializes a new instance. + * + * @param kind the kind + * @param data the data + */ + public VserportChangeEvent(Kind kind, JsonNode data) { + super(kind, data); + } + + /** + * Return the channel's id. + * + * @return the string + */ + @SuppressWarnings("PMD.ShortMethodName") + public String id() { + return data().get("id").asText(); + } + + /** + * Returns the open state of the port. + * + * @return true, if is open + */ + public boolean isOpen() { + return Boolean.parseBoolean(data().get("open").asText()); + } +} diff --git a/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml b/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml index 5d10b54..e2610ba 100644 --- a/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml +++ b/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml @@ -122,7 +122,7 @@ # Best explanation found: # https://fedoraproject.org/wiki/Features/VirtioSerial - [ "-device", "virtio-serial-pci,id=virtio-serial0" ] - # - Guest agent serial connection + # - Guest agent serial connection. MUST have id "channel0"! - [ "-device", "virtserialport,id=channel0,name=org.qemu.guest_agent.0,\ chardev=guest-agent-socket" ] - [ "-chardev","socket,id=guest-agent-socket,\ From 0ded0ff9a9143eb7e41200014f62a7c0e8559014 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 16 Feb 2025 21:06:49 +0100 Subject: [PATCH 176/342] Add usage info. --- dev-example/pool-action.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dev-example/pool-action.sh b/dev-example/pool-action.sh index b605479..bc8fbce 100755 --- a/dev-example/pool-action.sh +++ b/dev-example/pool-action.sh @@ -7,6 +7,10 @@ Applys action to all VMs in the pool. --context Context to be passed to kubectl (required) -n, --namespace Namespace to be passed to kubectl + +Action is one of "start", "stop", "delete" or "delete-disks" + +Defaults for context and namespace are read from .vm-operator-cmd.rc. EOF exit 1 } From 3e713b4ff2434013d509a08aa577fc7fc1821085 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 17 Feb 2025 09:49:06 +0100 Subject: [PATCH 177/342] Extend comment. --- .../vmoperator/manager/DisplaySecretReconciler.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 0665d32..dcae3a3 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 @@ -41,13 +41,16 @@ import org.jose4j.base64url.Base64; /** * Delegee for reconciling the display secret */ -@SuppressWarnings("PMD.DataflowAnomalyAnalysis") +@SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.TooManyStaticImports" }) /* default */ class DisplaySecretReconciler { protected final Logger logger = Logger.getLogger(getClass().getName()); /** - * Reconcile. + * Reconcile. If the configuration prevents generating a secret + * or the secret already exists, do nothing. Else generate a new + * secret with a random password and immediate expiration, thus + * preventing access to the display. * * @param event the event * @param model the model From ec8152bd518572517f8f68cac63fdb2dd40dbb8f Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 17 Feb 2025 20:47:00 +0100 Subject: [PATCH 178/342] Add booted state. --- .../runner/qemu/GuestAgentClient.java | 5 -- .../vmoperator/runner/qemu/Runner.java | 60 ++++++++++++------- .../vmoperator/runner/qemu/StatusUpdater.java | 15 +++-- .../runner/qemu/events/RunnerStateChange.java | 23 ++++++- 4 files changed, 70 insertions(+), 33 deletions(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java index 4d1c764..f3928f5 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java @@ -33,7 +33,6 @@ import java.util.logging.Level; import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand; import org.jdrupes.vmoperator.runner.qemu.commands.QmpGuestGetOsinfo; import org.jdrupes.vmoperator.runner.qemu.events.GuestAgentCommand; -import org.jdrupes.vmoperator.runner.qemu.events.MonitorReady; import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent; import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent; import org.jgrapes.core.Channel; @@ -188,10 +187,6 @@ public class GuestAgentClient extends Component { logger.fine(() -> "guest agent(in): " + line); try { var response = mapper.readValue(line, ObjectNode.class); - if (response.has("QMP")) { - rep.fire(new MonitorReady()); - return; - } if (response.has("return") || response.has("error")) { QmpCommand executed = executing.poll(); logger.fine( 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 c8b9f44..b258e1a 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 @@ -61,6 +61,7 @@ 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; +import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent; import org.jdrupes.vmoperator.runner.qemu.events.QmpConfigured; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange; import org.jdrupes.vmoperator.runner.qemu.events.RunnerStateChange.RunState; @@ -619,8 +620,8 @@ public class Runner extends Component { } /** - * On monitor ready. - * + * When the monitor is ready, send QEMU its initial configuration. + * * @param event the event */ @Handler @@ -629,28 +630,14 @@ public class Runner extends Component { } /** - * On configure qemu. - * - * @param event the event - */ - @Handler(priority = -1000) - public void onConfigureQemuFinal(ConfigureQemu event) { - if (state == RunState.STARTING) { - fire(new MonitorCommand(new QmpCont())); - state = RunState.RUNNING; - rep.fire(new RunnerStateChange(state, "VmStarted", - "Qemu has been configured and is continuing")); - } - } - - /** - * On configure qemu. + * Whenever a new QEMU configuration is available, check if it + * is supposed to trigger a reset. * * @param event the event */ @Handler public void onConfigureQemu(ConfigureQemu event) { - if (state == RunState.RUNNING) { + if (state.vmActive()) { if (resetCounter != null && event.configuration().resetCounter != null && event.configuration().resetCounter > resetCounter) { @@ -660,6 +647,36 @@ public class Runner extends Component { } } + /** + * As last step when handling a new configuration, check if + * QEMU is suspended after startup and should be continued. + * + * @param event the event + */ + @Handler(priority = -1000) + public void onConfigureQemuFinal(ConfigureQemu event) { + if (state == RunState.STARTING) { + state = RunState.BOOTING; + fire(new MonitorCommand(new QmpCont())); + rep.fire(new RunnerStateChange(state, "VmStarted", + "Qemu has been configured and is continuing")); + } + } + + /** + * Receiving the OSinfo means that the OS has been booted. + * + * @param event the event + */ + @Handler + public void onOsinfo(OsinfoEvent event) { + if (state == RunState.BOOTING) { + state = RunState.BOOTED; + rep.fire(new RunnerStateChange(state, "VmBooted", + "The VM has started the guest agent.")); + } + } + /** * On process exited. * @@ -675,6 +692,7 @@ public class Runner extends Component { mayBeStartQemu(QemuPreps.CloudInit); return; } + // No other process(es) may exit during startup if (state == RunState.STARTING) { logger.severe(() -> "Process " + procDef.name @@ -683,7 +701,9 @@ public class Runner extends Component { rep.fire(new Stop()); return; } - if (procDef.equals(qemuDefinition) && state == RunState.RUNNING) { + + // No processes may exit while the VM is running normally + if (procDef.equals(qemuDefinition) && state.vmActive()) { rep.fire(new Exit(event.exitValue())); } logger.info(() -> "Process " + procDef.name diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java index d4548bf..f9644c8 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/StatusUpdater.java @@ -1,6 +1,6 @@ /* * VM-Operator - * Copyright (C) 2023,2024 Michael N. Lipp + * Copyright (C) 2023,2025 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 @@ -31,7 +31,6 @@ import io.kubernetes.client.openapi.JSON; import io.kubernetes.client.openapi.models.EventsV1Event; import java.io.IOException; import java.math.BigDecimal; -import java.util.Set; import java.util.logging.Level; import static org.jdrupes.vmoperator.common.Constants.APP_NAME; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; @@ -66,9 +65,6 @@ public class StatusUpdater extends VmDefUpdater { private static final ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule()); - private static final Set RUNNING_STATES - = Set.of(RunState.RUNNING, RunState.TERMINATING); - private long observedGeneration; private boolean guestShutdownStops; private boolean shutdownByGuest; @@ -186,16 +182,23 @@ public class StatusUpdater extends VmDefUpdater { } vmStub.updateStatus(vmDef, from -> { JsonObject status = from.statusJson(); - boolean running = RUNNING_STATES.contains(event.runState()); + boolean running = event.runState().vmRunning(); updateCondition(vmDef, vmDef.statusJson(), "Running", running, event.reason(), event.message()); + updateCondition(vmDef, vmDef.statusJson(), "Booted", + event.runState() == RunState.BOOTED, event.reason(), + event.message()); if (event.runState() == RunState.STARTING) { status.addProperty("ram", GsonPtr.to(from.data()) .getAsString("spec", "vm", "maximumRam").orElse("0")); status.addProperty("cpus", 1); + + // In case we had an irregular shutdown + status.remove("osinfo"); } else if (event.runState() == RunState.STOPPED) { status.addProperty("ram", "0"); status.addProperty("cpus", 0); + status.remove("osinfo"); } // In case console connection was still present diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java index bb6ab10..829cc88 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/RunnerStateChange.java @@ -18,6 +18,7 @@ package org.jdrupes.vmoperator.runner.qemu.events; +import java.util.EnumSet; import org.jgrapes.core.Channel; import org.jgrapes.core.Components; import org.jgrapes.core.Event; @@ -29,10 +30,28 @@ import org.jgrapes.core.Event; public class RunnerStateChange extends Event { /** - * The state. + * The states. */ public enum RunState { - INITIALIZING, STARTING, RUNNING, TERMINATING, STOPPED + INITIALIZING, STARTING, BOOTING, BOOTED, TERMINATING, STOPPED; + + /** + * Checks if the state is one of the states in which the VM is running. + * + * @return true, if is running + */ + public boolean vmRunning() { + return EnumSet.of(BOOTING, BOOTED, TERMINATING).contains(this); + } + + /** + * Checks if the state is one of the states in which the VM is active. + * + * @return true, if is active + */ + public boolean vmActive() { + return EnumSet.of(BOOTING, BOOTED).contains(this); + } } private final RunState state; From bccc4ac2190bc3bf1f8099e69d3b0977ca648229 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 18 Feb 2025 12:15:50 +0100 Subject: [PATCH 179/342] Add pretty os name to displayed data. --- .../org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html index 4dfc8d7..6ec6ce3 100644 --- a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html @@ -129,6 +129,9 @@
{{ localize("maximumCpus") }} + (conlet.element().querySelector( - ":scope .jdrupes-vmoperator-vmviewer-preview"))!; + ":scope .jdrupes-vmoperator-vmaccess-preview"))!; api.vmName = vmName; }); -JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer", +JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess", "updateVmDefinition", function(conletId: string, vmDefinition: any) { const conlet = JGConsole.findConletPreview(conletId); if (!conlet) { return; } const api = getApi(conlet.element().querySelector( - ":scope .jdrupes-vmoperator-vmviewer-preview"))!; + ":scope .jdrupes-vmoperator-vmaccess-preview"))!; // Add some short-cuts for rendering vmDefinition.name = vmDefinition.metadata.name; vmDefinition.currentCpus = vmDefinition.status.cpus; @@ -173,13 +173,13 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer", api.vmDefinition = vmDefinition; }); -JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer", +JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmaccess.VmAccess", "openConsole", function(_conletId: string, mimeType: string, data: string) { let target = document.getElementById( - "org.jdrupes.vmoperator.vmviewer.VmViewer.target"); + "org.jdrupes.vmoperator.vmaccess.VmAccess.target"); if (!target) { target = document.createElement("iframe"); - target.id = "org.jdrupes.vmoperator.vmviewer.VmViewer.target"; + target.id = "org.jdrupes.vmoperator.vmaccess.VmAccess.target"; target.setAttribute("name", target.id); target.setAttribute("style", "display: none;"); document.querySelector("body")!.append(target); @@ -188,7 +188,7 @@ JGConsole.registerConletFunction("org.jdrupes.vmoperator.vmviewer.VmViewer", window.open(url, target.id); }); -window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement, +window.orgJDrupesVmOperatorVmAccess.initEdit = (dialogDom: HTMLElement, isUpdate: boolean) => { if (isUpdate) { return; @@ -209,7 +209,7 @@ window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement, const conlet = JGConsole.findConletPreview(conletId); if (conlet) { const api = getApi(conlet.element().querySelector( - ":scope .jdrupes-vmoperator-vmviewer-preview"))!; + ":scope .jdrupes-vmoperator-vmaccess-preview"))!; vmNameInput.value = api.vmName; } @@ -222,7 +222,7 @@ window.orgJDrupesVmOperatorVmViewer.initEdit = (dialogDom: HTMLElement, app.mount(dialogDom); } -window.orgJDrupesVmOperatorVmViewer.applyEdit = +window.orgJDrupesVmOperatorVmAccess.applyEdit = (dialogDom: HTMLElement, apply: boolean) => { if (!apply) { return; @@ -233,7 +233,7 @@ window.orgJDrupesVmOperatorVmViewer.applyEdit = JGConsole.notifyConletModel(conletId, "selectedVm", vmName); } -window.orgJDrupesVmOperatorVmViewer.confirmReset = +window.orgJDrupesVmOperatorVmAccess.confirmReset = (conletType: string, conletId: string) => { JGConsole.instance.closeModalDialog(conletType, conletId); JGConsole.notifyConletModel(conletId, "resetConfirmed"); diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-style.scss similarity index 87% rename from org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss rename to org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-style.scss index 3ee432a..547dc74 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/VmViewer-style.scss +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-style.scss @@ -19,7 +19,7 @@ /* * Conlet specific styles. */ -.jdrupes-vmoperator-vmviewer { +.jdrupes-vmoperator-vmaccess { span[role="button"].svg-icon { display: inline-block; @@ -47,7 +47,7 @@ } } -.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-preview { +.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-preview { img { height: 3em; @@ -58,7 +58,7 @@ } } - .jdrupes-vmoperator-vmviewer-preview-action-list { + .jdrupes-vmoperator-vmaccess-preview-action-list { white-space: nowrap; } @@ -76,13 +76,13 @@ } } -.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-edit { +.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-edit { select { width: 15em; } } -.jdrupes-vmoperator-vmviewer.jdrupes-vmoperator-vmviewer-confirm-reset { +.jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-confirm-reset { p { text-align: center; } diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/l10nBundles-stub.d.ts b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/l10nBundles-stub.d.ts similarity index 100% rename from org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/browser/l10nBundles-stub.d.ts rename to org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/l10nBundles-stub.d.ts diff --git a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/package-info.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/package-info.java similarity index 89% rename from org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/package-info.java rename to org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/package-info.java index 9a4045a..745ded7 100644 --- a/org.jdrupes.vmoperator.vmviewer/src/org/jdrupes/vmoperator/vmviewer/package-info.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/package-info.java @@ -1,6 +1,6 @@ /* * VM-Operator - * Copyright (C) 2023 Michael N. Lipp + * Copyright (C) 2023, 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 @@ -16,4 +16,4 @@ * along with this program. If not, see . */ -package org.jdrupes.vmoperator.vmviewer; \ No newline at end of file +package org.jdrupes.vmoperator.vmaccess; diff --git a/org.jdrupes.vmoperator.vmviewer/tsconfig.json b/org.jdrupes.vmoperator.vmaccess/tsconfig.json similarity index 92% rename from org.jdrupes.vmoperator.vmviewer/tsconfig.json rename to org.jdrupes.vmoperator.vmaccess/tsconfig.json index 6418f59..d9dbb3f 100644 --- a/org.jdrupes.vmoperator.vmviewer/tsconfig.json +++ b/org.jdrupes.vmoperator.vmaccess/tsconfig.json @@ -14,7 +14,7 @@ "aash-plugin": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/aash-vue-components/lib/AashPlugin"], "jgconsole": ["./build/unpacked/org/jgrapes/webconsole/base/JGConsole"], "jgwc": ["./build/unpacked/org/jgrapes/webconsole/provider/jgwcvuecomponents/jgwc-vue-components/jgwc-components"], - "l10nBundles": ["./src/org/jdrupes/vmoperator/vmviewer/browser/l10nBundles-stub"], + "l10nBundles": ["./src/org/jdrupes/vmoperator/vmaccess/browser/l10nBundles-stub"], "vue": ["./build/unpacked/org/jgrapes/webconsole/provider/vue/vue/vue"] } }, diff --git a/org.jdrupes.vmoperator.vmviewer/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory b/org.jdrupes.vmoperator.vmviewer/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory deleted file mode 100644 index ebe4408..0000000 --- a/org.jdrupes.vmoperator.vmviewer/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory +++ /dev/null @@ -1 +0,0 @@ -org.jdrupes.vmoperator.vmviewer.VmViewerFactory diff --git a/settings.gradle b/settings.gradle index 64f3056..a32eaf8 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,6 +12,8 @@ rootProject.name = 'VM-Operator' include 'org.jdrupes.vmoperator.manager' include 'org.jdrupes.vmoperator.manager.events' +include 'org.jdrupes.vmoperator.poolaccess' +include 'org.jdrupes.vmoperator.vmaccess' include 'org.jdrupes.vmoperator.vmconlet' include 'org.jdrupes.vmoperator.vmviewer' include 'org.jdrupes.vmoperator.runner.qemu' diff --git a/webpages/vm-operator/VmViewer-preview.png b/webpages/vm-operator/VmAccess-preview.png similarity index 100% rename from webpages/vm-operator/VmViewer-preview.png rename to webpages/vm-operator/VmAccess-preview.png diff --git a/webpages/vm-operator/user-gui.md b/webpages/vm-operator/user-gui.md index ce46e8f..416e243 100644 --- a/webpages/vm-operator/user-gui.md +++ b/webpages/vm-operator/user-gui.md @@ -11,7 +11,7 @@ The idea of the user view is to provide an intuitive widget that allows the users to access their own VMs and to optionally start and stop them. -![VM-Viewer](VmViewer-preview.png) +![VM-Viewer](VmAccess-preview.png) The configuration options resulting from this seemingly simple requirement are unexpectedly complex. @@ -62,7 +62,7 @@ objects that either specify a role or a user. "/ConsoleWeblet": "/WebConsole": "/ComponentCollector": - "/VmViewer": + "/VmAccess": syncPreviewsFor: - role: user - user: test From eabb2d9cf02a7fbdc09d166fa070e8fa0a515b4d Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 12:52:42 +0100 Subject: [PATCH 110/342] Add method. --- .../org/jdrupes/vmoperator/common/VmPool.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java index aaa2746..8da0a9f 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmPool.java @@ -18,6 +18,7 @@ package org.jdrupes.vmoperator.common; +import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -25,6 +26,9 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.jdrupes.vmoperator.util.DataPath; /** * Represents a VM pool. @@ -97,6 +101,24 @@ public class VmPool { return builder.toString(); } + /** + * Collect all permissions for the given user with the given roles. + * + * @param user the user + * @param roles the roles + * @return the sets the + */ + public Set permissionsFor(String user, + Collection roles) { + return permissions.stream() + .filter(g -> DataPath.get(g, "user").map(u -> u.equals(user)) + .orElse(false) + || DataPath.get(g, "role").map(roles::contains).orElse(false)) + .map(g -> DataPath.> get(g, "may") + .orElse(Collections.emptySet()).stream()) + .flatMap(Function.identity()).collect(Collectors.toSet()); + } + /** * A permission grant to a user or role. * From 5efef2a083f9366cb622e5473bcebac3e1d66190 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 12:54:29 +0100 Subject: [PATCH 111/342] Deliver events on dedicated pipeline. --- .../vmoperator/manager/PoolManager.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java index f47c569..fb1de27 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/PoolManager.java @@ -43,10 +43,14 @@ import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.manager.events.VmPoolChanged; import org.jdrupes.vmoperator.util.GsonPtr; import org.jgrapes.core.Channel; +import org.jgrapes.core.EventPipeline; import org.jgrapes.core.annotation.Handler; +import org.jgrapes.core.events.Attached; /** - * Watches for changes of VM pools. + * Watches for changes of VM pools. Reports the changes using + * {@link VmPoolChanged} events fired on a special pipeline to + * avoid concurrent change informations. */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports" }) public class PoolManager extends @@ -55,6 +59,7 @@ public class PoolManager extends private final ReentrantLock pendingLock = new ReentrantLock(); private final Map> pending = new ConcurrentHashMap<>(); private final Map pools = new ConcurrentHashMap<>(); + private EventPipeline poolPipeline; /** * Instantiates a new VM pool manager. @@ -67,6 +72,19 @@ public class PoolManager extends K8sDynamicModels.class); } + /** + * On attached. + * + * @param event the event + */ + @Handler + @SuppressWarnings("PMD.CompareObjectsWithEquals") + public void onAttached(Attached event) { + if (event.node() == this) { + poolPipeline = newEventPipeline(); + } + } + @Override protected void prepareMonitoring() throws IOException, ApiException { client(new K8sClient()); @@ -96,7 +114,7 @@ public class PoolManager extends pending.computeIfAbsent(poolName, k -> Collections .synchronizedSet(new HashSet<>())).addAll(p.vms()); pools.remove(poolName); - fire(new VmPoolChanged(p, true)); + poolPipeline.fire(new VmPoolChanged(p, true)); }); } finally { pendingLock.unlock(); @@ -138,7 +156,7 @@ public class PoolManager extends }); pending.remove(poolName); pools.put(poolName, vmPool); - fire(new VmPoolChanged(vmPool)); + poolPipeline.fire(new VmPoolChanged(vmPool)); } finally { pendingLock.unlock(); } @@ -164,7 +182,7 @@ public class PoolManager extends pending.computeIfAbsent(p, k -> Collections .synchronizedSet(new HashSet<>())).add(vmName); } - fire(new VmPoolChanged(pools.get(p))); + poolPipeline.fire(new VmPoolChanged(pools.get(p))); }); } finally { pendingLock.unlock(); @@ -175,7 +193,7 @@ public class PoolManager extends pendingLock.lock(); pools.values().stream().forEach(p -> { if (p.vms().remove(vmName)) { - fire(new VmPoolChanged(p)); + poolPipeline.fire(new VmPoolChanged(p)); } }); // Should not be necessary, but just in case From 22446c361873885a823452b5888cdc601de11902 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 12:54:57 +0100 Subject: [PATCH 112/342] Clarify documentation. --- .../src/org/jdrupes/vmoperator/manager/AbstractMonitor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/AbstractMonitor.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/AbstractMonitor.java index 43f4287..2deb9ab 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/AbstractMonitor.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/AbstractMonitor.java @@ -246,7 +246,9 @@ public abstract class AbstractMonitor Date: Sat, 23 Nov 2024 12:55:48 +0100 Subject: [PATCH 113/342] Remove poolaccess conlet. --- settings.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index a32eaf8..50b3277 100644 --- a/settings.gradle +++ b/settings.gradle @@ -12,7 +12,6 @@ rootProject.name = 'VM-Operator' include 'org.jdrupes.vmoperator.manager' include 'org.jdrupes.vmoperator.manager.events' -include 'org.jdrupes.vmoperator.poolaccess' include 'org.jdrupes.vmoperator.vmaccess' include 'org.jdrupes.vmoperator.vmconlet' include 'org.jdrupes.vmoperator.vmviewer' From dc21dc8a7bcaaa9f89d8701e18bfcd655c6e6560 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 12:56:32 +0100 Subject: [PATCH 114/342] Test pools. --- dev-example/test-pool.yaml | 10 ++++++++++ dev-example/test-vm.tpl.yaml | 3 +++ 2 files changed, 13 insertions(+) create mode 100644 dev-example/test-pool.yaml diff --git a/dev-example/test-pool.yaml b/dev-example/test-pool.yaml new file mode 100644 index 0000000..73bd6ab --- /dev/null +++ b/dev-example/test-pool.yaml @@ -0,0 +1,10 @@ +apiVersion: "vmoperator.jdrupes.org/v1" +kind: VmPool +metadata: + namespace: vmop-dev + name: test-vms +spec: + permissions: + - user: admin + may: + - accessConsole diff --git a/dev-example/test-vm.tpl.yaml b/dev-example/test-vm.tpl.yaml index 6d8a89c..1ce8d95 100644 --- a/dev-example/test-vm.tpl.yaml +++ b/dev-example/test-vm.tpl.yaml @@ -30,6 +30,9 @@ spec: cloudInit: metaData: {} + pools: + - test-vms + vm: # state: Running bootMenu: true From c361f9296ddd1d311e3cbfefdae1499fcf6be695 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 13:03:04 +0100 Subject: [PATCH 115/342] Remove conlet. --- org.jdrupes.vmoperator.manager/build.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index f5ffe2c..cefac0b 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -33,7 +33,6 @@ dependencies { runtimeOnly project(':org.jdrupes.vmoperator.vmaccess') runtimeOnly project(':org.jdrupes.vmoperator.vmconlet') - runtimeOnly project(':org.jdrupes.vmoperator.poolaccess') } application { From 2be88d0f34facddbccfa77c8b329cb9a404497fd Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 13:06:51 +0100 Subject: [PATCH 116/342] Remove viewer. --- settings.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index 50b3277..be8546d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -14,7 +14,6 @@ include 'org.jdrupes.vmoperator.manager' include 'org.jdrupes.vmoperator.manager.events' include 'org.jdrupes.vmoperator.vmaccess' include 'org.jdrupes.vmoperator.vmconlet' -include 'org.jdrupes.vmoperator.vmviewer' include 'org.jdrupes.vmoperator.runner.qemu' include 'org.jdrupes.vmoperator.common' include 'org.jdrupes.vmoperator.util' From 4ceaaa9fa2371360c59c97e6f4e4a56ec0e77c68 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 14:08:01 +0100 Subject: [PATCH 117/342] Provide backward compatibility for configuration. --- dev-example/config.yaml | 2 +- dev-example/kustomization.yaml | 2 +- .../jdrupes/vmoperator/vmaccess/VmAccess.java | 83 +++++++++++-------- webpages/vm-operator/upgrading.md | 13 +++ 4 files changed, 63 insertions(+), 37 deletions(-) diff --git a/dev-example/config.yaml b/dev-example/config.yaml index 1c80ab8..f2e0563 100644 --- a/dev-example/config.yaml +++ b/dev-example/config.yaml @@ -65,7 +65,7 @@ other: - org.jgrapes.webconlet.oidclogin.LoginConlet "/ComponentCollector": - "/VmViewer": + "/VmAccess": displayResource: preferredIpVersion: ipv4 syncPreviewsFor: diff --git a/dev-example/kustomization.yaml b/dev-example/kustomization.yaml index f6e51b8..7dc4a15 100644 --- a/dev-example/kustomization.yaml +++ b/dev-example/kustomization.yaml @@ -79,7 +79,7 @@ patches: other: - org.jgrapes.webconlet.locallogin.LoginConlet "/ComponentCollector": - "/VmViewer": + "/VmAccess": displayResource: preferredIpVersion: ipv4 syncPreviewsFor: diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index b323084..e1a41ef 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -152,44 +152,57 @@ public class VmAccess extends FreeMarkerConlet { @SuppressWarnings({ "unchecked", "PMD.AvoidDuplicateLiterals" }) @Handler public void onConfigurationUpdate(ConfigurationUpdate event) { - event.structured(componentPath()).ifPresent(c -> { - try { - var dispRes = (Map) c - .getOrDefault("displayResource", Collections.emptyMap()); - switch ((String) dispRes.getOrDefault("preferredIpVersion", - "")) { - case "ipv6": - preferredIpVersion = Inet6Address.class; - break; - case "ipv4": - default: - preferredIpVersion = Inet4Address.class; - break; + event.structured(componentPath()) + .or(() -> { + var oldConfig = event.structured("/Manager/GuiHttpServer" + + "/ConsoleWeblet/WebConsole/ComponentCollector/VmViewer"); + if (oldConfig.isPresent()) { + logger.warning(() -> "Using configuration with old " + + "component name \"VmViewer\", please update to " + + "\"VmAccess\""); } + return oldConfig; + }) + .ifPresent(c -> { + try { + var dispRes = (Map) c + .getOrDefault("displayResource", + Collections.emptyMap()); + switch ((String) dispRes.getOrDefault("preferredIpVersion", + "")) { + case "ipv6": + preferredIpVersion = Inet6Address.class; + break; + case "ipv4": + default: + preferredIpVersion = Inet4Address.class; + break; + } - // Delete connection file - deleteConnectionFile - = Optional.ofNullable(c.get("deleteConnectionFile")) - .filter(v -> v instanceof String).map(v -> (String) v) - .map(Boolean::parseBoolean).orElse(true); + // Delete connection file + deleteConnectionFile + = Optional.ofNullable(c.get("deleteConnectionFile")) + .filter(v -> v instanceof String) + .map(v -> (String) v) + .map(Boolean::parseBoolean).orElse(true); - // Users or roles for which previews should be synchronized - syncUsers = ((List>) c.getOrDefault( - "syncPreviewsFor", Collections.emptyList())).stream() - .map(m -> m.get("user")) - .filter(s -> s != null).collect(Collectors.toSet()); - logger.finest(() -> "Syncing previews for users: " - + syncUsers.toString()); - syncRoles = ((List>) c.getOrDefault( - "syncPreviewsFor", Collections.emptyList())).stream() - .map(m -> m.get("role")) - .filter(s -> s != null).collect(Collectors.toSet()); - logger.finest(() -> "Syncing previews for roles: " - + syncRoles.toString()); - } catch (ClassCastException e) { - logger.config("Malformed configuration: " + e.getMessage()); - } - }); + // Users or roles for which previews should be synchronized + syncUsers = ((List>) c.getOrDefault( + "syncPreviewsFor", Collections.emptyList())).stream() + .map(m -> m.get("user")) + .filter(s -> s != null).collect(Collectors.toSet()); + logger.finest(() -> "Syncing previews for users: " + + syncUsers.toString()); + syncRoles = ((List>) c.getOrDefault( + "syncPreviewsFor", Collections.emptyList())).stream() + .map(m -> m.get("role")) + .filter(s -> s != null).collect(Collectors.toSet()); + logger.finest(() -> "Syncing previews for roles: " + + syncRoles.toString()); + } catch (ClassCastException e) { + logger.config("Malformed configuration: " + e.getMessage()); + } + }); } private boolean syncPreviews(Session session) { diff --git a/webpages/vm-operator/upgrading.md b/webpages/vm-operator/upgrading.md index ec5da7e..a794ab6 100644 --- a/webpages/vm-operator/upgrading.md +++ b/webpages/vm-operator/upgrading.md @@ -5,6 +5,19 @@ layout: vm-operator # Upgrading +## To version 4.0.0 + +The VmViewer conlet has been renamed to VmAccess. This affects the +[configuration](https://jdrupes.org/vm-operator/user-gui.html). Configuration information using the old path +"/Manager/GuiHttpServer/ConsoleWeblet/WebConsole/ComponentCollector/VmViewer" +is still accepted for backward compatibility, but should be updated. + +The change of name also causes conlets added to the overview page by +users to "disappear" from the GUI. They have to be re-added. + +The latter behavior also applies to the VmConlet conlet which has been +renamed to VmMgmt. + ## To version 3.4.0 Starting with this version, the VM-Operator no longer uses a stateful set From e839f7b3b2dd34a658ab776cc4142a20bfc66e59 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 23 Nov 2024 14:08:45 +0100 Subject: [PATCH 118/342] Rename conlet. --- org.jdrupes.vmoperator.manager/build.gradle | 2 +- ...apes.webconsole.base.ConletComponentFactory | 1 - .../.checkstyle | 0 .../.eclipse-pmd | 0 .../.eslintignore | 0 .../.eslintrc.json | 0 .../.gitignore | 0 .../.settings/org.eclipse.buildship.core.prefs | 0 .../.settings/org.eclipse.core.resources.prefs | 0 .../.settings/org.eclipse.core.runtime.prefs | 0 .../.settings/org.eclipse.jdt.ui.prefs | 0 .../build.gradle | 0 .../package.json | 0 ...apes.webconsole.base.ConletComponentFactory | 1 + .../vmmgmt/VmMgmt-l10nBundles.ftl.js | 0 .../vmoperator/vmmgmt/VmMgmt-preview.ftl.html | 4 ++-- .../vmoperator/vmmgmt/VmMgmt-view.ftl.html | 10 +++++----- .../jdrupes/vmoperator/vmmgmt}/l10n.properties | 2 +- .../vmoperator/vmmgmt}/l10n_de.properties | 2 +- .../vmoperator/vmmgmt}/l10n_en.properties | 0 .../rollup.config.mjs | 4 ++-- .../jdrupes/vmoperator/vmmgmt}/TimeSeries.java | 2 +- .../org/jdrupes/vmoperator/vmmgmt/VmMgmt.java | 14 +++++++------- .../vmoperator/vmmgmt/VmMgmtFactory.java | 10 +++++----- .../browser/ConditionalInputController.ts | 0 .../vmoperator/vmmgmt}/browser/CpuRamChart.ts | 0 .../vmoperator/vmmgmt}/browser/MemorySize.ts | 0 .../vmoperator/vmmgmt}/browser/TimeSeries.ts | 0 .../vmmgmt/browser/VmMgmt-functions.ts | 18 +++++++++--------- .../vmmgmt/browser/VmMgmt-style.scss | 8 ++++---- .../vmmgmt}/browser/l10nBundles-stub.d.ts | 0 .../vmoperator/vmmgmt}/package-info.java | 2 +- .../tsconfig.json | 2 +- settings.gradle | 2 +- 34 files changed, 42 insertions(+), 42 deletions(-) delete mode 100644 org.jdrupes.vmoperator.vmconlet/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.checkstyle (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.eclipse-pmd (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.eslintignore (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.eslintrc.json (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.gitignore (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.settings/org.eclipse.buildship.core.prefs (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.settings/org.eclipse.core.resources.prefs (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.settings/org.eclipse.core.runtime.prefs (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/.settings/org.eclipse.jdt.ui.prefs (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/build.gradle (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/package.json (100%) create mode 100644 org.jdrupes.vmoperator.vmmgmt/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory rename org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-l10nBundles.ftl.js => org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-l10nBundles.ftl.js (100%) rename org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-preview.ftl.html => org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-preview.ftl.html (88%) rename org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html => org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html (93%) rename {org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt}/l10n.properties (92%) rename {org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt}/l10n_de.properties (94%) rename {org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt}/l10n_en.properties (100%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/rollup.config.mjs (93%) rename {org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt}/TimeSeries.java (98%) rename org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/VmConlet.java => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java (97%) rename org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/VmConletFactory.java => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmtFactory.java (85%) rename {org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt}/browser/ConditionalInputController.ts (100%) rename {org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt}/browser/CpuRamChart.ts (100%) rename {org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt}/browser/MemorySize.ts (100%) rename {org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt}/browser/TimeSeries.ts (100%) rename org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-functions.ts => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-functions.ts (93%) rename org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet/browser/VmConlet-style.scss => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/browser/VmMgmt-style.scss (91%) rename {org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt}/browser/l10nBundles-stub.d.ts (100%) rename {org.jdrupes.vmoperator.vmconlet/src/org/jdrupes/vmoperator/vmconlet => org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt}/package-info.java (94%) rename {org.jdrupes.vmoperator.vmconlet => org.jdrupes.vmoperator.vmmgmt}/tsconfig.json (91%) diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index cefac0b..b581971 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -31,8 +31,8 @@ dependencies { runtimeOnly 'org.slf4j:slf4j-jdk14:[2.0.7,3)' runtimeOnly 'org.apache.logging.log4j:log4j-to-jul:2.20.0' + runtimeOnly project(':org.jdrupes.vmoperator.vmmgmt') runtimeOnly project(':org.jdrupes.vmoperator.vmaccess') - runtimeOnly project(':org.jdrupes.vmoperator.vmconlet') } application { diff --git a/org.jdrupes.vmoperator.vmconlet/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory b/org.jdrupes.vmoperator.vmconlet/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory deleted file mode 100644 index 5a22dc7..0000000 --- a/org.jdrupes.vmoperator.vmconlet/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory +++ /dev/null @@ -1 +0,0 @@ -org.jdrupes.vmoperator.vmconlet.VmConletFactory diff --git a/org.jdrupes.vmoperator.vmconlet/.checkstyle b/org.jdrupes.vmoperator.vmmgmt/.checkstyle similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.checkstyle rename to org.jdrupes.vmoperator.vmmgmt/.checkstyle diff --git a/org.jdrupes.vmoperator.vmconlet/.eclipse-pmd b/org.jdrupes.vmoperator.vmmgmt/.eclipse-pmd similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.eclipse-pmd rename to org.jdrupes.vmoperator.vmmgmt/.eclipse-pmd diff --git a/org.jdrupes.vmoperator.vmconlet/.eslintignore b/org.jdrupes.vmoperator.vmmgmt/.eslintignore similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.eslintignore rename to org.jdrupes.vmoperator.vmmgmt/.eslintignore diff --git a/org.jdrupes.vmoperator.vmconlet/.eslintrc.json b/org.jdrupes.vmoperator.vmmgmt/.eslintrc.json similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.eslintrc.json rename to org.jdrupes.vmoperator.vmmgmt/.eslintrc.json diff --git a/org.jdrupes.vmoperator.vmconlet/.gitignore b/org.jdrupes.vmoperator.vmmgmt/.gitignore similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.gitignore rename to org.jdrupes.vmoperator.vmmgmt/.gitignore diff --git a/org.jdrupes.vmoperator.vmconlet/.settings/org.eclipse.buildship.core.prefs b/org.jdrupes.vmoperator.vmmgmt/.settings/org.eclipse.buildship.core.prefs similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.settings/org.eclipse.buildship.core.prefs rename to org.jdrupes.vmoperator.vmmgmt/.settings/org.eclipse.buildship.core.prefs diff --git a/org.jdrupes.vmoperator.vmconlet/.settings/org.eclipse.core.resources.prefs b/org.jdrupes.vmoperator.vmmgmt/.settings/org.eclipse.core.resources.prefs similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.settings/org.eclipse.core.resources.prefs rename to org.jdrupes.vmoperator.vmmgmt/.settings/org.eclipse.core.resources.prefs diff --git a/org.jdrupes.vmoperator.vmconlet/.settings/org.eclipse.core.runtime.prefs b/org.jdrupes.vmoperator.vmmgmt/.settings/org.eclipse.core.runtime.prefs similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.settings/org.eclipse.core.runtime.prefs rename to org.jdrupes.vmoperator.vmmgmt/.settings/org.eclipse.core.runtime.prefs diff --git a/org.jdrupes.vmoperator.vmconlet/.settings/org.eclipse.jdt.ui.prefs b/org.jdrupes.vmoperator.vmmgmt/.settings/org.eclipse.jdt.ui.prefs similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/.settings/org.eclipse.jdt.ui.prefs rename to org.jdrupes.vmoperator.vmmgmt/.settings/org.eclipse.jdt.ui.prefs diff --git a/org.jdrupes.vmoperator.vmconlet/build.gradle b/org.jdrupes.vmoperator.vmmgmt/build.gradle similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/build.gradle rename to org.jdrupes.vmoperator.vmmgmt/build.gradle diff --git a/org.jdrupes.vmoperator.vmconlet/package.json b/org.jdrupes.vmoperator.vmmgmt/package.json similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/package.json rename to org.jdrupes.vmoperator.vmmgmt/package.json diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory b/org.jdrupes.vmoperator.vmmgmt/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory new file mode 100644 index 0000000..d7d7c8d --- /dev/null +++ b/org.jdrupes.vmoperator.vmmgmt/resources/META-INF/services/org.jgrapes.webconsole.base.ConletComponentFactory @@ -0,0 +1 @@ +org.jdrupes.vmoperator.vmmgmt.VmMgmtFactory diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-l10nBundles.ftl.js b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-l10nBundles.ftl.js similarity index 100% rename from org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-l10nBundles.ftl.js rename to org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-l10nBundles.ftl.js diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-preview.ftl.html b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-preview.ftl.html similarity index 88% rename from org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-preview.ftl.html rename to org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-preview.ftl.html index 0c6aa37..8c9970a 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-preview.ftl.html +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-preview.ftl.html @@ -1,6 +1,6 @@ -
diff --git a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html similarity index 93% rename from org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html rename to org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html index 0af656b..6b46faa 100644 --- a/org.jdrupes.vmoperator.vmconlet/resources/org/jdrupes/vmoperator/vmconlet/VmConlet-view.ftl.html +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html @@ -1,7 +1,7 @@ -
-
@@ -48,6 +48,11 @@ >{{ shortDateTime(entry[key].toString()) }} {{ formatMemory(entry[key]) }} + +
+ + + From 777ae73c745ecb769b3196dd468fc03b9d63e4fe Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 18 Feb 2025 16:50:43 +0100 Subject: [PATCH 180/342] Add OS icons. --- .../vmoperator/vmaccess/osicons/Licenses.txt | 16 + .../vmoperator/vmaccess/osicons/almalinux.svg | 16 + .../vmoperator/vmaccess/osicons/arch.svg | 20 + .../vmoperator/vmaccess/osicons/debian.svg | 9 + .../vmoperator/vmaccess/osicons/fedora.svg | Bin 0 -> 41315 bytes .../vmoperator/vmaccess/osicons/tux.svg | 438 ++++++++++++++++++ .../vmoperator/vmaccess/osicons/ubuntu.svg | 8 + .../vmoperator/vmaccess/osicons/unknown.svg | 84 ++++ .../vmoperator/vmaccess/osicons/windows.svg | 1 + .../vmaccess/browser/VmAccess-functions.ts | 33 +- .../vmaccess/browser/VmAccess-style.scss | 14 + 11 files changed, 634 insertions(+), 5 deletions(-) create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/Licenses.txt create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/almalinux.svg create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/arch.svg create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/debian.svg create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/fedora.svg create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/tux.svg create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/ubuntu.svg create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/unknown.svg create mode 100644 org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/windows.svg diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/Licenses.txt b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/Licenses.txt new file mode 100644 index 0000000..f67978f --- /dev/null +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/Licenses.txt @@ -0,0 +1,16 @@ +almalinux.svg: + Source: https://commons.wikimedia.org/wiki/File:AlmaLinux_Icon_Logo.svg + License: https://github.com/AlmaLinux/wiki/blob/master/LICENSE + +archlinux.svg: + Source: https://commons.wikimedia.org/wiki/File:Arch_Linux_%22Crystal%22_icon.svghttps://commons.wikimedia.org/wiki/File:Arch_Linux_%22Crystal%22_icon.svg + License: GPL v2 or later + +debian.svg: + Source: https://commons.wikimedia.org/wiki/File:Openlogo-debianV2.svg + License : LGPL + +tux.svg: + Source: https://commons.wikimedia.org/wiki/File:Tux.svghttps://commons.wikimedia.org/wiki/File:Tux.svg + License: Creative Commons CC0 1.0 Universal Public Domain Dedication. Creative Commons CC0 1.0 Universal Public Domain Dedication. + diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/almalinux.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/almalinux.svg new file mode 100644 index 0000000..b2e050a --- /dev/null +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/almalinux.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/arch.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/arch.svg new file mode 100644 index 0000000..ca8204c --- /dev/null +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/arch.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/debian.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/debian.svg new file mode 100644 index 0000000..685f632 --- /dev/null +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/debian.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/fedora.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/fedora.svg new file mode 100644 index 0000000000000000000000000000000000000000..78717917f660f45dd4c2e9d11c8af3b32c901589 GIT binary patch literal 41315 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 + + Tux + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/ubuntu.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/ubuntu.svg new file mode 100644 index 0000000..f217bc8 --- /dev/null +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/ubuntu.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/unknown.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/unknown.svg new file mode 100644 index 0000000..51f3016 --- /dev/null +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/unknown.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + OS + + + diff --git a/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/windows.svg b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/windows.svg new file mode 100644 index 0000000..2c7392e --- /dev/null +++ b/org.jdrupes.vmoperator.vmaccess/resources/org/jdrupes/vmoperator/vmaccess/osicons/windows.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts index 9d2e134..ec21fb5 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts @@ -87,6 +87,26 @@ window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement, const running = computed(() => previewApi.vmDefinition.running); const inUse = computed(() => previewApi.vmDefinition.usedBy != ''); const permissions = computed(() => previewApi.permissions); + const osicon = computed(() => { + if (!previewApi.vmDefinition.status?.osinfo?.id) { + return null; + } + switch(previewApi.vmDefinition.status.osinfo.id) { + case "almalinux": return "almalinux.svg"; + case "arch": return "arch.svg"; + case "debian": return "debian.svg"; + case "fedora": return "fedora.svg"; + case "mswindows": return "windows.svg"; + case "ubuntu": return "ubuntu.svg"; + default: { + if ((previewApi.vmDefinition.status.osinfo.name || "") + .toLowerCase().includes("linux")) { + return "tux.svg"; + } + return "unknown.svg"; + } + } + }); watch(previewApi, (api: Api) => { JGConsole.instance.updateConletTitle(conletId, @@ -101,7 +121,7 @@ window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement, return { localize, resourceBase, vmAction, poolName, vmName, configured, busy, startable, stoppable, running, inUse, - permissions }; + permissions, osicon }; }, template: `
{{ entry.status?.osinfo?.["pretty-name"] || "" }}
{{ localize("usedFrom") }} {{ entry.usedFrom }}
@@ -111,13 +131,16 @@ window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement, style="position: absolute;" :class="{ busy: busy }" > + :src="resourceBase + 'computer.svg'"> diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-style.scss b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-style.scss index 86b4014..63ae299 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-style.scss +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-style.scss @@ -79,6 +79,20 @@ z-index: 100; pointer-events: none; } + + span.osicon { + width: 4.25em; + height: 3em; + padding: 0.25rem; + pointer-events: none; + + img { + display: block; + height: 1.75em; + margin: 0.2em auto 0; + pointer-events: none; + } + } } .jdrupes-vmoperator-vmaccess.jdrupes-vmoperator-vmaccess-edit { From 5ad052ffe479341ade5833af0d499620eb08c61a Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 19 Feb 2025 21:04:08 +0100 Subject: [PATCH 181/342] Delay console opening for pool VMs. --- .../manager/events/GetDisplayPassword.java | 74 ----------- .../manager/events/PrepareConsole.java | 119 ++++++++++++++++++ .../manager/DisplaySecretMonitor.java | 48 ++++--- .../jdrupes/vmoperator/vmaccess/VmAccess.java | 25 ++-- .../vmaccess/browser/VmAccess-functions.ts | 21 ++-- .../org/jdrupes/vmoperator/vmmgmt/VmMgmt.java | 23 ++-- 6 files changed, 191 insertions(+), 119 deletions(-) delete mode 100644 org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetDisplayPassword.java create mode 100644 org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/PrepareConsole.java diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetDisplayPassword.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetDisplayPassword.java deleted file mode 100644 index f6fa555..0000000 --- a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/GetDisplayPassword.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 java.util.Optional; -import org.jdrupes.vmoperator.common.VmDefinition; -import org.jgrapes.core.Event; - -/** - * Gets the current display secret and optionally updates it. - */ -@SuppressWarnings("PMD.DataClass") -public class GetDisplayPassword extends Event { - - private final VmDefinition vmDef; - private final String user; - - /** - * Instantiates a new request for the display secret. - * - * @param vmDef the vm name - * @param user the requesting user - */ - public GetDisplayPassword(VmDefinition vmDef, String user) { - this.vmDef = vmDef; - this.user = user; - } - - /** - * Gets the vm definition. - * - * @return the vm definition - */ - public VmDefinition vmDefinition() { - return vmDef; - } - - /** - * Return the id of the user who has requested the password. - * - * @return the string - */ - public String user() { - return user; - } - - /** - * Return the password. May only be called when the event is completed. - * - * @return the optional - */ - public Optional password() { - if (!isDone()) { - throw new IllegalStateException("Event is not done."); - } - return currentResults().stream().findFirst(); - } -} diff --git a/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/PrepareConsole.java b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/PrepareConsole.java new file mode 100644 index 0000000..ad8f9ce --- /dev/null +++ b/org.jdrupes.vmoperator.manager.events/src/org/jdrupes/vmoperator/manager/events/PrepareConsole.java @@ -0,0 +1,119 @@ +/* + * 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.jdrupes.vmoperator.common.VmDefinition; +import org.jgrapes.core.Event; + +/** + * Gets the current display secret and optionally updates it. + */ +@SuppressWarnings("PMD.DataClass") +public class PrepareConsole extends Event { + + private final VmDefinition vmDef; + private final String user; + private final boolean loginUser; + + /** + * Instantiates a new request for the display secret. + * After handling the event, a result of `null` means that + * no password is needed. No result means that the console + * is not accessible. + * + * @param vmDef the vm name + * @param user the requesting user + * @param loginUser login the user + */ + public PrepareConsole(VmDefinition vmDef, String user, + boolean loginUser) { + this.vmDef = vmDef; + this.user = user; + this.loginUser = loginUser; + } + + /** + * Instantiates a new request for the display secret. + * After handling the event, a result of `null` means that + * no password is needed. No result means that the console + * is not accessible. + * + * @param vmDef the vm name + * @param user the requesting user + */ + public PrepareConsole(VmDefinition vmDef, String user) { + this(vmDef, user, false); + } + + /** + * Gets the vm definition. + * + * @return the vm definition + */ + public VmDefinition vmDefinition() { + return vmDef; + } + + /** + * Return the id of the user who has requested the password. + * + * @return the string + */ + public String user() { + return user; + } + + /** + * Checks if the user should be logged in before allowing access. + * + * @return the loginUser + */ + public boolean loginUser() { + return loginUser; + } + + /** + * Returns `true` if a password is available. May only be called + * when the event is completed. Note that the password returned + * by {@link #password()} may be `null`, indicating that no password + * is needed. + * + * @return true, if successful + */ + public boolean passwordAvailable() { + if (!isDone()) { + throw new IllegalStateException("Event is not done."); + } + return !currentResults().isEmpty(); + } + + /** + * Return the password. May only be called when the event has been + * completed with a valid result (see {@link #passwordAvailable()}). + * + * @return the password. A value of `null` means that no password + * is required. + */ + public String password() { + if (!isDone() || currentResults().isEmpty()) { + throw new IllegalStateException("Event is not done."); + } + return currentResults().get(0); + } +} 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 a0809e9..152f91e 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 @@ -50,7 +50,7 @@ import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET; import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_PASSWORD; import static org.jdrupes.vmoperator.manager.Constants.DATA_PASSWORD_EXPIRY; import org.jdrupes.vmoperator.manager.events.ChannelDictionary; -import org.jdrupes.vmoperator.manager.events.GetDisplayPassword; +import org.jdrupes.vmoperator.manager.events.PrepareConsole; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jgrapes.core.Channel; @@ -72,7 +72,7 @@ public class DisplaySecretMonitor extends AbstractMonitor { private int passwordValidity = 10; - private final List pendingGets + private final List pendingPrepares = Collections.synchronizedList(new LinkedList<>()); private final ChannelDictionary channelDictionary; @@ -178,49 +178,59 @@ public class DisplaySecretMonitor */ @Handler @SuppressWarnings("PMD.StringInstantiation") - public void onGetDisplaySecrets(GetDisplayPassword event, VmChannel channel) + public void onPrepareConsole(PrepareConsole event, VmChannel channel) throws ApiException { // Update console user in status var vmStub = VmDefinitionStub.get(client(), new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), event.vmDefinition().namespace(), event.vmDefinition().name()); - vmStub.updateStatus(from -> { + var optVmDef = vmStub.updateStatus(from -> { JsonObject status = from.statusJson(); status.addProperty("consoleUser", event.user()); return status; }); + if (optVmDef.isEmpty()) { + return; + } + var vmDef = optVmDef.get(); + + // Check if access is possible + if (event.loginUser() + ? !vmDef.conditionStatus("Booted").orElse(false) + : !vmDef.conditionStatus("Running").orElse(false)) { + return; + } // Look for secret ListOptions options = new ListOptions(); options.setLabelSelector("app.kubernetes.io/name=" + APP_NAME + "," + "app.kubernetes.io/component=" + COMP_DISPLAY_SECRET + "," - + "app.kubernetes.io/instance=" - + event.vmDefinition().metadata().getName()); - var stubs = K8sV1SecretStub.list(client(), - event.vmDefinition().namespace(), options); + + "app.kubernetes.io/instance=" + vmDef.name()); + var stubs = K8sV1SecretStub.list(client(), vmDef.namespace(), options); if (stubs.isEmpty()) { // No secret means no password for this VM wanted + event.setResult(null); return; } var stub = stubs.iterator().next(); // Check validity - var model = stub.model().get(); + var secret = stub.model().get(); @SuppressWarnings("PMD.StringInstantiation") - var expiry = Optional.ofNullable(model.getData() + var expiry = Optional.ofNullable(secret.getData() .get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null); - if (model.getData().get(DATA_DISPLAY_PASSWORD) != null + if (secret.getData().get(DATA_DISPLAY_PASSWORD) != null && stillValid(expiry)) { // Fixed secret, don't touch event.setResult( - new String(model.getData().get(DATA_DISPLAY_PASSWORD))); + new String(secret.getData().get(DATA_DISPLAY_PASSWORD))); return; } updatePassword(stub, event); } @SuppressWarnings("PMD.StringInstantiation") - private void updatePassword(K8sV1SecretStub stub, GetDisplayPassword event) + private void updatePassword(K8sV1SecretStub stub, PrepareConsole event) throws ApiException { SecureRandom random = null; try { @@ -242,9 +252,9 @@ public class DisplaySecretMonitor var pending = new PendingGet(event, event.vmDefinition().displayPasswordSerial().orElse(0L) + 1, new CompletionLock(event, 1500)); - pendingGets.add(pending); + pendingPrepares.add(pending); Event.onCompletion(event, e -> { - pendingGets.remove(pending); + pendingPrepares.remove(pending); }); // Update, will (eventually) trigger confirmation @@ -273,9 +283,9 @@ public class DisplaySecretMonitor @Handler @SuppressWarnings("PMD.AvoidSynchronizedStatement") public void onVmDefChanged(VmDefChanged event, Channel channel) { - synchronized (pendingGets) { + synchronized (pendingPrepares) { String vmName = event.vmDefinition().name(); - for (var pending : pendingGets) { + for (var pending : pendingPrepares) { if (pending.event.vmDefinition().name().equals(vmName) && event.vmDefinition().displayPasswordSerial() .map(s -> s >= pending.expectedSerial).orElse(false)) { @@ -293,7 +303,7 @@ public class DisplaySecretMonitor */ @SuppressWarnings("PMD.DataClass") private static class PendingGet { - public final GetDisplayPassword event; + public final PrepareConsole event; public final long expectedSerial; public final CompletionLock lock; @@ -303,7 +313,7 @@ public class DisplaySecretMonitor * @param event the event * @param expectedSerial the expected serial */ - public PendingGet(GetDisplayPassword event, long expectedSerial, + public PendingGet(PrepareConsole event, long expectedSerial, CompletionLock lock) { super(); this.event = event; diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java index e283504..3b28d1c 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/VmAccess.java @@ -49,11 +49,11 @@ import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.common.VmDefinition.Permission; import org.jdrupes.vmoperator.common.VmPool; import org.jdrupes.vmoperator.manager.events.AssignVm; -import org.jdrupes.vmoperator.manager.events.GetDisplayPassword; import org.jdrupes.vmoperator.manager.events.GetPools; import org.jdrupes.vmoperator.manager.events.GetVms; import org.jdrupes.vmoperator.manager.events.GetVms.VmData; import org.jdrupes.vmoperator.manager.events.ModifyVm; +import org.jdrupes.vmoperator.manager.events.PrepareConsole; import org.jdrupes.vmoperator.manager.events.ResetVm; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; @@ -808,18 +808,23 @@ public class VmAccess extends FreeMarkerConlet { Map.of("autoClose", 5_000, "type", "Warning"))); return; } - var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef, user), - e -> { - vmDef.extra() - .map(xtra -> xtra.connectionFile(e.password().orElse(null), - preferredIpVersion, deleteConnectionFile)) - .ifPresent( - cf -> channel.respond(new NotifyConletView(type(), - model.getConletId(), "openConsole", cf))); - }); + var pwQuery = Event.onCompletion(new PrepareConsole(vmDef, user, + model.mode() == ResourceModel.Mode.POOL), + e -> gotPassword(channel, model, vmDef, e)); fire(pwQuery, vmChannel); } + private void gotPassword(ConsoleConnection channel, ResourceModel model, + VmDefinition vmDef, PrepareConsole event) { + if (!event.passwordAvailable()) { + return; + } + vmDef.extra().map(xtra -> xtra.connectionFile(event.password(), + preferredIpVersion, deleteConnectionFile)) + .ifPresent(cf -> channel.respond(new NotifyConletView(type(), + model.getConletId(), "openConsole", cf))); + } + @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", "PMD.UseLocaleWithCaseConversions" }) private void selectResource(NotifyConletModel event, diff --git a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts index ec21fb5..31408cb 100644 --- a/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts +++ b/org.jdrupes.vmoperator.vmaccess/src/org/jdrupes/vmoperator/vmaccess/browser/VmAccess-functions.ts @@ -73,7 +73,9 @@ window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement, const configured = computed(() => previewApi.vmDefinition.spec); const busy = computed(() => previewApi.vmDefinition.spec && (previewApi.vmDefinition.spec.vm.state === 'Running' - && !previewApi.vmDefinition.running + && (previewApi.poolName + ? !previewApi.vmDefinition.booted + : !previewApi.vmDefinition.running) || previewApi.vmDefinition.spec.vm.state === 'Stopped' && previewApi.vmDefinition.running)); const startable = computed(() => previewApi.vmDefinition.spec @@ -85,6 +87,7 @@ window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement, previewApi.vmDefinition.spec.vm.state !== 'Stopped' && previewApi.vmDefinition.running); const running = computed(() => previewApi.vmDefinition.running); + const booted = computed(() => previewApi.vmDefinition.booted); const inUse = computed(() => previewApi.vmDefinition.usedBy != ''); const permissions = computed(() => previewApi.permissions); const osicon = computed(() => { @@ -120,8 +123,8 @@ window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement, }; return { localize, resourceBase, vmAction, poolName, vmName, - configured, busy, startable, stoppable, running, inUse, - permissions, osicon }; + configured, busy, startable, stoppable, running, booted, + inUse, permissions, osicon }; }, template: `
{{ vmName }}
@@ -129,7 +132,8 @@ window.orgJDrupesVmOperatorVmAccess.initPreview = (previewDom: HTMLElement, -
{ if (condition.type === "Running") { vmDefinition.running = condition.status === "True"; vmDefinition.runningConditionSince = new Date(condition.lastTransitionTime); - break; + } else if (condition.type === "Booted") { + vmDefinition.booted = condition.status === "True"; + vmDefinition.bootedConditionSince + = new Date(condition.lastTransitionTime); } - } + }) } else { vmDefinition = {}; } diff --git a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java index 4cc63fa..10b4f48 100644 --- a/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java +++ b/org.jdrupes.vmoperator.vmmgmt/src/org/jdrupes/vmoperator/vmmgmt/VmMgmt.java @@ -43,8 +43,8 @@ import org.jdrupes.vmoperator.common.VmDefinition; import org.jdrupes.vmoperator.common.VmDefinition.Permission; import org.jdrupes.vmoperator.common.VmExtraData; import org.jdrupes.vmoperator.manager.events.ChannelTracker; -import org.jdrupes.vmoperator.manager.events.GetDisplayPassword; import org.jdrupes.vmoperator.manager.events.ModifyVm; +import org.jdrupes.vmoperator.manager.events.PrepareConsole; import org.jdrupes.vmoperator.manager.events.ResetVm; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; @@ -483,17 +483,22 @@ public class VmMgmt extends FreeMarkerConlet { Map.of("autoClose", 5_000, "type", "Warning"))); return; } - var pwQuery = Event.onCompletion(new GetDisplayPassword(vmDef, user), - e -> { - vmDef.extra().map(xtra -> xtra.connectionFile( - e.password().orElse(null), preferredIpVersion, - deleteConnectionFile)).ifPresent( - cf -> channel.respond(new NotifyConletView(type(), - model.getConletId(), "openConsole", cf))); - }); + var pwQuery = Event.onCompletion(new PrepareConsole(vmDef, user), + e -> gotPassword(channel, model, vmDef, e)); fire(pwQuery, vmChannel); } + private void gotPassword(ConsoleConnection channel, VmsModel model, + VmDefinition vmDef, PrepareConsole event) { + if (!event.passwordAvailable()) { + return; + } + vmDef.extra().map(xtra -> xtra.connectionFile(event.password(), + preferredIpVersion, deleteConnectionFile)).ifPresent( + cf -> channel.respond(new NotifyConletView(type(), + model.getConletId(), "openConsole", cf))); + } + @Override protected boolean doSetLocale(SetLocale event, ConsoleConnection channel, String conletId) throws Exception { From e29135282848de191f1075d35e5cefe64bb25fb0 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Fri, 21 Feb 2025 20:54:27 +0100 Subject: [PATCH 182/342] Prepare usage of guest os command. --- .../runner/qemu/GuestAgentClient.java | 39 ++++++++++++++++++- .../vmoperator/runner/qemu/Runner.java | 9 ++++- .../templates/Standard-VM-latest.ftl.yaml | 4 ++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java index f3928f5..afe3d26 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java @@ -20,6 +20,7 @@ package org.jdrupes.vmoperator.runner.qemu; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; import java.io.Writer; @@ -28,6 +29,8 @@ import java.net.UnixDomainSocketAddress; import java.nio.file.Files; import java.nio.file.Path; import java.util.LinkedList; +import java.util.List; +import java.util.Map; import java.util.Queue; import java.util.logging.Level; import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand; @@ -65,6 +68,8 @@ public class GuestAgentClient extends Component { private EventPipeline rep; private Path socketPath; + private List> guestAgentCmds; + private String guestAgentCmd; private SocketIOChannel gaChannel; private final Queue executing = new LinkedList<>(); @@ -72,6 +77,7 @@ public class GuestAgentClient extends Component { * Instantiates a new guest agent client. * * @param componentChannel the component channel + * @param guestAgentCmds * @throws IOException Signals that an I/O exception has occurred. */ @SuppressWarnings({ "PMD.AssignmentToNonFinalStatic", @@ -87,10 +93,20 @@ public class GuestAgentClient extends Component { * forwarded from the {@link Runner} instead. * * @param socketPath the socket path + * @param guestAgentCmds * @param powerdownTimeout */ - /* default */ void configure(Path socketPath) { + @SuppressWarnings("PMD.EmptyCatchBlock") + /* default */ void configure(Path socketPath, ArrayNode guestAgentCmds) { this.socketPath = socketPath; + try { + this.guestAgentCmds = mapper.convertValue(guestAgentCmds, + mapper.constructType(getClass() + .getDeclaredField("guestAgentCmds").getGenericType())); + } catch (IllegalArgumentException | NoSuchFieldException + | SecurityException e) { + // Cannot happen + } } /** @@ -193,7 +209,7 @@ public class GuestAgentClient extends Component { () -> String.format("(Previous \"guest agent(in)\" is " + "result from executing %s)", executed)); if (executed instanceof QmpGuestGetOsinfo) { - rep.fire(new OsinfoEvent(response.get("return"))); + processOsInfo(response); } } } catch (JsonProcessingException e) { @@ -201,6 +217,25 @@ public class GuestAgentClient extends Component { } } + private void processOsInfo(ObjectNode response) { + var osInfo = new OsinfoEvent(response.get("return")); + var osId = osInfo.osinfo().get("id").asText(); + for (var cmdDef : guestAgentCmds) { + if (osId.equals(cmdDef.get("osId")) + || "*".equals(cmdDef.get("osId"))) { + guestAgentCmd = cmdDef.get("executable"); + break; + } + } + if (guestAgentCmd == null) { + logger.warning(() -> "No guest agent command for OS " + osId); + } else { + logger.fine(() -> "Guest agent command for OS " + osId + + " is " + guestAgentCmd); + } + rep.fire(osInfo); + } + /** * On closed. * 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 b258e1a..e0cd837 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 @@ -23,6 +23,7 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; import freemarker.core.ParseException; @@ -197,6 +198,7 @@ public class Runner extends Component { private static final String QEMU = "qemu"; private static final String SWTPM = "swtpm"; private static final String CLOUD_INIT_IMG = "cloudInitImg"; + private static final String GUEST_AGENT_CMDS = "guestAgentCmds"; private static final String TEMPLATE_DIR = "/opt/" + APP_NAME.replace("-", "") + "/templates"; private static final String DEFAULT_TEMPLATE @@ -348,11 +350,16 @@ public class Runner extends Component { .map(d -> new CommandDefinition(CLOUD_INIT_IMG, d)) .orElse(null); logger.finest(() -> cloudInitImgDefinition.toString()); + var guestAgentCmds = (ArrayNode) tplData.get(GUEST_AGENT_CMDS); + if (guestAgentCmds != null) { + logger.finest( + () -> "GuestAgentCmds: " + guestAgentCmds.toString()); + } // Forward some values to child components qemuMonitor.configure(config.monitorSocket, config.vm.powerdownTimeout); - guestAgentClient.configure(config.guestAgentSocket); + guestAgentClient.configure(config.guestAgentSocket, guestAgentCmds); } catch (IllegalArgumentException | IOException | TemplateException e) { logger.log(Level.SEVERE, e, () -> "Invalid configuration: " + e.getMessage()); diff --git a/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml b/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml index e2610ba..3eacfa3 100644 --- a/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml +++ b/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml @@ -233,3 +233,7 @@ + +"guestAgentCmds": + - "osId": "*" + "executable": "/usr/local/libexec/vm-operator-cmd" From 81b128e4a3461039abfde053ed7a32e5a391b811 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Feb 2025 21:24:58 +0100 Subject: [PATCH 183/342] Clarify responsibilities of display secret monitor and reconciler. --- .../manager/DisplaySecretMonitor.java | 210 +--------------- .../manager/DisplaySecretReconciler.java | 224 +++++++++++++++++- .../vmoperator/manager/Reconciler.java | 5 +- webpages/vm-operator/upgrading.md | 24 +- webpages/vm-operator/user-gui.md | 12 +- 5 files changed, 252 insertions(+), 223 deletions(-) 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 152f91e..99c8a11 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 @@ -1,6 +1,6 @@ /* * VM-Operator - * Copyright (C) 2024 Michael N. Lipp + * Copyright (C) 2025 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 @@ -18,8 +18,6 @@ package org.jdrupes.vmoperator.manager; -import com.google.gson.JsonObject; -import io.kubernetes.client.apimachinery.GroupVersionKind; import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.V1Secret; @@ -28,52 +26,26 @@ import io.kubernetes.client.util.Watch.Response; import io.kubernetes.client.util.generic.options.ListOptions; import io.kubernetes.client.util.generic.options.PatchOptions; import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.time.Instant; -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; -import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; -import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import static org.jdrupes.vmoperator.common.Constants.VM_OP_NAME; import org.jdrupes.vmoperator.common.K8sClient; import org.jdrupes.vmoperator.common.K8sV1PodStub; import org.jdrupes.vmoperator.common.K8sV1SecretStub; -import org.jdrupes.vmoperator.common.VmDefinitionStub; import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET; -import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_PASSWORD; -import static org.jdrupes.vmoperator.manager.Constants.DATA_PASSWORD_EXPIRY; import org.jdrupes.vmoperator.manager.events.ChannelDictionary; -import org.jdrupes.vmoperator.manager.events.PrepareConsole; import org.jdrupes.vmoperator.manager.events.VmChannel; -import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jgrapes.core.Channel; -import org.jgrapes.core.CompletionLock; -import org.jgrapes.core.Event; -import org.jgrapes.core.annotation.Handler; -import org.jgrapes.util.events.ConfigurationUpdate; -import org.jose4j.base64url.Base64; /** - * Watches for changes of display secrets. The component supports the - * following configuration properties: - * - * * `passwordValidity`: the validity of the random password in seconds. - * Used to calculate the password expiry time in the generated secret. + * Watches for changes of display secrets. Updates an artifical attribute + * of the pod running the VM in response to force an update of the files + * in the pod that reflect the information from the secret. */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.TooManyStaticImports" }) public class DisplaySecretMonitor extends AbstractMonitor { - private int passwordValidity = 10; - private final List pendingPrepares - = Collections.synchronizedList(new LinkedList<>()); private final ChannelDictionary channelDictionary; /** @@ -93,27 +65,6 @@ public class DisplaySecretMonitor options(options); } - /** - * On configuration update. - * - * @param event the event - */ - @Handler - @Override - public void onConfigurationUpdate(ConfigurationUpdate event) { - super.onConfigurationUpdate(event); - event.structured(componentPath()).ifPresent(c -> { - try { - if (c.containsKey("passwordValidity")) { - passwordValidity = Integer - .parseInt((String) c.get("passwordValidity")); - } - } catch (ClassCastException e) { - logger.config("Malformed configuration: " + e.getMessage()); - } - }); - } - @Override protected void prepareMonitoring() throws IOException, ApiException { client(new K8sClient()); @@ -168,157 +119,4 @@ public class DisplaySecretMonitor + "\"}]"), patchOpts); } - - /** - * On get display secrets. - * - * @param event the event - * @param channel the channel - * @throws ApiException the api exception - */ - @Handler - @SuppressWarnings("PMD.StringInstantiation") - public void onPrepareConsole(PrepareConsole event, VmChannel channel) - throws ApiException { - // Update console user in status - var vmStub = VmDefinitionStub.get(client(), - new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), - event.vmDefinition().namespace(), event.vmDefinition().name()); - var optVmDef = vmStub.updateStatus(from -> { - JsonObject status = from.statusJson(); - status.addProperty("consoleUser", event.user()); - return status; - }); - if (optVmDef.isEmpty()) { - return; - } - var vmDef = optVmDef.get(); - - // Check if access is possible - if (event.loginUser() - ? !vmDef.conditionStatus("Booted").orElse(false) - : !vmDef.conditionStatus("Running").orElse(false)) { - return; - } - - // Look for secret - ListOptions options = new ListOptions(); - options.setLabelSelector("app.kubernetes.io/name=" + APP_NAME + "," - + "app.kubernetes.io/component=" + COMP_DISPLAY_SECRET + "," - + "app.kubernetes.io/instance=" + vmDef.name()); - var stubs = K8sV1SecretStub.list(client(), vmDef.namespace(), options); - if (stubs.isEmpty()) { - // No secret means no password for this VM wanted - event.setResult(null); - return; - } - var stub = stubs.iterator().next(); - - // Check validity - var secret = stub.model().get(); - @SuppressWarnings("PMD.StringInstantiation") - var expiry = Optional.ofNullable(secret.getData() - .get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null); - if (secret.getData().get(DATA_DISPLAY_PASSWORD) != null - && stillValid(expiry)) { - // Fixed secret, don't touch - event.setResult( - new String(secret.getData().get(DATA_DISPLAY_PASSWORD))); - return; - } - updatePassword(stub, event); - } - - @SuppressWarnings("PMD.StringInstantiation") - private void updatePassword(K8sV1SecretStub stub, PrepareConsole event) - throws ApiException { - SecureRandom random = null; - try { - random = SecureRandom.getInstanceStrong(); - } catch (NoSuchAlgorithmException e) { // NOPMD - // "Every implementation of the Java platform is required - // to support at least one strong SecureRandom implementation." - } - byte[] bytes = new byte[16]; - random.nextBytes(bytes); - var password = Base64.encode(bytes); - var model = stub.model().get(); - model.setStringData(Map.of(DATA_DISPLAY_PASSWORD, password, - DATA_PASSWORD_EXPIRY, - Long.toString(Instant.now().getEpochSecond() + passwordValidity))); - event.setResult(password); - - // Prepare wait for confirmation (by VM status change) - var pending = new PendingGet(event, - event.vmDefinition().displayPasswordSerial().orElse(0L) + 1, - new CompletionLock(event, 1500)); - pendingPrepares.add(pending); - Event.onCompletion(event, e -> { - pendingPrepares.remove(pending); - }); - - // Update, will (eventually) trigger confirmation - stub.update(model).getObject(); - } - - private boolean stillValid(String expiry) { - if (expiry == null || "never".equals(expiry)) { - return true; - } - @SuppressWarnings({ "PMD.CloseResource", "resource" }) - var scanner = new Scanner(expiry); - if (!scanner.hasNextLong()) { - return false; - } - long expTime = scanner.nextLong(); - return expTime > Instant.now().getEpochSecond() + passwordValidity; - } - - /** - * On vm def changed. - * - * @param event the event - * @param channel the channel - */ - @Handler - @SuppressWarnings("PMD.AvoidSynchronizedStatement") - public void onVmDefChanged(VmDefChanged event, Channel channel) { - synchronized (pendingPrepares) { - String vmName = event.vmDefinition().name(); - for (var pending : pendingPrepares) { - if (pending.event.vmDefinition().name().equals(vmName) - && event.vmDefinition().displayPasswordSerial() - .map(s -> s >= pending.expectedSerial).orElse(false)) { - pending.lock.remove(); - // pending will be removed from pendingGest by - // waiting thread, see updatePassword - continue; - } - } - } - } - - /** - * The Class PendingGet. - */ - @SuppressWarnings("PMD.DataClass") - private static class PendingGet { - public final PrepareConsole event; - public final long expectedSerial; - public final CompletionLock lock; - - /** - * Instantiates a new pending get. - * - * @param event the event - * @param expectedSerial the expected serial - */ - public PendingGet(PrepareConsole event, long expectedSerial, - CompletionLock lock) { - super(); - this.event = event; - this.expectedSerial = expectedSerial; - this.lock = lock; - } - } } 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 dcae3a3..a281b8e 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 @@ -1,6 +1,6 @@ /* * VM-Operator - * Copyright (C) 2023 Michael N. Lipp + * Copyright (C) 2025 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 @@ -18,7 +18,9 @@ package org.jdrupes.vmoperator.manager; +import com.google.gson.JsonObject; import freemarker.template.TemplateException; +import io.kubernetes.client.apimachinery.GroupVersionKind; import io.kubernetes.client.openapi.ApiException; import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.openapi.models.V1Secret; @@ -26,25 +28,83 @@ import io.kubernetes.client.util.generic.options.ListOptions; import java.io.IOException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.time.Instant; +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.Logger; +import static org.jdrupes.vmoperator.common.Constants.APP_NAME; +import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; +import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import org.jdrupes.vmoperator.common.K8sV1SecretStub; -import static org.jdrupes.vmoperator.manager.Constants.APP_NAME; +import org.jdrupes.vmoperator.common.VmDefinitionStub; import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET; import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_PASSWORD; import static org.jdrupes.vmoperator.manager.Constants.DATA_PASSWORD_EXPIRY; +import org.jdrupes.vmoperator.manager.events.PrepareConsole; import org.jdrupes.vmoperator.manager.events.VmChannel; import org.jdrupes.vmoperator.manager.events.VmDefChanged; import org.jdrupes.vmoperator.util.DataPath; +import org.jgrapes.core.Channel; +import org.jgrapes.core.CompletionLock; +import org.jgrapes.core.Component; +import org.jgrapes.core.Event; +import org.jgrapes.core.annotation.Handler; +import org.jgrapes.util.events.ConfigurationUpdate; import org.jose4j.base64url.Base64; /** - * Delegee for reconciling the display secret + * The properties of the display secret do not only depend on the + * VM definition, but also on events that occur during runtime. + * The reconciler for the display secret is therefore a separate + * component. + * + * The reconciler supports the following configuration properties: + * + * * `passwordValidity`: the validity of the random password in seconds. + * Used to calculate the password expiry time in the generated secret. */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.TooManyStaticImports" }) -/* default */ class DisplaySecretReconciler { +public class DisplaySecretReconciler extends Component { protected final Logger logger = Logger.getLogger(getClass().getName()); + private int passwordValidity = 10; + private final List pendingPrepares + = Collections.synchronizedList(new LinkedList<>()); + + /** + * On configuration update. + * + * @param event the event + */ + @Handler + public void onConfigurationUpdate(ConfigurationUpdate event) { + event.structured(componentPath()) + // for backward compatibility + .or(() -> { + var oldConfig = event + .structured("/Manager/Controller/DisplaySecretMonitor"); + if (oldConfig.isPresent()) { + logger.warning(() -> "Using configuration with old " + + "path '/Manager/Controller/DisplaySecretMonitor' " + + "for `passwordValidity`, please update " + + "the configuration."); + } + return oldConfig; + }).ifPresent(c -> { + try { + if (c.containsKey("passwordValidity")) { + passwordValidity = Integer + .parseInt((String) c.get("passwordValidity")); + } + } catch (ClassCastException e) { + logger.config("Malformed configuration: " + e.getMessage()); + } + }); + } /** * Reconcile. If the configuration prevents generating a secret @@ -104,4 +164,160 @@ import org.jose4j.base64url.Base64; K8sV1SecretStub.create(channel.client(), secret); } + /** + * Prepares access to the console for the user from the event. + * Generates a new password and sends it to the runner. + * Requests the VM (via the runner) to login the user if specified + * in the event. + * + * @param event the event + * @param channel the channel + * @throws ApiException the api exception + */ + @Handler + @SuppressWarnings("PMD.StringInstantiation") + public void onPrepareConsole(PrepareConsole event, VmChannel channel) + throws ApiException { + // Update console user in status + var vmStub = VmDefinitionStub.get(channel.client(), + new GroupVersionKind(VM_OP_GROUP, "", VM_OP_KIND_VM), + event.vmDefinition().namespace(), event.vmDefinition().name()); + var optVmDef = vmStub.updateStatus(from -> { + JsonObject status = from.statusJson(); + status.addProperty("consoleUser", event.user()); + return status; + }); + if (optVmDef.isEmpty()) { + return; + } + var vmDef = optVmDef.get(); + + // Check if access is possible + if (event.loginUser() + ? !vmDef.conditionStatus("Booted").orElse(false) + : !vmDef.conditionStatus("Running").orElse(false)) { + return; + } + + // Look for secret + ListOptions options = new ListOptions(); + options.setLabelSelector("app.kubernetes.io/name=" + APP_NAME + "," + + "app.kubernetes.io/component=" + COMP_DISPLAY_SECRET + "," + + "app.kubernetes.io/instance=" + vmDef.name()); + var stubs = K8sV1SecretStub.list(channel.client(), vmDef.namespace(), + options); + if (stubs.isEmpty()) { + // No secret means no password for this VM wanted + event.setResult(null); + return; + } + var stub = stubs.iterator().next(); + + // Check validity + var secret = stub.model().get(); + @SuppressWarnings("PMD.StringInstantiation") + var expiry = Optional.ofNullable(secret.getData() + .get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null); + if (secret.getData().get(DATA_DISPLAY_PASSWORD) != null + && stillValid(expiry)) { + // Fixed secret, don't touch + event.setResult( + new String(secret.getData().get(DATA_DISPLAY_PASSWORD))); + return; + } + updatePassword(stub, event); + } + + @SuppressWarnings("PMD.StringInstantiation") + private void updatePassword(K8sV1SecretStub stub, PrepareConsole event) + throws ApiException { + SecureRandom random = null; + try { + random = SecureRandom.getInstanceStrong(); + } catch (NoSuchAlgorithmException e) { // NOPMD + // "Every implementation of the Java platform is required + // to support at least one strong SecureRandom implementation." + } + byte[] bytes = new byte[16]; + random.nextBytes(bytes); + var password = Base64.encode(bytes); + var model = stub.model().get(); + model.setStringData(Map.of(DATA_DISPLAY_PASSWORD, password, + DATA_PASSWORD_EXPIRY, + Long.toString(Instant.now().getEpochSecond() + passwordValidity))); + event.setResult(password); + + // Prepare wait for confirmation (by VM status change) + var pending = new PendingGet(event, + event.vmDefinition().displayPasswordSerial().orElse(0L) + 1, + new CompletionLock(event, 1500)); + pendingPrepares.add(pending); + Event.onCompletion(event, e -> { + pendingPrepares.remove(pending); + }); + + // Update, will (eventually) trigger confirmation + stub.update(model).getObject(); + } + + private boolean stillValid(String expiry) { + if (expiry == null || "never".equals(expiry)) { + return true; + } + @SuppressWarnings({ "PMD.CloseResource", "resource" }) + var scanner = new Scanner(expiry); + if (!scanner.hasNextLong()) { + return false; + } + long expTime = scanner.nextLong(); + return expTime > Instant.now().getEpochSecond() + passwordValidity; + } + + /** + * On vm def changed. + * + * @param event the event + * @param channel the channel + */ + @Handler + @SuppressWarnings("PMD.AvoidSynchronizedStatement") + public void onVmDefChanged(VmDefChanged event, Channel channel) { + synchronized (pendingPrepares) { + String vmName = event.vmDefinition().name(); + for (var pending : pendingPrepares) { + if (pending.event.vmDefinition().name().equals(vmName) + && event.vmDefinition().displayPasswordSerial() + .map(s -> s >= pending.expectedSerial).orElse(false)) { + pending.lock.remove(); + // pending will be removed from pendingGest by + // waiting thread, see updatePassword + continue; + } + } + } + } + + /** + * The Class PendingGet. + */ + @SuppressWarnings("PMD.DataClass") + private static class PendingGet { + public final PrepareConsole event; + public final long expectedSerial; + public final CompletionLock lock; + + /** + * Instantiates a new pending get. + * + * @param event the event + * @param expectedSerial the expected serial + */ + public PendingGet(PrepareConsole event, long expectedSerial, + CompletionLock lock) { + super(); + this.event = event; + this.expectedSerial = expectedSerial; + this.lock = lock; + } + } } 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 7dbb410..7969d46 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 @@ -138,6 +138,8 @@ import org.jgrapes.util.events.ConfigurationUpdate; * properties to be used by the runners managed by the controller. * This property is a string that holds the content of * a logging.properties file. + * + * @see org.jdrupes.vmoperator.manager.DisplaySecretReconciler */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.AvoidDuplicateLiterals" }) @@ -163,6 +165,7 @@ public class Reconciler extends Component { * * @param componentChannel the component channel */ + @SuppressWarnings("PMD.ConstructorCallsOverridableMethod") public Reconciler(Channel componentChannel) { super(componentChannel); @@ -177,7 +180,7 @@ public class Reconciler extends Component { fmConfig.setClassForTemplateLoading(Reconciler.class, ""); cmReconciler = new ConfigMapReconciler(fmConfig); - dsReconciler = new DisplaySecretReconciler(); + dsReconciler = attach(new DisplaySecretReconciler()); stsReconciler = new StatefulSetReconciler(fmConfig); pvcReconciler = new PvcReconciler(fmConfig); podReconciler = new PodReconciler(fmConfig); diff --git a/webpages/vm-operator/upgrading.md b/webpages/vm-operator/upgrading.md index 77cacad..2c4253e 100644 --- a/webpages/vm-operator/upgrading.md +++ b/webpages/vm-operator/upgrading.md @@ -7,16 +7,24 @@ layout: vm-operator ## To version 4.0.0 -The VmViewer conlet has been renamed to VmAccess. This affects the -[configuration](https://jdrupes.org/vm-operator/user-gui.html). Configuration information using the old path -"/Manager/GuiHttpServer/ConsoleWeblet/WebConsole/ComponentCollector/VmViewer" -is still accepted for backward compatibility, but should be updated. + * The VmViewer conlet has been renamed to VmAccess. This affects the + [configuration](https://jdrupes.org/vm-operator/user-gui.html). Configuration + information using the old path + `/Manager/GuiHttpServer/ConsoleWeblet/WebConsole/ComponentCollector/VmViewer` + is still accepted for backward compatibility until the next major version, + but should be updated. -The change of name also causes conlets added to the overview page by -users to "disappear" from the GUI. They have to be re-added. + The change of name also causes conlets added to the overview page by + users to "disappear" from the GUI. They have to be re-added. -The latter behavior also applies to the VmConlet conlet which has been -renamed to VmMgmt. + The latter behavior also applies to the VmConlet conlet which has been + renamed to VmMgmt. + + * The configuration property `passwordValidity` has been moved from component + `/Manager/Controller/DisplaySecretMonitor` to + `/Manager/Controller/Reconciler/DisplaySecretReconciler`. The old path is + still accepted for backward compatibility until the next major version, + but should be updated. ## To version 3.4.0 diff --git a/webpages/vm-operator/user-gui.md b/webpages/vm-operator/user-gui.md index 0439db2..bc0b93e 100644 --- a/webpages/vm-operator/user-gui.md +++ b/webpages/vm-operator/user-gui.md @@ -127,16 +127,20 @@ of 16 (strong) random bytes (128 random bits). It is valid for 10 seconds only. This may be challenging on a slower computer or if users may not enable automatic open for connection files in the browser. The validity can therefore be adjusted in the -configuration. +configuration.[^oldPath] ```yaml "/Manager": "/Controller": - "/DisplaySecretMonitor": - # Validity of generated password in seconds - passwordValidity: 10 + "/Reconciler": + "/DisplaySecretReconciler": + # Validity of generated password in seconds + passwordValidity: 10 ``` +[^oldPath]: Before version 4.0, the path for `passwordValidity` was + `/Manager/Controller/DisplaySecretMonitor`. + Taking into account that the controller generates a display secret automatically by default, this approach to securing console access should be sufficient in all cases. (Any feedback From 0828d0383520b88a019a433e813010e2bee4fc46 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 22 Feb 2025 21:27:39 +0100 Subject: [PATCH 184/342] Javadoc fixes. --- .../org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java index afe3d26..fba975e 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java @@ -77,7 +77,6 @@ public class GuestAgentClient extends Component { * Instantiates a new guest agent client. * * @param componentChannel the component channel - * @param guestAgentCmds * @throws IOException Signals that an I/O exception has occurred. */ @SuppressWarnings({ "PMD.AssignmentToNonFinalStatic", @@ -93,8 +92,7 @@ public class GuestAgentClient extends Component { * forwarded from the {@link Runner} instead. * * @param socketPath the socket path - * @param guestAgentCmds - * @param powerdownTimeout + * @param guestAgentCmds the guest agent cmds */ @SuppressWarnings("PMD.EmptyCatchBlock") /* default */ void configure(Path socketPath, ArrayNode guestAgentCmds) { From 3012da3e876e1156db5f854a21ac4ebce8d00f8c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 23 Feb 2025 11:14:46 +0100 Subject: [PATCH 185/342] Add login information to display secret. --- .../jdrupes/vmoperator/manager/Constants.java | 7 ++ .../manager/DisplaySecretReconciler.java | 96 ++++++++++++------- .../vmoperator/manager/Reconciler.java | 2 +- 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Constants.java b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Constants.java index 7de839b..f12b512 100644 --- a/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Constants.java +++ b/org.jdrupes.vmoperator.manager/src/org/jdrupes/vmoperator/manager/Constants.java @@ -18,6 +18,7 @@ package org.jdrupes.vmoperator.manager; +// TODO: Auto-generated Javadoc /** * Some constants. */ @@ -33,6 +34,12 @@ public class Constants extends org.jdrupes.vmoperator.common.Constants { /** The Constant DATA_PASSWORD_EXPIRY. */ public static final String DATA_PASSWORD_EXPIRY = "password-expiry"; + /** The Constant DATA_DISPLAY_USER. */ + public static final String DATA_DISPLAY_USER = "display-user"; + + /** The Constant DATA_DISPLAY_LOGIN. */ + public static final String DATA_DISPLAY_LOGIN = "login-user"; + /** The Constant STATE_RUNNING. */ public static final String STATE_RUNNING = "Running"; 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 a281b8e..66bb021 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 @@ -26,6 +26,7 @@ import io.kubernetes.client.openapi.models.V1ObjectMeta; import io.kubernetes.client.openapi.models.V1Secret; import io.kubernetes.client.util.generic.options.ListOptions; import java.io.IOException; +import static java.nio.charset.StandardCharsets.UTF_8; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.time.Instant; @@ -33,16 +34,19 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Scanner; import java.util.logging.Logger; import static org.jdrupes.vmoperator.common.Constants.APP_NAME; +import static org.jdrupes.vmoperator.common.Constants.COMP_DISPLAY_SECRET; import static org.jdrupes.vmoperator.common.Constants.VM_OP_GROUP; import static org.jdrupes.vmoperator.common.Constants.VM_OP_KIND_VM; import org.jdrupes.vmoperator.common.K8sV1SecretStub; import org.jdrupes.vmoperator.common.VmDefinitionStub; -import static org.jdrupes.vmoperator.manager.Constants.COMP_DISPLAY_SECRET; +import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_LOGIN; import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_PASSWORD; +import static org.jdrupes.vmoperator.manager.Constants.DATA_DISPLAY_USER; import static org.jdrupes.vmoperator.manager.Constants.DATA_PASSWORD_EXPIRY; import org.jdrupes.vmoperator.manager.events.PrepareConsole; import org.jdrupes.vmoperator.manager.events.VmChannel; @@ -75,6 +79,15 @@ public class DisplaySecretReconciler extends Component { private final List pendingPrepares = Collections.synchronizedList(new LinkedList<>()); + /** + * Instantiates a new display secret reconciler. + * + * @param componentChannel the component channel + */ + public DisplaySecretReconciler(Channel componentChannel) { + super(componentChannel); + } + /** * On configuration update. * @@ -213,39 +226,13 @@ public class DisplaySecretReconciler extends Component { } var stub = stubs.iterator().next(); - // Check validity + // Get secret and update var secret = stub.model().get(); - @SuppressWarnings("PMD.StringInstantiation") - var expiry = Optional.ofNullable(secret.getData() - .get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null); - if (secret.getData().get(DATA_DISPLAY_PASSWORD) != null - && stillValid(expiry)) { - // Fixed secret, don't touch - event.setResult( - new String(secret.getData().get(DATA_DISPLAY_PASSWORD))); + var updPw = updatePassword(secret, event); + var updUsr = updateUser(secret, event); + if (!updPw && !updUsr) { return; } - updatePassword(stub, event); - } - - @SuppressWarnings("PMD.StringInstantiation") - private void updatePassword(K8sV1SecretStub stub, PrepareConsole event) - throws ApiException { - SecureRandom random = null; - try { - random = SecureRandom.getInstanceStrong(); - } catch (NoSuchAlgorithmException e) { // NOPMD - // "Every implementation of the Java platform is required - // to support at least one strong SecureRandom implementation." - } - byte[] bytes = new byte[16]; - random.nextBytes(bytes); - var password = Base64.encode(bytes); - var model = stub.model().get(); - model.setStringData(Map.of(DATA_DISPLAY_PASSWORD, password, - DATA_PASSWORD_EXPIRY, - Long.toString(Instant.now().getEpochSecond() + passwordValidity))); - event.setResult(password); // Prepare wait for confirmation (by VM status change) var pending = new PendingGet(event, @@ -257,7 +244,52 @@ public class DisplaySecretReconciler extends Component { }); // Update, will (eventually) trigger confirmation - stub.update(model).getObject(); + stub.update(secret).getObject(); + } + + private boolean updateUser(V1Secret secret, PrepareConsole event) { + var curUser = DataPath. get(secret, "data", DATA_DISPLAY_USER) + .map(b -> new String(b, UTF_8)).orElse(null); + var curLogin = DataPath. get(secret, "data", DATA_DISPLAY_LOGIN) + .map(b -> new String(b, UTF_8)).map(Boolean::parseBoolean) + .orElse(null); + if (Objects.equals(curUser, event.user()) && Objects.equals( + curLogin, event.loginUser())) { + return false; + } + secret.getData().put(DATA_DISPLAY_USER, event.user().getBytes(UTF_8)); + secret.getData().put(DATA_DISPLAY_LOGIN, + Boolean.toString(event.loginUser()).getBytes(UTF_8)); + return true; + } + + private boolean updatePassword(V1Secret secret, PrepareConsole event) { + var expiry = Optional.ofNullable(secret.getData() + .get(DATA_PASSWORD_EXPIRY)).map(b -> new String(b)).orElse(null); + if (secret.getData().get(DATA_DISPLAY_PASSWORD) != null + && stillValid(expiry)) { + // Fixed secret, don't touch + event.setResult( + new String(secret.getData().get(DATA_DISPLAY_PASSWORD))); + return false; + } + + // Generate password and set expiry + SecureRandom random = null; + try { + random = SecureRandom.getInstanceStrong(); + } catch (NoSuchAlgorithmException e) { // NOPMD + // "Every implementation of the Java platform is required + // to support at least one strong SecureRandom implementation." + } + byte[] bytes = new byte[16]; + random.nextBytes(bytes); + var password = Base64.encode(bytes); + secret.setStringData(Map.of(DATA_DISPLAY_PASSWORD, password, + DATA_PASSWORD_EXPIRY, + Long.toString(Instant.now().getEpochSecond() + passwordValidity))); + event.setResult(password); + return true; } private boolean stillValid(String expiry) { 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 7969d46..8011e2c 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 @@ -180,7 +180,7 @@ public class Reconciler extends Component { fmConfig.setClassForTemplateLoading(Reconciler.class, ""); cmReconciler = new ConfigMapReconciler(fmConfig); - dsReconciler = attach(new DisplaySecretReconciler()); + dsReconciler = attach(new DisplaySecretReconciler(componentChannel)); stsReconciler = new StatefulSetReconciler(fmConfig); pvcReconciler = new PvcReconciler(fmConfig); podReconciler = new PodReconciler(fmConfig); From 5b8b47f95cb80bc469db18b2be7f166bfc95a5b8 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 23 Feb 2025 11:47:13 +0100 Subject: [PATCH 186/342] Add some metadata to make bing happy. --- dev-example/test-vm.tpl.yaml | 2 +- webpages/vm-operator/admin-gui.md | 4 ++++ webpages/vm-operator/controller.md | 3 +++ webpages/vm-operator/index.md | 7 +++++-- webpages/vm-operator/manager.md | 3 +++ webpages/vm-operator/runner.md | 4 ++++ webpages/vm-operator/upgrading.md | 2 ++ webpages/vm-operator/user-gui.md | 4 ++++ 8 files changed, 26 insertions(+), 3 deletions(-) diff --git a/dev-example/test-vm.tpl.yaml b/dev-example/test-vm.tpl.yaml index 50031bb..260341e 100644 --- a/dev-example/test-vm.tpl.yaml +++ b/dev-example/test-vm.tpl.yaml @@ -14,7 +14,7 @@ spec: # repository: ghcr.io # path: mnlipp/org.jdrupes.vmoperator.runner.qemu-alpine # version: "3.0.0" - source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:testing + source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:feature-auto-login pullPolicy: Always permissions: diff --git a/webpages/vm-operator/admin-gui.md b/webpages/vm-operator/admin-gui.md index 4bfa3d3..4b7f5b2 100644 --- a/webpages/vm-operator/admin-gui.md +++ b/webpages/vm-operator/admin-gui.md @@ -1,5 +1,9 @@ --- title: "VM-Operator: Administrator View — Provides an overview of running VMs" +description: >- + Information about the administrator view of the VM-Operator, which provides + an overview of the defined VMs, their state and resource consumptions and + actions for starting, stopping and accessing the VMs. layout: vm-operator --- diff --git a/webpages/vm-operator/controller.md b/webpages/vm-operator/controller.md index cc6a274..e20263f 100644 --- a/webpages/vm-operator/controller.md +++ b/webpages/vm-operator/controller.md @@ -1,5 +1,8 @@ --- title: "VM-Operator: Controller — Reconciles the VM CRs" +description: >- + Information about the VM Operator's controller component its + configuration options and the CRD used to define VMs. layout: vm-operator --- diff --git a/webpages/vm-operator/index.md b/webpages/vm-operator/index.md index baf8e20..5cd2d58 100644 --- a/webpages/vm-operator/index.md +++ b/webpages/vm-operator/index.md @@ -1,6 +1,9 @@ --- -title: Run VMs on Kubernetes using Qemu/KVM and SPICE -description: A solution for running VMs on Kubernetes with a web interface for admins and users. Focuses on running Qemu/KVM virtual machines and using SPICE as display protocol. +title: "Run VMs on Kubernetes using QEMU/KVM and SPICE" +description: >- + A solution for running VMs on Kubernetes with a web interface for + admins and users. Focuses on running QEMU/KVM virtual machines and + using SPICE as display protocol. layout: vm-operator --- diff --git a/webpages/vm-operator/manager.md b/webpages/vm-operator/manager.md index c1965f1..ee971c1 100644 --- a/webpages/vm-operator/manager.md +++ b/webpages/vm-operator/manager.md @@ -1,5 +1,8 @@ --- title: "VM-Operator: The Manager — Provides the controller and a web user interface" +description: >- + Information about the installation and configuration of the + VM Operator. layout: vm-operator --- diff --git a/webpages/vm-operator/runner.md b/webpages/vm-operator/runner.md index c72793d..a6a744d 100644 --- a/webpages/vm-operator/runner.md +++ b/webpages/vm-operator/runner.md @@ -1,5 +1,9 @@ --- title: "VM-Operator: The Runner — Starts and monitors a VM" +description: >- + Description of the VM Operator's runner component which starts + QEMU and thus the VM, optionally together with a TPM, in a + kubenernetes pod and monitors everything. layout: vm-operator --- diff --git a/webpages/vm-operator/upgrading.md b/webpages/vm-operator/upgrading.md index 77cacad..b987298 100644 --- a/webpages/vm-operator/upgrading.md +++ b/webpages/vm-operator/upgrading.md @@ -1,5 +1,7 @@ --- title: "VM-Operator: Upgrading — Issues to watch out for" +description: >- + Information about issues to watch out for when upgrading the VM-Operator. layout: vm-operator --- diff --git a/webpages/vm-operator/user-gui.md b/webpages/vm-operator/user-gui.md index 0439db2..0d16113 100644 --- a/webpages/vm-operator/user-gui.md +++ b/webpages/vm-operator/user-gui.md @@ -1,5 +1,9 @@ --- title: "VM-Operator: User View — Allows users to manage their own VMs" +description: >- + Information about the user view of the VM-Operator, which allows users + to access and optionally manage the VMs for which they have the + respective permissions. layout: vm-operator --- From 558f4d96c9aee5186d85130d85345712cdaef5f1 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 23 Feb 2025 12:00:27 +0100 Subject: [PATCH 187/342] Add pagefind. --- webpages/_layouts/vm-operator.html | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 30e6407..e779711 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -1,5 +1,5 @@ - + @@ -11,10 +11,31 @@ - {% seo %} + + + + {% seo %}
+
@@ -68,4 +89,4 @@ {% include matomo.html %} - + From f236b376ae27d4c6c8f8a40ad9d8681ef0730c90 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 23 Feb 2025 12:05:55 +0100 Subject: [PATCH 188/342] Back to testing. --- dev-example/test-vm.tpl.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-example/test-vm.tpl.yaml b/dev-example/test-vm.tpl.yaml index 260341e..50031bb 100644 --- a/dev-example/test-vm.tpl.yaml +++ b/dev-example/test-vm.tpl.yaml @@ -14,7 +14,7 @@ spec: # repository: ghcr.io # path: mnlipp/org.jdrupes.vmoperator.runner.qemu-alpine # version: "3.0.0" - source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:feature-auto-login + source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:testing pullPolicy: Always permissions: From e3b5f5a04dcd92cfbf1b34af605cf6f77534c085 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 24 Feb 2025 11:58:13 +0100 Subject: [PATCH 189/342] Refactor QEMU socket connection handling and start vmop agent. --- dev-example/test-vm.tpl.yaml | 2 +- .../runner/qemu/AgentConnector.java | 86 +++++++ .../vmoperator/runner/qemu/Configuration.java | 6 +- .../runner/qemu/GuestAgentClient.java | 200 ++------------- .../vmoperator/runner/qemu/QemuConnector.java | 234 ++++++++++++++++++ .../vmoperator/runner/qemu/QemuMonitor.java | 134 ++-------- .../vmoperator/runner/qemu/Runner.java | 42 +++- .../runner/qemu/VmopAgentClient.java | 48 ++++ .../templates/Standard-VM-latest.ftl.yaml | 11 +- webpages/vm-operator/upgrading.md | 7 + 10 files changed, 451 insertions(+), 319 deletions(-) create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/AgentConnector.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuConnector.java create mode 100644 org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java diff --git a/dev-example/test-vm.tpl.yaml b/dev-example/test-vm.tpl.yaml index 50031bb..260341e 100644 --- a/dev-example/test-vm.tpl.yaml +++ b/dev-example/test-vm.tpl.yaml @@ -14,7 +14,7 @@ spec: # repository: ghcr.io # path: mnlipp/org.jdrupes.vmoperator.runner.qemu-alpine # version: "3.0.0" - source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:testing + source: registry.mnl.de/org/jdrupes/vm-operator/org.jdrupes.vmoperator.runner.qemu-arch:feature-auto-login pullPolicy: Always permissions: diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/AgentConnector.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/AgentConnector.java new file mode 100644 index 0000000..40db84a --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/AgentConnector.java @@ -0,0 +1,86 @@ +/* + * VM-Operator + * Copyright (C) 2025 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; + +import java.io.IOException; +import java.nio.file.Path; +import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent; +import org.jgrapes.core.Channel; +import org.jgrapes.core.annotation.Handler; +import org.jgrapes.util.events.ConfigurationUpdate; + +/** + * A component that handles the communication with an agent + * running in the VM. + * + * If the log level for this class is set to fine, the messages + * exchanged on the socket are logged. + */ +public abstract class AgentConnector extends QemuConnector { + + protected String channelId; + + /** + * Instantiates a new agent connector. + * + * @param componentChannel the component channel + * @throws IOException Signals that an I/O exception has occurred. + */ + public AgentConnector(Channel componentChannel) throws IOException { + super(componentChannel); + } + + /** + * As the initial configuration of this component depends on the + * configuration of the {@link Runner}, it doesn't have a handler + * for the {@link ConfigurationUpdate} event. The values are + * forwarded from the {@link Runner} instead. + * + * @param channelId the channel id + * @param socketPath the socket path + */ + /* default */ void configure(String channelId, Path socketPath) { + super.configure(socketPath); + this.channelId = channelId; + logger.fine(() -> getClass().getSimpleName() + " configured with" + + " channelId=" + channelId); + } + + /** + * When the virtual serial port with the configured channel id has + * been opened call {@link #agentConnected()}. + * + * @param event the event + */ + @Handler + public void onVserportChanged(VserportChangeEvent event) { + if (event.id().equals(channelId) && event.isOpen()) { + agentConnected(); + } + } + + /** + * Called when the agent in the VM opens the connection. The + * default implementation does nothing. + */ + @SuppressWarnings("PMD.EmptyMethodInAbstractClassShouldBeAbstract") + protected void agentConnected() { + // Default is to do nothing. + } +} 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 086f085..20d4c66 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 @@ -39,7 +39,7 @@ import org.jdrupes.vmoperator.util.FsdUtils; /** * The configuration information from the configuration file. */ -@SuppressWarnings("PMD.ExcessivePublicCount") +@SuppressWarnings({ "PMD.ExcessivePublicCount", "PMD.TooManyFields" }) public class Configuration implements Dto { private static final String CI_INSTANCE_ID = "instance-id"; @@ -67,9 +67,6 @@ public class Configuration implements Dto { /** The monitor socket. */ public Path monitorSocket; - /** The guest agent socket socket. */ - public Path guestAgentSocket; - /** The firmware rom. */ public Path firmwareRom; @@ -344,7 +341,6 @@ public class Configuration implements Dto { runtimeDir.toFile().mkdir(); swtpmSocket = runtimeDir.resolve("swtpm-sock"); monitorSocket = runtimeDir.resolve("monitor.sock"); - guestAgentSocket = runtimeDir.resolve("org.qemu.guest_agent.0"); } if (!Files.isDirectory(runtimeDir) || !Files.isWritable(runtimeDir)) { logger.severe(() -> String.format( diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java index fba975e..2e5e059 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java @@ -19,58 +19,26 @@ package org.jdrupes.vmoperator.runner.qemu; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; -import java.io.Writer; -import java.lang.reflect.UndeclaredThrowableException; -import java.net.UnixDomainSocketAddress; -import java.nio.file.Files; -import java.nio.file.Path; import java.util.LinkedList; -import java.util.List; -import java.util.Map; import java.util.Queue; import java.util.logging.Level; import org.jdrupes.vmoperator.runner.qemu.commands.QmpCommand; import org.jdrupes.vmoperator.runner.qemu.commands.QmpGuestGetOsinfo; import org.jdrupes.vmoperator.runner.qemu.events.GuestAgentCommand; import org.jdrupes.vmoperator.runner.qemu.events.OsinfoEvent; -import org.jdrupes.vmoperator.runner.qemu.events.VserportChangeEvent; import org.jgrapes.core.Channel; -import org.jgrapes.core.Component; -import org.jgrapes.core.EventPipeline; import org.jgrapes.core.annotation.Handler; -import org.jgrapes.core.events.Start; -import org.jgrapes.core.events.Stop; -import org.jgrapes.io.events.Closed; -import org.jgrapes.io.events.ConnectError; -import org.jgrapes.io.events.Input; -import org.jgrapes.io.events.OpenSocketConnection; -import org.jgrapes.io.util.ByteBufferWriter; -import org.jgrapes.io.util.LineCollector; -import org.jgrapes.net.SocketIOChannel; -import org.jgrapes.net.events.ClientConnected; -import org.jgrapes.util.events.ConfigurationUpdate; /** - * A component that handles the communication over the guest agent - * socket. + * A component that handles the communication with the guest agent. * * If the log level for this class is set to fine, the messages * exchanged on the monitor socket are logged. */ -@SuppressWarnings("PMD.DataflowAnomalyAnalysis") -public class GuestAgentClient extends Component { +public class GuestAgentClient extends AgentConnector { - private static ObjectMapper mapper = new ObjectMapper(); - - private EventPipeline rep; - private Path socketPath; - private List> guestAgentCmds; - private String guestAgentCmd; - private SocketIOChannel gaChannel; private final Queue executing = new LinkedList<>(); /** @@ -79,135 +47,36 @@ public class GuestAgentClient extends Component { * @param componentChannel the component channel * @throws IOException Signals that an I/O exception has occurred. */ - @SuppressWarnings({ "PMD.AssignmentToNonFinalStatic", - "PMD.ConstructorCallsOverridableMethod" }) public GuestAgentClient(Channel componentChannel) throws IOException { super(componentChannel); } /** - * As the initial configuration of this component depends on the - * configuration of the {@link Runner}, it doesn't have a handler - * for the {@link ConfigurationUpdate} event. The values are - * forwarded from the {@link Runner} instead. - * - * @param socketPath the socket path - * @param guestAgentCmds the guest agent cmds + * When the agent has connected, request the OS information. */ - @SuppressWarnings("PMD.EmptyCatchBlock") - /* default */ void configure(Path socketPath, ArrayNode guestAgentCmds) { - this.socketPath = socketPath; - try { - this.guestAgentCmds = mapper.convertValue(guestAgentCmds, - mapper.constructType(getClass() - .getDeclaredField("guestAgentCmds").getGenericType())); - } catch (IllegalArgumentException | NoSuchFieldException - | SecurityException e) { - // Cannot happen - } + @Override + protected void agentConnected() { + fire(new GuestAgentCommand(new QmpGuestGetOsinfo())); } /** - * Handle the start event. + * Process agent input. * - * @param event the event + * @param line the line * @throws IOException Signals that an I/O exception has occurred. */ - @Handler - public void onStart(Start event) throws IOException { - rep = event.associated(EventPipeline.class).get(); - if (socketPath == null) { - return; - } - Files.deleteIfExists(socketPath); - } - - /** - * When the virtual serial port "channel0" has been opened, - * establish the connection by opening the socket. - * - * @param event the event - */ - @Handler - public void onVserportChanged(VserportChangeEvent event) { - if ("channel0".equals(event.id()) && event.isOpen()) { - fire(new OpenSocketConnection( - UnixDomainSocketAddress.of(socketPath)) - .setAssociated(GuestAgentClient.class, this)); - } - } - - /** - * Check if this is from opening the monitor socket and if true, - * save the socket in the context and associate the channel with - * the context. Then send the initial message to the socket. - * - * @param event the event - * @param channel the channel - */ - @SuppressWarnings("resource") - @Handler - public void onClientConnected(ClientConnected event, - SocketIOChannel channel) { - event.openEvent().associated(GuestAgentClient.class).ifPresent(qm -> { - gaChannel = channel; - channel.setAssociated(GuestAgentClient.class, this); - channel.setAssociated(Writer.class, new ByteBufferWriter( - channel).nativeCharset()); - channel.setAssociated(LineCollector.class, - new LineCollector() - .consumer(line -> { - try { - processGuestAgentInput(line); - } catch (IOException e) { - throw new UndeclaredThrowableException(e); - } - })); - fire(new GuestAgentCommand(new QmpGuestGetOsinfo())); - }); - } - - /** - * Called when a connection attempt fails. - * - * @param event the event - * @param channel the channel - */ - @Handler - public void onConnectError(ConnectError event, SocketIOChannel channel) { - event.event().associated(GuestAgentClient.class).ifPresent(qm -> { - rep.fire(new Stop()); - }); - } - - /** - * Handle data from qemu monitor connection. - * - * @param event the event - * @param channel the channel - */ - @Handler - public void onInput(Input event, SocketIOChannel channel) { - if (channel.associated(GuestAgentClient.class).isEmpty()) { - return; - } - channel.associated(LineCollector.class).ifPresent(collector -> { - collector.feed(event); - }); - } - - private void processGuestAgentInput(String line) - throws IOException { + @Override + protected void processInput(String line) throws IOException { logger.fine(() -> "guest agent(in): " + line); try { var response = mapper.readValue(line, ObjectNode.class); if (response.has("return") || response.has("error")) { QmpCommand executed = executing.poll(); - logger.fine( - () -> String.format("(Previous \"guest agent(in)\" is " - + "result from executing %s)", executed)); + logger.fine(() -> String.format("(Previous \"guest agent(in)\"" + + " is result from executing %s)", executed)); if (executed instanceof QmpGuestGetOsinfo) { - processOsInfo(response); + var osInfo = new OsinfoEvent(response.get("return")); + rep().fire(osInfo); } } } catch (JsonProcessingException e) { @@ -215,48 +84,17 @@ public class GuestAgentClient extends Component { } } - private void processOsInfo(ObjectNode response) { - var osInfo = new OsinfoEvent(response.get("return")); - var osId = osInfo.osinfo().get("id").asText(); - for (var cmdDef : guestAgentCmds) { - if (osId.equals(cmdDef.get("osId")) - || "*".equals(cmdDef.get("osId"))) { - guestAgentCmd = cmdDef.get("executable"); - break; - } - } - if (guestAgentCmd == null) { - logger.warning(() -> "No guest agent command for OS " + osId); - } else { - logger.fine(() -> "Guest agent command for OS " + osId - + " is " + guestAgentCmd); - } - rep.fire(osInfo); - } - - /** - * On closed. - * - * @param event the event - */ - @Handler - @SuppressWarnings({ "PMD.AvoidSynchronizedStatement", - "PMD.AvoidDuplicateLiterals" }) - public void onClosed(Closed event, SocketIOChannel channel) { - channel.associated(QemuMonitor.class).ifPresent(qm -> { - gaChannel = null; - }); - } - /** * On guest agent command. * * @param event the event */ @Handler - @SuppressWarnings({ "PMD.AvoidLiteralsInIfCondition", - "PMD.AvoidSynchronizedStatement" }) + @SuppressWarnings("PMD.AvoidSynchronizedStatement") public void onGuestAgentCommand(GuestAgentCommand event) { + if (qemuChannel() == null) { + return; + } var command = event.command(); logger.fine(() -> "guest agent(out): " + command.toString()); String asText; @@ -268,7 +106,7 @@ public class GuestAgentClient extends Component { return; } synchronized (executing) { - gaChannel.associated(Writer.class).ifPresent(writer -> { + writer().ifPresent(writer -> { try { executing.add(command); writer.append(asText).append('\n').flush(); diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuConnector.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuConnector.java new file mode 100644 index 0000000..143cfc2 --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuConnector.java @@ -0,0 +1,234 @@ +/* + * VM-Operator + * Copyright (C) 2025 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; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.IOException; +import java.io.Writer; +import java.lang.reflect.UndeclaredThrowableException; +import java.net.UnixDomainSocketAddress; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import org.jgrapes.core.Channel; +import org.jgrapes.core.Component; +import org.jgrapes.core.EventPipeline; +import org.jgrapes.core.annotation.Handler; +import org.jgrapes.core.events.Start; +import org.jgrapes.core.events.Stop; +import org.jgrapes.io.events.Closed; +import org.jgrapes.io.events.ConnectError; +import org.jgrapes.io.events.Input; +import org.jgrapes.io.events.OpenSocketConnection; +import org.jgrapes.io.util.ByteBufferWriter; +import org.jgrapes.io.util.LineCollector; +import org.jgrapes.net.SocketIOChannel; +import org.jgrapes.net.events.ClientConnected; +import org.jgrapes.util.events.ConfigurationUpdate; +import org.jgrapes.util.events.FileChanged; +import org.jgrapes.util.events.WatchFile; + +/** + * A component that handles the communication with QEMU over a socket. + * + * If the log level for this class is set to fine, the messages + * exchanged on the socket are logged. + */ +public abstract class QemuConnector extends Component { + + @SuppressWarnings("PMD.FieldNamingConventions") + protected static final ObjectMapper mapper = new ObjectMapper(); + + private EventPipeline rep; + private Path socketPath; + private SocketIOChannel qemuChannel; + + /** + * Instantiates a new QEMU connector. + * + * @param componentChannel the component channel + * @throws IOException Signals that an I/O exception has occurred. + */ + public QemuConnector(Channel componentChannel) throws IOException { + super(componentChannel); + } + + /** + * As the initial configuration of this component depends on the + * configuration of the {@link Runner}, it doesn't have a handler + * for the {@link ConfigurationUpdate} event. The values are + * forwarded from the {@link Runner} instead. + * + * @param socketPath the socket path + */ + /* default */ void configure(Path socketPath) { + this.socketPath = socketPath; + logger.fine(() -> getClass().getSimpleName() + + " configured with socketPath=" + socketPath); + } + + /** + * Note the runner's event processor and delete the socket. + * + * @param event the event + * @throws IOException Signals that an I/O exception has occurred. + */ + @Handler + public void onStart(Start event) throws IOException { + rep = event.associated(EventPipeline.class).get(); + if (socketPath == null) { + return; + } + Files.deleteIfExists(socketPath); + fire(new WatchFile(socketPath)); + } + + /** + * Return the runner's event pipeline. + * + * @return the event pipeline + */ + protected EventPipeline rep() { + return rep; + } + + /** + * Watch for the creation of the swtpm socket and start the + * qemu process if it has been created. + * + * @param event the event + */ + @Handler + public void onFileChanged(FileChanged event) { + if (event.change() == FileChanged.Kind.CREATED + && event.path().equals(socketPath)) { + // qemu running, open socket + fire(new OpenSocketConnection( + UnixDomainSocketAddress.of(socketPath)) + .setAssociated(getClass(), this)); + } + } + + /** + * Check if this is from opening the agent socket and if true, + * save the socket in the context and associate the channel with + * the context. + * + * @param event the event + * @param channel the channel + */ + @SuppressWarnings("resource") + @Handler + public void onClientConnected(ClientConnected event, + SocketIOChannel channel) { + event.openEvent().associated(getClass()).ifPresent(qm -> { + qemuChannel = channel; + channel.setAssociated(getClass(), this); + channel.setAssociated(Writer.class, new ByteBufferWriter( + channel).nativeCharset()); + channel.setAssociated(LineCollector.class, + new LineCollector() + .consumer(line -> { + try { + processInput(line); + } catch (IOException e) { + throw new UndeclaredThrowableException(e); + } + })); + socketConnected(); + }); + } + + /** + * Return the QEMU channel if the connection has been established. + * + * @return the socket IO channel + */ + protected Optional qemuChannel() { + return Optional.ofNullable(qemuChannel); + } + + /** + * Return the {@link Writer} for the connection if the connection + * has been established. + * + * @return the optional + */ + protected Optional writer() { + return qemuChannel().flatMap(c -> c.associated(Writer.class)); + } + + /** + * Called when the connector has been connected to the socket. + */ + @SuppressWarnings("PMD.EmptyMethodInAbstractClassShouldBeAbstract") + protected void socketConnected() { + // Default is to do nothing. + } + + /** + * Called when a connection attempt fails. + * + * @param event the event + * @param channel the channel + */ + @Handler + public void onConnectError(ConnectError event, SocketIOChannel channel) { + event.event().associated(getClass()).ifPresent(qm -> { + rep.fire(new Stop()); + }); + } + + /** + * Handle data from the socket connection. + * + * @param event the event + * @param channel the channel + */ + @Handler + public void onInput(Input event, SocketIOChannel channel) { + if (channel.associated(getClass()).isEmpty()) { + return; + } + channel.associated(LineCollector.class).ifPresent(collector -> { + collector.feed(event); + }); + } + + /** + * Process agent input. + * + * @param line the line + * @throws IOException Signals that an I/O exception has occurred. + */ + protected abstract void processInput(String line) throws IOException; + + /** + * On closed. + * + * @param event the event + * @param channel the channel + */ + @Handler + public void onClosed(Closed event, SocketIOChannel channel) { + channel.associated(getClass()).ifPresent(qm -> { + qemuChannel = null; + }); + } +} diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java index 7cac734..000a3bf 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java @@ -19,13 +19,8 @@ package org.jdrupes.vmoperator.runner.qemu; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.io.IOException; -import java.io.Writer; -import java.lang.reflect.UndeclaredThrowableException; -import java.net.UnixDomainSocketAddress; -import java.nio.file.Files; import java.nio.file.Path; import java.time.Duration; import java.time.Instant; @@ -42,24 +37,13 @@ import org.jdrupes.vmoperator.runner.qemu.events.MonitorReady; import org.jdrupes.vmoperator.runner.qemu.events.MonitorResult; import org.jdrupes.vmoperator.runner.qemu.events.PowerdownEvent; import org.jgrapes.core.Channel; -import org.jgrapes.core.Component; import org.jgrapes.core.Components; import org.jgrapes.core.Components.Timer; -import org.jgrapes.core.EventPipeline; import org.jgrapes.core.annotation.Handler; -import org.jgrapes.core.events.Start; import org.jgrapes.core.events.Stop; import org.jgrapes.io.events.Closed; -import org.jgrapes.io.events.ConnectError; -import org.jgrapes.io.events.Input; -import org.jgrapes.io.events.OpenSocketConnection; -import org.jgrapes.io.util.ByteBufferWriter; -import org.jgrapes.io.util.LineCollector; import org.jgrapes.net.SocketIOChannel; -import org.jgrapes.net.events.ClientConnected; import org.jgrapes.util.events.ConfigurationUpdate; -import org.jgrapes.util.events.FileChanged; -import org.jgrapes.util.events.WatchFile; /** * A component that handles the communication over the Qemu monitor @@ -69,14 +53,9 @@ import org.jgrapes.util.events.WatchFile; * exchanged on the monitor socket are logged. */ @SuppressWarnings("PMD.DataflowAnomalyAnalysis") -public class QemuMonitor extends Component { +public class QemuMonitor extends QemuConnector { - private static ObjectMapper mapper = new ObjectMapper(); - - private EventPipeline rep; - private Path socketPath; private int powerdownTimeout; - private SocketIOChannel monitorChannel; private final Queue executing = new LinkedList<>(); private Instant powerdownStartedAt; private Stop suspendedStop; @@ -84,7 +63,7 @@ public class QemuMonitor extends Component { private boolean powerdownConfirmed; /** - * Instantiates a new qemu monitor. + * Instantiates a new QEMU monitor. * * @param componentChannel the component channel * @param configDir the config dir @@ -111,109 +90,26 @@ public class QemuMonitor extends Component { * @param powerdownTimeout */ /* default */ void configure(Path socketPath, int powerdownTimeout) { - this.socketPath = socketPath; + super.configure(socketPath); this.powerdownTimeout = powerdownTimeout; } /** - * Handle the start event. - * - * @param event the event - * @throws IOException Signals that an I/O exception has occurred. + * When the socket is connected, send the capabilities command. */ - @Handler - public void onStart(Start event) throws IOException { - rep = event.associated(EventPipeline.class).get(); - if (socketPath == null) { - return; - } - Files.deleteIfExists(socketPath); - fire(new WatchFile(socketPath)); + @Override + protected void socketConnected() { + fire(new MonitorCommand(new QmpCapabilities())); } - /** - * Watch for the creation of the swtpm socket and start the - * qemu process if it has been created. - * - * @param event the event - */ - @Handler - public void onFileChanged(FileChanged event) { - if (event.change() == FileChanged.Kind.CREATED - && event.path().equals(socketPath)) { - // qemu running, open socket - fire(new OpenSocketConnection( - UnixDomainSocketAddress.of(socketPath)) - .setAssociated(QemuMonitor.class, this)); - } - } - - /** - * Check if this is from opening the monitor socket and if true, - * save the socket in the context and associate the channel with - * the context. Then send the initial message to the socket. - * - * @param event the event - * @param channel the channel - */ - @SuppressWarnings("resource") - @Handler - public void onClientConnected(ClientConnected event, - SocketIOChannel channel) { - event.openEvent().associated(QemuMonitor.class).ifPresent(qm -> { - monitorChannel = channel; - channel.setAssociated(QemuMonitor.class, this); - channel.setAssociated(Writer.class, new ByteBufferWriter( - channel).nativeCharset()); - channel.setAssociated(LineCollector.class, - new LineCollector() - .consumer(line -> { - try { - processMonitorInput(line); - } catch (IOException e) { - throw new UndeclaredThrowableException(e); - } - })); - fire(new MonitorCommand(new QmpCapabilities())); - }); - } - - /** - * Called when a connection attempt fails. - * - * @param event the event - * @param channel the channel - */ - @Handler - public void onConnectError(ConnectError event, SocketIOChannel channel) { - event.event().associated(QemuMonitor.class).ifPresent(qm -> { - rep.fire(new Stop()); - }); - } - - /** - * Handle data from qemu monitor connection. - * - * @param event the event - * @param channel the channel - */ - @Handler - public void onInput(Input event, SocketIOChannel channel) { - if (channel.associated(QemuMonitor.class).isEmpty()) { - return; - } - channel.associated(LineCollector.class).ifPresent(collector -> { - collector.feed(event); - }); - } - - private void processMonitorInput(String line) + @Override + protected void processInput(String line) throws IOException { logger.fine(() -> "monitor(in): " + line); try { var response = mapper.readValue(line, ObjectNode.class); if (response.has("QMP")) { - rep.fire(new MonitorReady()); + rep().fire(new MonitorReady()); return; } if (response.has("return") || response.has("error")) { @@ -221,11 +117,11 @@ public class QemuMonitor extends Component { logger.fine( () -> String.format("(Previous \"monitor(in)\" is result " + "from executing %s)", executed)); - rep.fire(MonitorResult.from(executed, response)); + rep().fire(MonitorResult.from(executed, response)); return; } if (response.has("event")) { - MonitorEvent.from(response).ifPresent(rep::fire); + MonitorEvent.from(response).ifPresent(rep()::fire); } } catch (JsonProcessingException e) { throw new IOException(e); @@ -241,8 +137,8 @@ public class QemuMonitor extends Component { @SuppressWarnings({ "PMD.AvoidSynchronizedStatement", "PMD.AvoidDuplicateLiterals" }) public void onClosed(Closed event, SocketIOChannel channel) { + super.onClosed(event, channel); channel.associated(QemuMonitor.class).ifPresent(qm -> { - monitorChannel = null; synchronized (this) { if (powerdownTimer != null) { powerdownTimer.cancel(); @@ -275,7 +171,7 @@ public class QemuMonitor extends Component { return; } synchronized (executing) { - monitorChannel.associated(Writer.class).ifPresent(writer -> { + writer().ifPresent(writer -> { try { executing.add(command); writer.append(asText).append('\n').flush(); @@ -295,7 +191,7 @@ public class QemuMonitor extends Component { @Handler(priority = 100) @SuppressWarnings("PMD.AvoidSynchronizedStatement") public void onStop(Stop event) { - if (monitorChannel != null) { + if (qemuChannel() != null) { // We have a connection to Qemu, attempt ACPI shutdown. event.suspendHandling(); suspendedStop = event; 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 e0cd837..0eaabe9 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 @@ -23,7 +23,6 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator; import freemarker.core.ParseException; @@ -198,7 +197,6 @@ public class Runner extends Component { private static final String QEMU = "qemu"; private static final String SWTPM = "swtpm"; private static final String CLOUD_INIT_IMG = "cloudInitImg"; - private static final String GUEST_AGENT_CMDS = "guestAgentCmds"; private static final String TEMPLATE_DIR = "/opt/" + APP_NAME.replace("-", "") + "/templates"; private static final String DEFAULT_TEMPLATE @@ -222,6 +220,7 @@ public class Runner extends Component { private CommandDefinition qemuDefinition; private final QemuMonitor qemuMonitor; private final GuestAgentClient guestAgentClient; + private final VmopAgentClient vmopAgentClient; private Integer resetCounter; private RunState state = RunState.INITIALIZING; @@ -280,6 +279,7 @@ public class Runner extends Component { attach(new SocketConnector(channel())); attach(qemuMonitor = new QemuMonitor(channel(), configDir)); attach(guestAgentClient = new GuestAgentClient(channel())); + attach(vmopAgentClient = new VmopAgentClient(channel())); attach(new StatusUpdater(channel())); attach(new YamlConfigurationStore(channel(), configFile, false)); fire(new WatchFile(configFile.toPath())); @@ -350,16 +350,12 @@ public class Runner extends Component { .map(d -> new CommandDefinition(CLOUD_INIT_IMG, d)) .orElse(null); logger.finest(() -> cloudInitImgDefinition.toString()); - var guestAgentCmds = (ArrayNode) tplData.get(GUEST_AGENT_CMDS); - if (guestAgentCmds != null) { - logger.finest( - () -> "GuestAgentCmds: " + guestAgentCmds.toString()); - } // Forward some values to child components qemuMonitor.configure(config.monitorSocket, config.vm.powerdownTimeout); - guestAgentClient.configure(config.guestAgentSocket, guestAgentCmds); + configureAgentClient(guestAgentClient, "guest-agent-socket"); + configureAgentClient(vmopAgentClient, "vmop-agent-socket"); } catch (IllegalArgumentException | IOException | TemplateException e) { logger.log(Level.SEVERE, e, () -> "Invalid configuration: " + e.getMessage()); @@ -484,6 +480,36 @@ public class Runner extends Component { } } + @SuppressWarnings("PMD.CognitiveComplexity") + private void configureAgentClient(AgentConnector client, String chardev) { + String id = null; + Path path = null; + for (var arg : qemuDefinition.command) { + if (arg.startsWith("virtserialport,") + && arg.contains("chardev=" + chardev)) { + for (var prop : arg.split(",")) { + if (prop.startsWith("id=")) { + id = prop.substring(3); + } + } + } + if (arg.startsWith("socket,") + && arg.contains("id=" + chardev)) { + for (var prop : arg.split(",")) { + if (prop.startsWith("path=")) { + path = Path.of(prop.substring(5)); + } + } + } + } + if (id == null || path == null) { + logger.warning(() -> "Definition of chardev " + chardev + + " missing in runner template."); + return; + } + client.configure(id, path); + } + /** * Handle the started event. * diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java new file mode 100644 index 0000000..a74432b --- /dev/null +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java @@ -0,0 +1,48 @@ +/* + * VM-Operator + * Copyright (C) 2025 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; + +import java.io.IOException; +import org.jgrapes.core.Channel; + +/** + * A component that handles the communication over the vmop agent + * socket. + * + * If the log level for this class is set to fine, the messages + * exchanged on the socket are logged. + */ +public class VmopAgentClient extends AgentConnector { + + /** + * Instantiates a new VM operator agent client. + * + * @param componentChannel the component channel + * @throws IOException Signals that an I/O exception has occurred. + */ + public VmopAgentClient(Channel componentChannel) throws IOException { + super(componentChannel); + } + + @Override + protected void processInput(String line) throws IOException { + // TODO Auto-generated method stub + } + +} diff --git a/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml b/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml index 3eacfa3..c5c0252 100644 --- a/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml +++ b/org.jdrupes.vmoperator.runner.qemu/templates/Standard-VM-latest.ftl.yaml @@ -122,11 +122,16 @@ # Best explanation found: # https://fedoraproject.org/wiki/Features/VirtioSerial - [ "-device", "virtio-serial-pci,id=virtio-serial0" ] - # - Guest agent serial connection. MUST have id "channel0"! + # - Guest agent serial connection. - [ "-device", "virtserialport,id=channel0,name=org.qemu.guest_agent.0,\ chardev=guest-agent-socket" ] - [ "-chardev","socket,id=guest-agent-socket,\ path=${ runtimeDir }/org.qemu.guest_agent.0,server=on,wait=off" ] + # - VM operator agent serial connection. + - [ "-device", "virtserialport,id=channel1,name=org.jdrupes.vmop_agent.0,\ + chardev=vmop-agent-socket" ] + - [ "-chardev","socket,id=vmop-agent-socket,\ + path=${ runtimeDir }/org.jdrupes.vmop_agent.0,server=on,wait=off" ] # * USB Hub and devices (more in SPICE configuration below) # https://qemu-project.gitlab.io/qemu/system/devices/usb.html # https://github.com/qemu/qemu/blob/master/hw/usb/hcd-xhci.c @@ -233,7 +238,3 @@ - -"guestAgentCmds": - - "osId": "*" - "executable": "/usr/local/libexec/vm-operator-cmd" diff --git a/webpages/vm-operator/upgrading.md b/webpages/vm-operator/upgrading.md index 2c4253e..422c32d 100644 --- a/webpages/vm-operator/upgrading.md +++ b/webpages/vm-operator/upgrading.md @@ -26,6 +26,13 @@ layout: vm-operator still accepted for backward compatibility until the next major version, but should be updated. + * The standard [template](./runner.html#stand-alone-configuration) used + to generate the QEMU command has been updated. Unless you have enabled + automatic updates of the template in the VM definition, you have to + update the template manually. If you're using your own template, you + have to add a virtual serial port (see the git history of the standard + template for the required addition). + ## To version 3.4.0 Starting with this version, the VM-Operator no longer uses a stateful set From c45c452c83a09cf6c00ab6ab3cfe8ad0ab7e6529 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 24 Feb 2025 13:20:28 +0100 Subject: [PATCH 190/342] Adjust class name. --- .../vmoperator/manager/DisplaySecretReconciler.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 66bb021..e1955b4 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 @@ -76,7 +76,7 @@ public class DisplaySecretReconciler extends Component { protected final Logger logger = Logger.getLogger(getClass().getName()); private int passwordValidity = 10; - private final List pendingPrepares + private final List pendingPrepares = Collections.synchronizedList(new LinkedList<>()); /** @@ -234,8 +234,8 @@ public class DisplaySecretReconciler extends Component { return; } - // Prepare wait for confirmation (by VM status change) - var pending = new PendingGet(event, + // Register wait for confirmation (by VM status change) + var pending = new PendingPrepare(event, event.vmDefinition().displayPasswordSerial().orElse(0L) + 1, new CompletionLock(event, 1500)); pendingPrepares.add(pending); @@ -333,7 +333,7 @@ public class DisplaySecretReconciler extends Component { * The Class PendingGet. */ @SuppressWarnings("PMD.DataClass") - private static class PendingGet { + private static class PendingPrepare { public final PrepareConsole event; public final long expectedSerial; public final CompletionLock lock; @@ -344,7 +344,7 @@ public class DisplaySecretReconciler extends Component { * @param event the event * @param expectedSerial the expected serial */ - public PendingGet(PrepareConsole event, long expectedSerial, + public PendingPrepare(PrepareConsole event, long expectedSerial, CompletionLock lock) { super(); this.event = event; From ddab466fd05a8d168f5b38dd3716a4ccdb898985 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 24 Feb 2025 14:03:49 +0100 Subject: [PATCH 191/342] Restrict pagefind search to project. --- webpages/_layouts/vm-operator.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index e779711..4456d20 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -11,11 +11,12 @@ - - + + + + +

Hosted on GitHub Pages — TermsPrivacy — Theme derived from minimal

From d7af1f5d068ab4f8283e109220b16ace7f88c322 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 12:23:02 +0100 Subject: [PATCH 219/342] Fix footer. --- webpages/_layouts/vm-operator.html | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 5d780ef..1c3bad2 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -82,15 +82,17 @@
- - - - - -

Hosted on GitHub Pages — Terms - — Privacy - — Theme derived from minimal

From 05d53c58b16f5ac60842012d0fc0c662bdd03cbd Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 12:28:08 +0100 Subject: [PATCH 220/342] Fix footer. --- webpages/_layouts/vm-operator.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 1c3bad2..966b268 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -88,7 +88,7 @@ — Privacy — Theme derived from minimal

-
- -
From 687a050ec446441ba6e28e1e56f19d2473b9641c Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 12:55:40 +0100 Subject: [PATCH 222/342] Generate sitemap. --- webpages/Gemfile | 1 + webpages/_config.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/webpages/Gemfile b/webpages/Gemfile index ecbbb7d..3e965ca 100644 --- a/webpages/Gemfile +++ b/webpages/Gemfile @@ -2,4 +2,5 @@ source 'https://rubygems.org' # gem 'github-pages', group: :jekyll_plugins gem "jekyll", "~> 4.0" gem "jekyll-seo-tag" +gem 'jekyll-sitemap' gem 'webrick', '~> 1.3', '>= 1.3.1' diff --git a/webpages/_config.yml b/webpages/_config.yml index bc830a3..a2ee1a3 100644 --- a/webpages/_config.yml +++ b/webpages/_config.yml @@ -1,5 +1,6 @@ plugins: - jekyll-seo-tag + - jekyll-sitemap url: "https://jdrupes.org" From 07fb07a6a4c4c334cad516282a0ffeac331dc17d Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 12:57:26 +0100 Subject: [PATCH 223/342] Javadoc is hosted on main site only. --- webpages/_layouts/vm-operator.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 8be6f81..820aeb6 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -68,7 +68,7 @@
  • For Users

  • Upgrading

    -

    Javadoc

    +

    Javadoc

    From 3a94602a0d825cda0045401e270f34e1ab183b61 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 13:02:46 +0100 Subject: [PATCH 224/342] Add sitemap. --- webpages/robots.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 webpages/robots.txt diff --git a/webpages/robots.txt b/webpages/robots.txt new file mode 100644 index 0000000..457a45d --- /dev/null +++ b/webpages/robots.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / +Sitemap: sitemap.xml From f6338758d8b5abfaa125cc3e07698eb6eacf8b29 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 13:13:03 +0100 Subject: [PATCH 225/342] Sitemap property must be an absolute url. --- webpages/.readthedocs.yaml | 1 + webpages/robots-readthedocs.txt | 3 +++ webpages/robots.txt | 3 --- 3 files changed, 4 insertions(+), 3 deletions(-) create mode 100644 webpages/robots-readthedocs.txt delete mode 100644 webpages/robots.txt diff --git a/webpages/.readthedocs.yaml b/webpages/.readthedocs.yaml index 15aece6..2eac996 100644 --- a/webpages/.readthedocs.yaml +++ b/webpages/.readthedocs.yaml @@ -14,4 +14,5 @@ build: - cd webpages && bundle install # Build the site and save generated files into Read the Docs directory - cd webpages && jekyll build --destination $READTHEDOCS_OUTPUT/html + - cp webpages/robots-readthedocs.txt $READTHEDOCS_OUTPUT/html \ No newline at end of file diff --git a/webpages/robots-readthedocs.txt b/webpages/robots-readthedocs.txt new file mode 100644 index 0000000..90e0f33 --- /dev/null +++ b/webpages/robots-readthedocs.txt @@ -0,0 +1,3 @@ +User-agent: * +Allow: / +Sitemap: https://kubernetes-vm-operator.readthedocs.io/sitemap.xml diff --git a/webpages/robots.txt b/webpages/robots.txt deleted file mode 100644 index 457a45d..0000000 --- a/webpages/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -User-agent: * -Allow: / -Sitemap: sitemap.xml From 199cd8185ea66681ba2617f1ef553dc3eae54cc8 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 13:15:38 +0100 Subject: [PATCH 226/342] Fix robots.txt "generation". --- webpages/.readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/.readthedocs.yaml b/webpages/.readthedocs.yaml index 2eac996..546c09f 100644 --- a/webpages/.readthedocs.yaml +++ b/webpages/.readthedocs.yaml @@ -14,5 +14,5 @@ build: - cd webpages && bundle install # Build the site and save generated files into Read the Docs directory - cd webpages && jekyll build --destination $READTHEDOCS_OUTPUT/html - - cp webpages/robots-readthedocs.txt $READTHEDOCS_OUTPUT/html + - cp webpages/robots-readthedocs.txt $READTHEDOCS_OUTPUT/html/robots.txt \ No newline at end of file From 60349bca7881b4c08fc034aa6934d5eff078b882 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 13:45:38 +0100 Subject: [PATCH 227/342] Shorten title to make bing happy. --- webpages/vm-operator/manager.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/vm-operator/manager.md b/webpages/vm-operator/manager.md index ee971c1..d283484 100644 --- a/webpages/vm-operator/manager.md +++ b/webpages/vm-operator/manager.md @@ -1,5 +1,5 @@ --- -title: "VM-Operator: The Manager — Provides the controller and a web user interface" +title: "VM-Operator: The Manager — Provides the controller and a Web UI" description: >- Information about the installation and configuration of the VM Operator. From 0e28bcd038bc529a5ee8be6f228449bfd33426bb Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 18:48:13 +0100 Subject: [PATCH 228/342] Change (main) site. --- webpages/_config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webpages/_config.yml b/webpages/_config.yml index a2ee1a3..1ebd835 100644 --- a/webpages/_config.yml +++ b/webpages/_config.yml @@ -2,7 +2,7 @@ plugins: - jekyll-seo-tag - jekyll-sitemap -url: "https://jdrupes.org" +url: "https://vm-operator.jdrupes.org" author: Michael N. Lipp From fd0bcc93074418fec8ba33f962210a856edd7f53 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 20:10:42 +0100 Subject: [PATCH 229/342] Move main site to vm-operator.jdrupes.org. --- misc/javadoc.bottom.txt | 7 ++++--- webpages/_includes/matomo.html | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/misc/javadoc.bottom.txt b/misc/javadoc.bottom.txt index abf54f3..631d63f 100644 --- a/misc/javadoc.bottom.txt +++ b/misc/javadoc.bottom.txt @@ -16,18 +16,19 @@ var _paq = _paq || []; /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDocumentTitle", document.domain + "/" + document.title]); - _paq.push(["setCookieDomain", "*.jdrupes.org"]); + _paq.push(["setCookieDomain", "*.mnlipp.github.io"]); + _paq.push(["setDomains", ["*.mnlipp.github.io", "*.jdrupes.org", "kubernetes-vm-operator.readthedocs.io"]]); _paq.push(['disableCookies']); _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="//jdrupes.org/"; _paq.push(['setTrackerUrl', u+'piwik.php']); - _paq.push(['setSiteId', '15']); + _paq.push(['setSiteId', '17']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); })(); - +
    \ No newline at end of file diff --git a/webpages/_includes/matomo.html b/webpages/_includes/matomo.html index 3a93186..75978bc 100644 --- a/webpages/_includes/matomo.html +++ b/webpages/_includes/matomo.html @@ -4,20 +4,20 @@ /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ _paq.push(["setDocumentTitle", document.domain + "/" + document.title]); _paq.push(["setCookieDomain", "*.mnlipp.github.io"]); - _paq.push(["setDomains", ["*.mnlipp.github.io"]]); + _paq.push(["setDomains", ["*.mnlipp.github.io", "*.jdrupes.org", "kubernetes-vm-operator.readthedocs.io"]]); _paq.push(['disableCookies']); _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { var u="//piwik.mnl.de/"; _paq.push(['setTrackerUrl', u+'piwik.php']); - _paq.push(['setSiteId', '14']); + _paq.push(['setSiteId', '17']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); })(); From a0dfd2519226e6ac479d0cbe462a9ac5bc9a65fd Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 20:29:56 +0100 Subject: [PATCH 230/342] Add robots.txt. --- webpages/robots.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 webpages/robots.txt diff --git a/webpages/robots.txt b/webpages/robots.txt new file mode 100644 index 0000000..c2a49f4 --- /dev/null +++ b/webpages/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: / From 4965845f3da5170ce813aa8430c6364d3c85bf2b Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 20:44:39 +0100 Subject: [PATCH 231/342] Move robots.txt. --- webpages/vm-operator/robots.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 webpages/vm-operator/robots.txt diff --git a/webpages/vm-operator/robots.txt b/webpages/vm-operator/robots.txt new file mode 100644 index 0000000..c2a49f4 --- /dev/null +++ b/webpages/vm-operator/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Allow: / From d8cff8b9425e449255dc15db3e5496ffb0a8fef4 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 21:06:26 +0100 Subject: [PATCH 232/342] Track vm-operator separately. --- buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle | 1 + .../{matomo.html => matomo-vm-operator.jdrupes.org.html} | 0 webpages/_layouts/vm-operator.html | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) rename webpages/_includes/{matomo.html => matomo-vm-operator.jdrupes.org.html} (100%) diff --git a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle index 5eed550..0b6e68f 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle @@ -124,6 +124,7 @@ gitPublish { branch = 'main' contents { from("${rootProject.projectDir}/webpages") { + include '_includes/matomo-vm-operator.jdrupes.org.html' include '_layouts/vm-operator.html' include 'vm-operator/**' } diff --git a/webpages/_includes/matomo.html b/webpages/_includes/matomo-vm-operator.jdrupes.org.html similarity index 100% rename from webpages/_includes/matomo.html rename to webpages/_includes/matomo-vm-operator.jdrupes.org.html diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 820aeb6..2e2e444 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -104,7 +104,7 @@ - {% include matomo.html %} + {% include matomo-vm-operator.jdrupes.org.html %} From d6e2a92fe8a3f5578e606d8eb9956e07f967c67d Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 21:20:25 +0100 Subject: [PATCH 233/342] Fix url. --- misc/javadoc.bottom.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/misc/javadoc.bottom.txt b/misc/javadoc.bottom.txt index 631d63f..c858345 100644 --- a/misc/javadoc.bottom.txt +++ b/misc/javadoc.bottom.txt @@ -22,7 +22,7 @@ _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { - var u="//jdrupes.org/"; + var u="//piwik.mnl.de/"; _paq.push(['setTrackerUrl', u+'piwik.php']); _paq.push(['setSiteId', '17']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; From 7670857d0a48bf8fd4c6faa89e36dba0bfa46665 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 21:50:24 +0100 Subject: [PATCH 234/342] Separate sites. --- .github/workflows/jekyll.yml | 68 +++++++++++++++++++ ...-operator.jdrupes.org.html => matomo.html} | 0 webpages/_layouts/vm-operator.html | 4 +- webpages/robots.txt | 2 - 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/jekyll.yml rename webpages/_includes/{matomo-vm-operator.jdrupes.org.html => matomo.html} (100%) delete mode 100644 webpages/robots.txt diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml new file mode 100644 index 0000000..57d3802 --- /dev/null +++ b/.github/workflows/jekyll.yml @@ -0,0 +1,68 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# Sample workflow for building and deploying a Jekyll site to GitHub Pages +name: Deploy Jekyll site to Pages + +on: + # Runs on pushes targeting the default branch + push: + branches: ["main"] + + # Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between +# the run in-progress and latest queued. However, do NOT cancel +# in-progress runs as we want to allow these production deployments +# to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + # Build job + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Setup Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.3' # Not needed with a .ruby-version file + bundler-cache: true # runs 'bundle install' and caches installed gems automatically + cache-version: 0 # Increment this number if you need to re-download cached gems + - name: Setup Pages + id: pages + uses: actions/configure-pages@v5 + - name: Build with Jekyll + # Outputs to the './_site' directory by default + run: bundle exec jekyll build + env: + JEKYLL_ENV: production + - name: Index pagefind + run: npx pagefind --source "_site/vm-operator" + - name: Upload artifact + # Automatically uploads an artifact from the './_site' directory by default + uses: actions/upload-pages-artifact@v3 + + # Deployment job + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/webpages/_includes/matomo-vm-operator.jdrupes.org.html b/webpages/_includes/matomo.html similarity index 100% rename from webpages/_includes/matomo-vm-operator.jdrupes.org.html rename to webpages/_includes/matomo.html diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 2e2e444..6d0df26 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -83,7 +83,7 @@
    - {% include matomo-vm-operator.jdrupes.org.html %} + {% include matomo.html %} diff --git a/webpages/robots.txt b/webpages/robots.txt deleted file mode 100644 index c2a49f4..0000000 --- a/webpages/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Allow: / From 083c6db2da1224786963e0cfe791fcf24a65f692 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 22:12:43 +0100 Subject: [PATCH 235/342] Build own site. --- .github/workflows/jekyll.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml index 57d3802..b273259 100644 --- a/.github/workflows/jekyll.yml +++ b/.github/workflows/jekyll.yml @@ -35,25 +35,38 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 + - name: Set up JDK 21 + uses: actions/setup-java@v3 + with: + java-version: '21' + distribution: 'temurin' - name: Setup Ruby uses: ruby/setup-ruby@v1 with: ruby-version: '3.3' # Not needed with a .ruby-version file bundler-cache: true # runs 'bundle install' and caches installed gems automatically cache-version: 0 # Increment this number if you need to re-download cached gems + - name: Install graphviz + run: sudo apt-get install graphviz + - name: Build apidocs + run: ./gradlew apidocs - name: Setup Pages id: pages uses: actions/configure-pages@v5 - name: Build with Jekyll # Outputs to the './_site' directory by default - run: bundle exec jekyll build + run: cd webpages && bundle exec jekyll build env: JEKYLL_ENV: production + - name: Copy javadoc + run: cp -a build/javadoc webpages/_site/vm-operator/ - name: Index pagefind - run: npx pagefind --source "_site/vm-operator" + run: cd webpages && npx pagefind --source "_site/vm-operator" - name: Upload artifact # Automatically uploads an artifact from the './_site' directory by default uses: actions/upload-pages-artifact@v3 + with: + path: './webpages/_site' # Deployment job deploy: From 987f634f40cc1ab3abbade24ab5cb36b2634a8ce Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 22:33:22 +0100 Subject: [PATCH 236/342] Update. --- .github/workflows/jekyll.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml index b273259..c7df16e 100644 --- a/.github/workflows/jekyll.yml +++ b/.github/workflows/jekyll.yml @@ -35,21 +35,12 @@ jobs: steps: - name: Checkout uses: actions/checkout@v4 - - name: Set up JDK 21 - uses: actions/setup-java@v3 - with: - java-version: '21' - distribution: 'temurin' - name: Setup Ruby uses: ruby/setup-ruby@v1 with: ruby-version: '3.3' # Not needed with a .ruby-version file bundler-cache: true # runs 'bundle install' and caches installed gems automatically cache-version: 0 # Increment this number if you need to re-download cached gems - - name: Install graphviz - run: sudo apt-get install graphviz - - name: Build apidocs - run: ./gradlew apidocs - name: Setup Pages id: pages uses: actions/configure-pages@v5 @@ -58,6 +49,15 @@ jobs: run: cd webpages && bundle exec jekyll build env: JEKYLL_ENV: production + - name: Install graphviz + run: sudo apt-get install graphviz + - name: Set up JDK 21 + uses: actions/setup-java@v3 + with: + java-version: '21' + distribution: 'temurin' + - name: Build apidocs + run: ./gradlew apidocs - name: Copy javadoc run: cp -a build/javadoc webpages/_site/vm-operator/ - name: Index pagefind From 30bc11917880229e14bcbd46e80935019484bfbd Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 22:57:22 +0100 Subject: [PATCH 237/342] Update. --- .github/workflows/jekyll.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml index c7df16e..58609d6 100644 --- a/.github/workflows/jekyll.yml +++ b/.github/workflows/jekyll.yml @@ -41,6 +41,7 @@ jobs: ruby-version: '3.3' # Not needed with a .ruby-version file bundler-cache: true # runs 'bundle install' and caches installed gems automatically cache-version: 0 # Increment this number if you need to re-download cached gems + working-directory: webpages - name: Setup Pages id: pages uses: actions/configure-pages@v5 From 214085119c180a990835e05d01902bd54396fdd0 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 2 Mar 2025 23:15:19 +0100 Subject: [PATCH 238/342] Add style for searching. --- webpages/stylesheets/styles.css | 50 +++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/webpages/stylesheets/styles.css b/webpages/stylesheets/styles.css index 8d6b803..41fb0d0 100644 --- a/webpages/stylesheets/styles.css +++ b/webpages/stylesheets/styles.css @@ -189,6 +189,56 @@ footer { margin-bottom:5px; } +#search { + + --pagefind-ui-font: inherit; + --pagefind-ui-border-radius: 4px; + + position: absolute; + right: 1em; + top: 1em; + + .pagefind-ui__form { + width: 20em; + margin-left: auto; + + &::before { + top: calc(17px * var(--pagefind-ui-scale)); + } + } + + .pagefind-ui__search-input { + font-weight: inherit; + height: calc(48px * var(--pagefind-ui-scale)); + } + + .pagefind-ui__search-clear { + font-weight: inherit; + height: calc(42px * var(--pagefind-ui-scale)); + } + + .pagefind-ui__drawer { + position: absolute; + right: 0; + width: 40em; + background-color: white; + border: solid var(--pagefind-ui-border-width) var(--pagefind-ui-border); + padding: 0 1em 1em 1em; + } + + .pagefind-ui__message { + padding-top: 0; + } + + .pagefind-ui__result { + padding: 0; + } + + .pagefind-ui__result-title { + font-weight: inherit; + } +} + @media print, screen and (max-width: 960px) { div.wrapper { From 03fdabe85a777618b9e9cd69158acafde87922e8 Mon Sep 17 00:00:00 2001 From: Michael Lipp Date: Mon, 3 Mar 2025 06:50:03 +0000 Subject: [PATCH 239/342] Edit README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4c989b6..e6292ec 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ # Run Qemu in Kubernetes Pods -The goal of this project is to provide easy to use and flexible components +The goal of this project is to provide orgy to use and flexible components for running Qemu based VMs in Kubernetes pods. - -See the [project's home page](https://jdrupes.org/vm-operator/) +vm-ovm +See the [project's home page](https://vm-operator.jdrupes.org/) for details. From c004265f5e8165c4a88bba79b96e132169972c46 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 3 Mar 2025 09:25:58 +0100 Subject: [PATCH 240/342] Don't merge into jdrupes.org any more. --- build.gradle | 9 +----- ...pes.vmoperator.java-doc-conventions.gradle | 31 ------------------- 2 files changed, 1 insertion(+), 39 deletions(-) diff --git a/build.gradle b/build.gradle index 8a7b571..eb8e59a 100644 --- a/build.gradle +++ b/build.gradle @@ -19,7 +19,7 @@ allprojects { } task stage { - description = 'To be executed by CI, build and update JavaDoc.' + description = 'To be executed by CI.' group = 'build' // Build everything first @@ -27,13 +27,6 @@ task stage { dependsOn subprojects.tasks.collect { tc -> tc.findByName("build") }.flatten() } - - def gitBranch = grgit.branch.current.name.replace('/', '-') - if (JavaVersion.current() == JavaVersion.VERSION_21 - && gitBranch == "main") { - // Publish JavaDoc - dependsOn gitPublishPush - } } eclipse { diff --git a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle index 0b6e68f..6af8fa7 100644 --- a/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle +++ b/buildSrc/src/org.jdrupes.vmoperator.java-doc-conventions.gradle @@ -118,34 +118,3 @@ if (System.properties['org.ajoberstar.grgit.auth.username'] == null) { System.setProperty('org.ajoberstar.grgit.auth.username', project.rootProject.properties['website.push.token'] ?: "nouser") } - -gitPublish { - repoUri = 'https://github.com/mnlipp/jdrupes.org.git' - branch = 'main' - contents { - from("${rootProject.projectDir}/webpages") { - include '_includes/matomo-vm-operator.jdrupes.org.html' - include '_layouts/vm-operator.html' - include 'vm-operator/**' - } - from("${rootProject.buildDir}/javadoc") { - into 'vm-operator/javadoc' - } - if (!findProject(':org.jdrupes.vmoperator.runner.qemu').isSnapshot - && !findProject(':org.jdrupes.vmoperator.manager').isSnapshot) { - from("${rootProject.buildDir}/javadoc") { - into 'vm-operator/latest-release/javadoc' - } - } - } - preserve { include '**/*' } - commitMessage = "Updated." -} - -gradle.projectsEvaluated { - tasks.gitPublishReset.mustRunAfter subprojects.tasks - .collect { tc -> tc.findByName("build") }.flatten() - tasks.gitPublishReset.mustRunAfter subprojects.tasks - .collect { tc -> tc.findByName("test") }.flatten() - tasks.gitPublishCopy.dependsOn apidocs -} From cc78c38efe650301f9bfba4d4632d781acd8a7eb Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 3 Mar 2025 10:16:05 +0100 Subject: [PATCH 241/342] Remove no longer needed sub-directory. --- .github/workflows/jekyll.yml | 4 ++-- misc/javadoc.bottom.txt | 5 +++-- webpages/{vm-operator => }/02_2_operator.png | Bin .../VM-Operator-GUI-preview.png | Bin .../{vm-operator => }/VM-Operator-GUI-view.png | Bin .../{vm-operator => }/VM-Operator-with-font.svg | 0 webpages/{vm-operator => }/VM-Operator.svg | 0 webpages/{vm-operator => }/VmAccess-preview.png | Bin webpages/_includes/matomo.html | 4 ++-- webpages/_layouts/vm-operator.html | 15 ++++++++------- webpages/{vm-operator => }/admin-gui.md | 0 webpages/{vm-operator => }/controller.md | 0 webpages/{vm-operator => }/favicon.svg | 0 webpages/{vm-operator => }/index-pic.svg | 0 webpages/index.html | 11 ----------- webpages/{vm-operator => }/index.md | 0 webpages/{vm-operator => }/manager.md | 0 webpages/{vm-operator => }/pools.md | 0 webpages/{vm-operator => }/robots.txt | 0 webpages/{vm-operator => }/runner.md | 0 webpages/{vm-operator => }/upgrading.md | 0 webpages/{vm-operator => }/user-gui.md | 0 webpages/{vm-operator => }/webgui.md | 0 23 files changed, 15 insertions(+), 24 deletions(-) rename webpages/{vm-operator => }/02_2_operator.png (100%) rename webpages/{vm-operator => }/VM-Operator-GUI-preview.png (100%) rename webpages/{vm-operator => }/VM-Operator-GUI-view.png (100%) rename webpages/{vm-operator => }/VM-Operator-with-font.svg (100%) rename webpages/{vm-operator => }/VM-Operator.svg (100%) rename webpages/{vm-operator => }/VmAccess-preview.png (100%) rename webpages/{vm-operator => }/admin-gui.md (100%) rename webpages/{vm-operator => }/controller.md (100%) rename webpages/{vm-operator => }/favicon.svg (100%) rename webpages/{vm-operator => }/index-pic.svg (100%) delete mode 100644 webpages/index.html rename webpages/{vm-operator => }/index.md (100%) rename webpages/{vm-operator => }/manager.md (100%) rename webpages/{vm-operator => }/pools.md (100%) rename webpages/{vm-operator => }/robots.txt (100%) rename webpages/{vm-operator => }/runner.md (100%) rename webpages/{vm-operator => }/upgrading.md (100%) rename webpages/{vm-operator => }/user-gui.md (100%) rename webpages/{vm-operator => }/webgui.md (100%) diff --git a/.github/workflows/jekyll.yml b/.github/workflows/jekyll.yml index 58609d6..b5acc1f 100644 --- a/.github/workflows/jekyll.yml +++ b/.github/workflows/jekyll.yml @@ -60,9 +60,9 @@ jobs: - name: Build apidocs run: ./gradlew apidocs - name: Copy javadoc - run: cp -a build/javadoc webpages/_site/vm-operator/ + run: cp -a build/javadoc webpages/_site/ - name: Index pagefind - run: cd webpages && npx pagefind --source "_site/vm-operator" + run: cd webpages && npx pagefind --source "_site" - name: Upload artifact # Automatically uploads an artifact from the './_site' directory by default uses: actions/upload-pages-artifact@v3 diff --git a/misc/javadoc.bottom.txt b/misc/javadoc.bottom.txt index c858345..dfc3373 100644 --- a/misc/javadoc.bottom.txt +++ b/misc/javadoc.bottom.txt @@ -22,13 +22,14 @@ _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { - var u="//piwik.mnl.de/"; + var u="https://piwik.mnl.de/"; _paq.push(['setTrackerUrl', u+'piwik.php']); _paq.push(['setSiteId', '17']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; g.type='text/javascript'; g.async=true; g.defer=true; g.src=u+'piwik.js'; s.parentNode.insertBefore(g,s); })(); - + \ No newline at end of file diff --git a/webpages/vm-operator/02_2_operator.png b/webpages/02_2_operator.png similarity index 100% rename from webpages/vm-operator/02_2_operator.png rename to webpages/02_2_operator.png diff --git a/webpages/vm-operator/VM-Operator-GUI-preview.png b/webpages/VM-Operator-GUI-preview.png similarity index 100% rename from webpages/vm-operator/VM-Operator-GUI-preview.png rename to webpages/VM-Operator-GUI-preview.png diff --git a/webpages/vm-operator/VM-Operator-GUI-view.png b/webpages/VM-Operator-GUI-view.png similarity index 100% rename from webpages/vm-operator/VM-Operator-GUI-view.png rename to webpages/VM-Operator-GUI-view.png diff --git a/webpages/vm-operator/VM-Operator-with-font.svg b/webpages/VM-Operator-with-font.svg similarity index 100% rename from webpages/vm-operator/VM-Operator-with-font.svg rename to webpages/VM-Operator-with-font.svg diff --git a/webpages/vm-operator/VM-Operator.svg b/webpages/VM-Operator.svg similarity index 100% rename from webpages/vm-operator/VM-Operator.svg rename to webpages/VM-Operator.svg diff --git a/webpages/vm-operator/VmAccess-preview.png b/webpages/VmAccess-preview.png similarity index 100% rename from webpages/vm-operator/VmAccess-preview.png rename to webpages/VmAccess-preview.png diff --git a/webpages/_includes/matomo.html b/webpages/_includes/matomo.html index 75978bc..adb7c30 100644 --- a/webpages/_includes/matomo.html +++ b/webpages/_includes/matomo.html @@ -9,7 +9,7 @@ _paq.push(['trackPageView']); _paq.push(['enableLinkTracking']); (function() { - var u="//piwik.mnl.de/"; + var u="https://piwik.mnl.de/"; _paq.push(['setTrackerUrl', u+'piwik.php']); _paq.push(['setSiteId', '17']); var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; @@ -17,7 +17,7 @@ })(); diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index 6d0df26..590412a 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -5,18 +5,19 @@ - - + + - - + + diff --git a/webpages/_layouts/vm-operator.html b/webpages/_layouts/vm-operator.html index b85f650..40bdff7 100644 --- a/webpages/_layouts/vm-operator.html +++ b/webpages/_layouts/vm-operator.html @@ -8,6 +8,7 @@ + {% include umami.html %} From 5bcf0ba0512950ba73adafe692998749f9afc4d6 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 13 Apr 2025 17:01:38 +0200 Subject: [PATCH 330/342] Add umami to javadoc. --- misc/javadoc.bottom.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/misc/javadoc.bottom.txt b/misc/javadoc.bottom.txt index dfc3373..d5589ac 100644 --- a/misc/javadoc.bottom.txt +++ b/misc/javadoc.bottom.txt @@ -32,4 +32,5 @@ + \ No newline at end of file From 6ef4c2aaa26eb9480edcecffc5239a8ae2979e44 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 14 Apr 2025 12:08:48 +0200 Subject: [PATCH 331/342] Fix return value. --- .../src/org/jdrupes/vmoperator/common/VmExtraData.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmExtraData.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmExtraData.java index 83d9577..6a94c9c 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmExtraData.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/VmExtraData.java @@ -118,14 +118,14 @@ public class VmExtraData { if (addr.isEmpty()) { logger .severe(() -> "Failed to find display IP for " + vmDef.name()); - return null; + return Optional.empty(); } var port = vmDef. fromVm("display", "spice", "port") .map(Number::longValue); if (port.isEmpty()) { logger .severe(() -> "No port defined for display of " + vmDef.name()); - return null; + return Optional.empty(); } StringBuffer data = new StringBuffer(100) .append("[virt-viewer]\ntype=spice\nhost=") From 7d298ce24b91269dcb4cb68af2ae01397339ba10 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Mon, 14 Apr 2025 21:39:35 +0200 Subject: [PATCH 332/342] Clarify intend. --- .../src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java | 1 + .../src/org/jdrupes/vmoperator/common/K8sGenericStub.java | 1 + 2 files changed, 2 insertions(+) diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java index af87af2..6b5fd7e 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sClusterGenericStub.java @@ -240,6 +240,7 @@ public class K8sClusterGenericStub the object list type * @param the result type */ + @FunctionalInterface public interface GenericSupplier> { diff --git a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java index b8f1992..aef791f 100644 --- a/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java +++ b/org.jdrupes.vmoperator.common/src/org/jdrupes/vmoperator/common/K8sGenericStub.java @@ -359,6 +359,7 @@ public class K8sGenericStub the object list type * @param the result type */ + @FunctionalInterface public interface GenericSupplier> { From b7fad4614db37bc9f72b3d622fc708d15bdde5e9 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Tue, 29 Apr 2025 14:02:12 +0200 Subject: [PATCH 333/342] Improve debug messages. --- .../runner/qemu/GuestAgentClient.java | 16 ++++++----- .../vmoperator/runner/qemu/QemuMonitor.java | 25 ++++++++++------- .../runner/qemu/VmopAgentClient.java | 27 +++++++++++++------ .../runner/qemu/events/MonitorEvent.java | 18 +++++++++++++ .../runner/qemu/events/OsinfoEvent.java | 19 +++++++++++++ 5 files changed, 81 insertions(+), 24 deletions(-) diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java index b0001e4..45d2487 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/GuestAgentClient.java @@ -69,14 +69,14 @@ public class GuestAgentClient extends AgentConnector { */ @Override protected void agentConnected() { - logger.fine(() -> "guest agent connected"); + logger.fine(() -> "Guest agent connected"); connected = true; rep().fire(new GuestAgentCommand(new QmpGuestGetOsinfo())); } @Override protected void agentDisconnected() { - logger.fine(() -> "guest agent disconnected"); + logger.fine(() -> "Guest agent disconnected"); connected = false; } @@ -88,15 +88,16 @@ public class GuestAgentClient extends AgentConnector { */ @Override protected void processInput(String line) throws IOException { - logger.fine(() -> "guest agent(in): " + line); + logger.finer(() -> "guest agent(in): " + line); try { var response = mapper.readValue(line, ObjectNode.class); if (response.has("return") || response.has("error")) { QmpCommand executed = executing.poll(); - logger.fine(() -> String.format("(Previous \"guest agent(in)\"" + logger.finer(() -> String.format("(Previous \"guest agent(in)\"" + " is result from executing %s)", executed)); if (executed instanceof QmpGuestGetOsinfo) { var osInfo = new OsinfoEvent(response.get("return")); + logger.fine(() -> "Guest agent triggers: " + osInfo); rep().fire(osInfo); } } @@ -120,10 +121,11 @@ public class GuestAgentClient extends AgentConnector { return; } var command = event.command(); - logger.fine(() -> "guest agent(out): " + command.toString()); + logger.fine(() -> "Guest handles: " + event); String asText; try { asText = command.asText(); + logger.finer(() -> "guest agent(out): " + asText); } catch (JsonProcessingException e) { logger.log(Level.SEVERE, e, () -> "Cannot serialize Json: " + e.getMessage()); @@ -163,8 +165,8 @@ public class GuestAgentClient extends AgentConnector { } event.suspendHandling(); suspendedStop = event; - logger.fine(() -> "Sending powerdown command, waiting for" - + " termination until " + waitUntil); + logger.fine(() -> "Attempting shutdown through guest agent," + + " waiting for termination until " + waitUntil); powerdownTimer = Components.schedule(t -> { logger.fine(() -> "Powerdown timeout reached."); synchronized (this) { diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java index 6be7603..e844bc4 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/QemuMonitor.java @@ -108,24 +108,30 @@ public class QemuMonitor extends QemuConnector { @Override protected void processInput(String line) throws IOException { - logger.fine(() -> "monitor(in): " + line); + logger.finer(() -> "monitor(in): " + line); try { var response = mapper.readValue(line, ObjectNode.class); if (response.has("QMP")) { monitorReady = true; + logger.fine(() -> "QMP connection ready"); rep().fire(new MonitorReady()); return; } if (response.has("return") || response.has("error")) { QmpCommand executed = executing.poll(); - logger.fine( + logger.finer( () -> String.format("(Previous \"monitor(in)\" is result " + "from executing %s)", executed)); - rep().fire(MonitorResult.from(executed, response)); + var monRes = MonitorResult.from(executed, response); + logger.fine(() -> "QMP triggers: " + monRes); + rep().fire(monRes); return; } if (response.has("event")) { - MonitorEvent.from(response).ifPresent(rep()::fire); + MonitorEvent.from(response).ifPresent(me -> { + logger.fine(() -> "QMP triggers: " + me); + rep().fire(me); + }); } } catch (JsonProcessingException e) { throw new IOException(e); @@ -141,7 +147,7 @@ public class QemuMonitor extends QemuConnector { public void onClosed(Closed event, SocketIOChannel channel) { channel.associated(this, getClass()).ifPresent(qm -> { super.onClosed(event, channel); - logger.finer(() -> "QMP socket closed."); + logger.fine(() -> "QMP connection closed."); monitorReady = false; }); } @@ -158,7 +164,7 @@ public class QemuMonitor extends QemuConnector { public void onMonitorCommand(MonitorCommand event) throws IOException { // Check prerequisites if (!monitorReady && !(event.command() instanceof QmpCapabilities)) { - logger.severe(() -> "Premature monitor command (not ready): " + logger.severe(() -> "Premature QMP command (not ready): " + event.command()); rep().fire(new Stop()); return; @@ -166,10 +172,11 @@ public class QemuMonitor extends QemuConnector { // Send the command var command = event.command(); - logger.fine(() -> "monitor(out): " + command.toString()); + logger.fine(() -> "QMP handles: " + event.toString()); String asText; try { asText = command.asText(); + logger.finer(() -> "monitor(out): " + asText); } catch (JsonProcessingException e) { logger.log(Level.SEVERE, e, () -> "Cannot serialize Json: " + e.getMessage()); @@ -192,8 +199,8 @@ public class QemuMonitor extends QemuConnector { @SuppressWarnings("PMD.AvoidSynchronizedStatement") public void onStop(Stop event) { if (!monitorReady) { - logger.fine(() -> "No QMP connection," - + " cannot send powerdown command"); + logger.fine(() -> "Not sending QMP powerdown command" + + " because QMP connection is closed"); return; } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java index f50d397..cac41d4 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/VmopAgentClient.java @@ -59,10 +59,14 @@ public class VmopAgentClient extends AgentConnector { */ @Handler public void onVmopAgentLogIn(VmopAgentLogIn event) throws IOException { - logger.fine(() -> "vmop agent(out): login " + event.user()); if (writer().isPresent()) { + logger.fine(() -> "Vmop agent handles:" + event); executing.add(event); + logger.finer(() -> "vmop agent(out): login " + event.user()); sendCommand("login " + event.user()); + } else { + logger + .warning(() -> "No vmop agent connection for sending " + event); } } @@ -74,9 +78,10 @@ public class VmopAgentClient extends AgentConnector { */ @Handler public void onVmopAgentLogout(VmopAgentLogOut event) throws IOException { - logger.fine(() -> "vmop agent(out): logout"); if (writer().isPresent()) { + logger.fine(() -> "Vmop agent handles:" + event); executing.add(event); + logger.finer(() -> "vmop agent(out): logout"); sendCommand("logout"); } } @@ -85,23 +90,27 @@ public class VmopAgentClient extends AgentConnector { @SuppressWarnings({ "PMD.UnnecessaryReturn", "PMD.AvoidLiteralsInIfCondition" }) protected void processInput(String line) throws IOException { - logger.fine(() -> "vmop agent(in): " + line); + logger.finer(() -> "vmop agent(in): " + line); // Check validity if (line.isEmpty() || !Character.isDigit(line.charAt(0))) { - logger.warning(() -> "Illegal response: " + line); + logger.warning(() -> "Illegal vmop agent response: " + line); return; } // Check positive responses if (line.startsWith("220 ")) { - rep().fire(new VmopAgentConnected()); + var evt = new VmopAgentConnected(); + logger.fine(() -> "Vmop agent triggers " + evt); + rep().fire(evt); return; } if (line.startsWith("201 ")) { Event cmd = executing.pop(); if (cmd instanceof VmopAgentLogIn login) { - rep().fire(new VmopAgentLoggedIn(login)); + var evt = new VmopAgentLoggedIn(login); + logger.fine(() -> "Vmop agent triggers " + evt); + rep().fire(evt); } else { logger.severe(() -> "Response " + line + " does not match executing command " + cmd); @@ -111,7 +120,9 @@ public class VmopAgentClient extends AgentConnector { if (line.startsWith("202 ")) { Event cmd = executing.pop(); if (cmd instanceof VmopAgentLogOut logout) { - rep().fire(new VmopAgentLoggedOut(logout)); + var evt = new VmopAgentLoggedOut(logout); + logger.fine(() -> "Vmop agent triggers " + evt); + rep().fire(evt); } else { logger.severe(() -> "Response " + line + "does not match executing command " + cmd); @@ -125,7 +136,7 @@ public class VmopAgentClient extends AgentConnector { } // Error - logger.warning(() -> "Error response: " + line); + logger.warning(() -> "Error response from vmop agent: " + line); executing.pop(); } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java index e35a172..6663fa4 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/MonitorEvent.java @@ -20,6 +20,8 @@ package org.jdrupes.vmoperator.runner.qemu.events; import com.fasterxml.jackson.databind.JsonNode; import java.util.Optional; +import org.jgrapes.core.Channel; +import org.jgrapes.core.Components; import org.jgrapes.core.Event; /** @@ -112,4 +114,20 @@ public class MonitorEvent extends Event { public JsonNode data() { return data; } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(Components.objectName(this)).append(" [").append(data); + if (channels() != null) { + builder.append(", channels=").append(Channel.toString(channels())); + } + builder.append(']'); + return builder.toString(); + } } diff --git a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/OsinfoEvent.java b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/OsinfoEvent.java index 294ac7b..0e90019 100644 --- a/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/OsinfoEvent.java +++ b/org.jdrupes.vmoperator.runner.qemu/src/org/jdrupes/vmoperator/runner/qemu/events/OsinfoEvent.java @@ -19,6 +19,8 @@ package org.jdrupes.vmoperator.runner.qemu.events; import com.fasterxml.jackson.databind.JsonNode; +import org.jgrapes.core.Channel; +import org.jgrapes.core.Components; import org.jgrapes.core.Event; /** @@ -40,4 +42,21 @@ public class OsinfoEvent extends Event { public JsonNode osinfo() { return osinfo; } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append(Components.objectName(this)).append(" [") + .append(osinfo); + if (channels() != null) { + builder.append(", channels=").append(Channel.toString(channels())); + } + builder.append(']'); + return builder.toString(); + } } From 10f3028f06d58d81f6972d5c29fcf8f1dfc698a7 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Wed, 30 Apr 2025 16:27:15 +0200 Subject: [PATCH 334/342] Increase concurrency and avoid race condition. --- .../vmoperator/manager/Controller.java | 3 +- .../jdrupes/vmoperator/manager/VmMonitor.java | 58 +++++++++++++------ 2 files changed, 42 insertions(+), 19 deletions(-) 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 c15acc5..ce14488 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 @@ -50,6 +50,7 @@ import org.jdrupes.vmoperator.manager.events.VmPoolChanged; import org.jdrupes.vmoperator.manager.events.VmResourceChanged; import org.jgrapes.core.Channel; import org.jgrapes.core.Component; +import org.jgrapes.core.EventPipeline; import org.jgrapes.core.annotation.Handler; import org.jgrapes.core.events.HandlingError; import org.jgrapes.core.events.Start; @@ -94,7 +95,7 @@ import org.jgrapes.util.events.ConfigurationUpdate; public class Controller extends Component { private String namespace; - private final ChannelManager chanMgr; + private final ChannelManager chanMgr; /** * Creates a new instance. 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 09bade8..b667aa6 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 @@ -22,7 +22,6 @@ import com.google.gson.JsonObject; import io.kubernetes.client.apimachinery.GroupVersionKind; import io.kubernetes.client.custom.V1Patch; import io.kubernetes.client.openapi.ApiException; -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; @@ -32,7 +31,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Optional; import java.util.Set; -import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Collectors; import org.jdrupes.vmoperator.common.Constants.Crd; import org.jdrupes.vmoperator.common.Constants.Status; @@ -57,16 +55,28 @@ import org.jdrupes.vmoperator.manager.events.VmResourceChanged; import org.jdrupes.vmoperator.util.GsonPtr; import org.jgrapes.core.Channel; import org.jgrapes.core.Event; +import org.jgrapes.core.EventPipeline; import org.jgrapes.core.annotation.Handler; /** - * Watches for changes of VM definitions. + * Watches for changes of VM definitions. When a VM definition (CR) + * becomes known, is is registered with a {@link ChannelManager} and thus + * gets an associated {@link VmChannel} and an associated + * {@link EventPipeline}. + * + * The {@link EventPipeline} is used for submitting an action that processes + * the change data from kubernetes, eventually transforming it to a + * {@link VmResourceChanged} event that is handled by another + * {@link EventPipeline} associated with the {@link VmChannel}. This + * event pipeline should be used for all events related to changes of + * a particular VM. */ @SuppressWarnings({ "PMD.DataflowAnomalyAnalysis", "PMD.ExcessiveImports" }) public class VmMonitor extends AbstractMonitor { - private final ChannelManager channelManager; + private final ChannelManager channelManager; /** * Instantiates a new VM definition watcher. @@ -75,7 +85,7 @@ public class VmMonitor extends * @param channelManager the channel manager */ public VmMonitor(Channel componentChannel, - ChannelManager channelManager) { + ChannelManager channelManager) { super(componentChannel, VmDefinition.class, VmDefinitions.class); this.channelManager = channelManager; @@ -122,14 +132,18 @@ public class VmMonitor extends @Override protected void handleChange(K8sClient client, Watch.Response response) { - V1ObjectMeta metadata = response.object.getMetadata(); - AtomicBoolean toBeAdded = new AtomicBoolean(false); - VmChannel channel = channelManager.channel(metadata.getName()) - .orElseGet(() -> { - toBeAdded.set(true); - return channelManager.createChannel(metadata.getName()); - }); + var name = response.object.getMetadata().getName(); + // Process the response data on a VM specific pipeline to + // increase concurrency when e.g. starting many VMs. + var preparing = channelManager.associated(name) + .orElseGet(() -> newEventPipeline()); + preparing.submit("VmChange[" + name + "]", + () -> processChange(client, response, preparing)); + } + + private void processChange(K8sClient client, + Watch.Response response, EventPipeline preparing) { // Get full definition and associate with channel as backup var vmDef = response.object; if (vmDef.data() == null) { @@ -137,6 +151,9 @@ public class VmMonitor extends // https://github.com/kubernetes-client/java/issues/3215 vmDef = getModel(client, vmDef); } + var name = response.object.getMetadata().getName(); + var channel = channelManager.channel(name) + .orElseGet(() -> channelManager.createChannel(name)); if (vmDef.data() != null) { // New data, augment and save addExtraData(vmDef, channel.vmDefinition()); @@ -150,9 +167,7 @@ public class VmMonitor extends + response.object.getMetadata()); return; } - if (toBeAdded.get()) { - channelManager.put(vmDef.name(), channel); - } + channelManager.put(name, channel, preparing); // Create and fire changed event. Remove channel from channel // manager on completion. @@ -199,9 +214,16 @@ public class VmMonitor extends @Handler public void onPodChanged(PodChanged event, VmChannel channel) { var vmDef = channel.vmDefinition(); - updateNodeInfo(event, vmDef); - channel - .fire(new VmResourceChanged(ResponseType.MODIFIED, vmDef, false, true)); + + // Make sure that this is properly sync'd with VM CR changes. + channelManager.associated(vmDef.name()) + .orElseGet(() -> activeEventPipeline()) + .submit("NodeInfo[" + vmDef.name() + "]", + () -> { + updateNodeInfo(event, vmDef); + channel.fire(new VmResourceChanged(ResponseType.MODIFIED, + vmDef, false, true)); + }); } private void updateNodeInfo(PodChanged event, VmDefinition vmDef) { From a5433c869bb5d25601060200cba2335bf250788a Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sat, 3 May 2025 22:29:42 +0200 Subject: [PATCH 335/342] Upgrade webconsole base library. --- org.jdrupes.vmoperator.manager/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.manager/build.gradle b/org.jdrupes.vmoperator.manager/build.gradle index eda5ce0..4ce4ed0 100644 --- a/org.jdrupes.vmoperator.manager/build.gradle +++ b/org.jdrupes.vmoperator.manager/build.gradle @@ -17,7 +17,7 @@ dependencies { implementation 'org.jgrapes:org.jgrapes.io:[2.12.1,3)' implementation 'org.jgrapes:org.jgrapes.http:[3.5.0,4)' - implementation 'org.jgrapes:org.jgrapes.webconsole.base:[2.2.0,3)' + implementation 'org.jgrapes:org.jgrapes.webconsole.base:[2.3.0,3)' implementation 'org.jgrapes:org.jgrapes.webconsole.vuejs:[1.8.0,2)' implementation 'org.jgrapes:org.jgrapes.webconsole.rbac:[1.4.0,2)' implementation 'org.jgrapes:org.jgrapes.webconlet.oidclogin:[1.7.0,2)' From 76b579c404f4ea691bf5a00cde47ddb8d35b1342 Mon Sep 17 00:00:00 2001 From: "Michael N. Lipp" Date: Sun, 4 May 2025 11:36:55 +0200 Subject: [PATCH 336/342] Add key, allowing vue to optimize. --- .../org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html index 5a28cb8..3197440 100644 --- a/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html +++ b/org.jdrupes.vmoperator.vmmgmt/resources/org/jdrupes/vmoperator/vmmgmt/VmMgmt-view.ftl.html @@ -30,7 +30,7 @@