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:
commit
5a7e5a8535
9 changed files with 106 additions and 44 deletions
55
README.md
55
README.md
|
@ -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
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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."
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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
|
||||||
) {
|
)
|
||||||
|
|
||||||
}
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue