Merge branch 'master' into improve-input-validation

# Conflicts:
#	src/main/kotlin/org/domaindrivenarchitecture/provs/server/application/CliArgumentsParser.kt
#	src/main/kotlin/org/domaindrivenarchitecture/provs/server/domain/k3s/K3sCliCommand.kt
#	src/main/kotlin/org/domaindrivenarchitecture/provs/server/domain/k3s/K3sService.kt
This commit is contained in:
az 2022-08-30 15:40:28 +02:00
commit 5a7e5a8535
9 changed files with 106 additions and 44 deletions

View file

@ -5,17 +5,12 @@
## Purpose ## Purpose
provs provides cli-based tooling for provisioning desktop or server resp. perform system checks. provs provides cli-based tools for
* provs-desktop minimal - provides a minimal setup (e.g. swappiness / randomutils) e.g. for setup on a VirtualBox * provisioning a desktop (various kinds)
* provs-desktop office - provides enhancements like zim / gopass / fakturama * provisioning a k3s server
* provs-desktop ide - provides development environments for java / kotlin / python / clojure / terraform * performing system checks
* provs-server k3s - provides a production ready & k3s setup with dualstack option
* provs-syspec - verifies a system according to the provided system spec config file
In general provs combines Tasks can be run locally or remotely.
* being able to use the power of shell commands
* a clear and detailed result summary of the built-in execution handling (incl. failure handling and reporting)
* the convenience and robustness of a modern programming language
## Status ## Status
@ -26,11 +21,24 @@ under development - we are working hard on setting up our environments using pro
* A **Java Virtual machine** (JVM) is required. * A **Java Virtual machine** (JVM) is required.
* Install `jarwrapper` (e.g. `sudo apt install jarwrapper`) * Install `jarwrapper` (e.g. `sudo apt install jarwrapper`)
* Download the latest `provs-desktop.jar` from: https://gitlab.com/domaindrivenarchitecture/provs/-/releases * Then either download the binaries or build them yourself
* Make the jar-file executable by `chmod +x provs-desktop.jar`
* For server functionality (e.g. k3s) download the latest `provs-server.jar` from: https://gitlab.com/domaindrivenarchitecture/provs/-/releases
### provs-desktop #### Download the binaries
* Download the latest `provs-desktop.jar`,`provs-server.jar` and/or `provs-syspec.jar` from: https://gitlab.com/domaindrivenarchitecture/provs/-/releases
* Preferably into `/usr/local/bin` or any other folder where executables can be found by the system
* Make the jar-file executable e.g. by `chmod +x provs-desktop.jar`
#### Build the binaries
Instead of downloading the binaries you can build them yourself
* Clone this repository
* In the repository's root folder execute: `./gradlew install`. This will install the binaries in `/usr/local/bin`
### Provision a desktop
After having installed `provs-desktop.jar` (see prerequisites) execute:
`provs-desktop.jar <type> <target> [<options>]` `provs-desktop.jar <type> <target> [<options>]`
@ -41,7 +49,9 @@ under development - we are working hard on setting up our environments using pro
**target** can be: **target** can be:
* `local` * `local`
* `user123:mypassword@myhost.com` - general format is: <user[:password]@host> - * remote, e.g. `user123:mypassword@myhost.com` - general format is: <user[:password]@host> -
* be sure to have openssh-server installed
* add your preferred public key to known_hosts on the target machine
* if password is omitted, then ssh-keys will be used for authentication * if password is omitted, then ssh-keys will be used for authentication
* if password is omitted but option `-p` is provided, then the password will be prompted interactively * if password is omitted but option `-p` is provided, then the password will be prompted interactively
@ -49,7 +59,7 @@ under development - we are working hard on setting up our environments using pro
* `-p` for interactive password question * `-p` for interactive password question
#### Provision a desktop #### Example
```bash ```bash
provs-desktop.jar basic local provs-desktop.jar basic local
@ -57,9 +67,9 @@ provs-desktop.jar basic local
provs-desktop.jar office myuser@myhost.com -p provs-desktop.jar office myuser@myhost.com -p
``` ```
In the last case you'll be prompted for the password of the remote user due to option `-p`. In the second case you'll be prompted for the password of the remote user due to option `-p`.
### Provision k3s ### Provision a k3s Server
```bash ```bash
provs-server.jar k3s local provs-server.jar k3s local
@ -67,7 +77,8 @@ provs-server.jar k3s local
provs-server.jar k3s myuser@myhost.com # using ssh-authentication - alternatively use option -p for password authentication provs-server.jar k3s myuser@myhost.com # using ssh-authentication - alternatively use option -p for password authentication
``` ```
For the remote server please configure a config file (default file name: server-config.yaml) For the remote server please configure a config file (default file name: server-config.yaml).
It has to be in the same folder where you execute the provs-server.jar command.
```yaml ```yaml
fqdn: "myhostname.com" fqdn: "myhostname.com"
node: node:
@ -94,14 +105,14 @@ provs-server.jar k3s myuser@myhost.com -o grafana
### Performing a system check ### Perform a system check
The default config-file for the system check is `syspec-config.yaml`, you can specify a different file with option `-c <config-file>`. The default config-file for the system check is `syspec-config.yaml`, you can specify a different file with option `-c <config-file>`.
```bash ```bash
provs-syspec.jar local provs-syspec.jar local
# or remote: # or remote with a custom config filename
provs-syspec.jar myuser@myhost.com provs-syspec.jar myuser@myhost.com -c my-syspec-config.yaml
``` ```
## Get help ## Get help

View file

@ -18,7 +18,7 @@ apply plugin: "kotlinx-serialization"
group = "org.domaindrivenarchitecture.provs" group = "org.domaindrivenarchitecture.provs"
version = "0.15.3-SNAPSHOT" version = "0.15.4-SNAPSHOT"
repositories { repositories {
mavenCentral() mavenCentral()

View file

@ -24,7 +24,7 @@ open class CliArgumentsParser(name: String) : CliTargetParser(name) {
val module = modules.first { it.parsed } val module = modules.first { it.parsed }
return DesktopCliCommand( return DesktopCliCommand(
DesktopType.returnIfExists(module.name.uppercase()), DesktopType.valueOf(module.name.uppercase()),
TargetCliCommand( TargetCliCommand(
target, target,
passwordInteractive passwordInteractive

View file

@ -4,9 +4,8 @@ package org.domaindrivenarchitecture.provs.desktop.domain
/** /**
* Provides desktop types. For each type a different set of software and packages is installed, see README.md. * Provides desktop types. For each type a different set of software and packages is installed, see README.md.
*/ */
open class DesktopType(val name: String) { // Uses a regular class instead of an enum class in order to allow subclasses which can add new DesktopTypes
open class DesktopType protected constructor(val name: String) {
// A regular class is used rather than enum class in order to allow extending DesktopType by subclassing.
companion object { companion object {
@ -17,7 +16,11 @@ open class DesktopType(val name: String) {
@JvmStatic @JvmStatic
protected val values = listOf(BASIC, OFFICE, IDE) protected val values = listOf(BASIC, OFFICE, IDE)
fun returnIfExists(value: String, valueList: List<DesktopType> = values): DesktopType { @JvmStatic
fun valueOf(value: String): DesktopType = valueOf(value, values)
@JvmStatic
protected fun valueOf(value: String, valueList: List<DesktopType>): DesktopType {
for (type in valueList) { for (type in valueList) {
if (value.uppercase().equals(type.name)) { if (value.uppercase().equals(type.name)) {
return type return type
@ -31,4 +34,3 @@ open class DesktopType(val name: String) {
return name return name
} }
} }

View file

@ -11,7 +11,7 @@ import org.domaindrivenarchitecture.provs.framework.ubuntu.web.base.downloadFrom
fun Prov.downloadGopassBridge() = task { fun Prov.downloadGopassBridge() = task {
val version = "0.8.0" val version = "0.9.0"
val filename = "gopass_bridge-${version}-fx.xpi" val filename = "gopass_bridge-${version}-fx.xpi"
val downloadDir = "${userHome()}Downloads/" val downloadDir = "${userHome()}Downloads/"
@ -25,10 +25,10 @@ fun Prov.downloadGopassBridge() = task {
fun Prov.installGopassBridgeJsonApi() = task { fun Prov.installGopassBridgeJsonApi() = task {
// see https://github.com/gopasspw/gopass-jsonapi // see https://github.com/gopasspw/gopass-jsonapi
val gopassBridgeVersion = "1.11.1" val gopassJsonApiVersion = "1.14.3"
val requiredGopassVersion = "1.12" val requiredGopassVersion = "1.14.4"
val filename = "gopass-jsonapi_${gopassBridgeVersion}_linux_amd64.deb" val filename = "gopass-jsonapi_${gopassJsonApiVersion}_linux_amd64.deb"
val downloadUrl = "-L https://github.com/gopasspw/gopass-jsonapi/releases/download/v$gopassBridgeVersion/$filename" val downloadUrl = "-L https://github.com/gopasspw/gopass-jsonapi/releases/download/v$gopassJsonApiVersion/$filename"
val downloadDir = "${userHome()}Downloads" val downloadDir = "${userHome()}Downloads"
val installedJsonApiVersion = gopassJsonApiVersion()?.trim() val installedJsonApiVersion = gopassJsonApiVersion()?.trim()
@ -55,13 +55,13 @@ fun Prov.installGopassBridgeJsonApi() = task {
) )
} }
} else { } else {
if (installedJsonApiVersion.startsWith("gopass-jsonapi version " + gopassBridgeVersion)) { if (installedJsonApiVersion.startsWith("gopass-jsonapi version " + gopassJsonApiVersion)) {
addResultToEval(ProvResult(true, out = "Version $gopassBridgeVersion of gopass-jsonapi is already installed")) addResultToEval(ProvResult(true, out = "Version $gopassJsonApiVersion of gopass-jsonapi is already installed"))
} else { } else {
addResultToEval( addResultToEval(
ProvResult( ProvResult(
false, false,
err = "gopass-jsonapi (version $gopassBridgeVersion) cannot be installed as version $installedJsonApiVersion is already installed." + err = "gopass-jsonapi (version $gopassJsonApiVersion) cannot be installed as version $installedJsonApiVersion is already installed." +
" Upgrading gopass-jsonapi is currently not supported by provs." " Upgrading gopass-jsonapi is currently not supported by provs."
) )
) )

View file

@ -34,7 +34,7 @@ class CliArgumentsParser(name: String) : CliTargetParser(name) {
), ),
module.configFileName, module.configFileName,
module.applicationFileName, module.applicationFileName,
module.submodules, module.submodules
) )
else -> return ServerCliCommand( else -> return ServerCliCommand(
ServerType.valueOf(module.name.uppercase()), ServerType.valueOf(module.name.uppercase()),
@ -73,6 +73,7 @@ class CliArgumentsParser(name: String) : CliTargetParser(name) {
"o", "o",
"provisions only parts ", "provisions only parts ",
) )
override fun execute() { override fun execute() {
super.configFileName = cliConfigFileName?.let { ConfigFileName(it) } super.configFileName = cliConfigFileName?.let { ConfigFileName(it) }
super.applicationFileName = cliApplicationFileName?.let { ApplicationFileName(it) } super.applicationFileName = cliApplicationFileName?.let { ApplicationFileName(it) }

View file

@ -4,18 +4,15 @@ import org.domaindrivenarchitecture.provs.configuration.domain.ConfigFileName
import org.domaindrivenarchitecture.provs.configuration.domain.TargetCliCommand import org.domaindrivenarchitecture.provs.configuration.domain.TargetCliCommand
import org.domaindrivenarchitecture.provs.server.domain.ServerCliCommand import org.domaindrivenarchitecture.provs.server.domain.ServerCliCommand
import org.domaindrivenarchitecture.provs.server.domain.ServerType import org.domaindrivenarchitecture.provs.server.domain.ServerType
import org.domaindrivenarchitecture.provs.server.infrastructure.genericFileExistenceCheck
class K3sCliCommand( class K3sCliCommand(
serverType: ServerType, serverType: ServerType,
target: TargetCliCommand, target: TargetCliCommand,
configFileName: ConfigFileName?, configFileName: ConfigFileName?,
val applicationFileName: ApplicationFileName?, val applicationFileName: ApplicationFileName?,
val submodules: List<String>? = null, val submodules: List<String>? = null
) : ServerCliCommand( ) : ServerCliCommand(
serverType, serverType,
target, target,
configFileName configFileName
) { )
}

View file

@ -63,7 +63,7 @@ private fun Prov.provisionGrafanaSanitized(
submodules: List<String>?, submodules: List<String>?,
grafanaConfigResolved: GrafanaAgentConfigResolved?) = task { grafanaConfigResolved: GrafanaAgentConfigResolved?) = task {
if (submodules!!.contains(ServerSubmodule.GRAFANA.name.lowercase())) { if (submodules != null && submodules.contains(ServerSubmodule.GRAFANA.name.lowercase())) {
if (grafanaConfigResolved == null) { if (grafanaConfigResolved == null) {
println("ERROR: Could not find grafana config.") println("ERROR: Could not find grafana config.")
exitProcess(7) exitProcess(7)

View file

@ -0,0 +1,51 @@
package org.domaindrivenarchitecture.provs.desktop.domain
import org.domaindrivenarchitecture.provs.desktop.domain.DesktopType.Companion.BASIC
import org.domaindrivenarchitecture.provs.desktop.domain.DesktopType.Companion.IDE
import org.domaindrivenarchitecture.provs.desktop.domain.SubDesktopType.Companion.SUBTYPE
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Assertions.*
// tests subclassing of DesktopType
internal open class SubDesktopType protected constructor(name: String) : DesktopType(name) {
companion object {
// defines a new DesktopType
val SUBTYPE = SubDesktopType("SUBTYPE")
private val values = DesktopType.values + SUBTYPE
fun valueOf(value: String): DesktopType {
return valueOf(value, values)
}
}
}
internal class DesktopTypeTest {
@Test
fun test_valueOf() {
assertEquals(BASIC, DesktopType.valueOf("basic"))
assertEquals(BASIC, DesktopType.valueOf("Basic"))
assertEquals(IDE, DesktopType.valueOf("IDE"))
val exception = assertThrows(RuntimeException::class.java) {
DesktopType.valueOf("subtype")
}
assertEquals("No DesktopType found for value: subtype", exception.message)
}
@Test
fun test_valueOf_in_subclass() {
assertEquals(SUBTYPE, SubDesktopType.valueOf("subtype"))
assertEquals(BASIC, SubDesktopType.valueOf("basic"))
assertNotEquals(SUBTYPE, DesktopType.valueOf("basic"))
val exception = assertThrows(RuntimeException::class.java) {
DesktopType.valueOf("subtype2")
}
assertEquals("No DesktopType found for value: subtype2", exception.message)
}
}