Merge branch 'master' into local-sudoer-without-pw
This commit is contained in:
commit
52641f8665
14 changed files with 114 additions and 125 deletions
|
@ -46,7 +46,7 @@ test:
|
||||||
- docker build --pull -t "$CI_REGISTRY_IMAGE" .
|
- docker build --pull -t "$CI_REGISTRY_IMAGE" .
|
||||||
- docker run --privileged -dit --name provs_test -v /var/run/docker.sock:/var/run/docker.sock $CI_REGISTRY_IMAGE
|
- docker run --privileged -dit --name provs_test -v /var/run/docker.sock:/var/run/docker.sock $CI_REGISTRY_IMAGE
|
||||||
- docker inspect -f '{{.State.Running}}' provs_test
|
- docker inspect -f '{{.State.Running}}' provs_test
|
||||||
- ./gradlew -x assemble test -Dtestdockerwithoutsudo=true -DexcludeTags=extensivecontainertest
|
- ./gradlew -x assemble test -Dtestdockerwithoutsudo=true -DexcludeTags=extensivecontainertest,nonci
|
||||||
artifacts:
|
artifacts:
|
||||||
when: on_failure
|
when: on_failure
|
||||||
paths:
|
paths:
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
```plantuml
|
|
||||||
@startuml
|
|
||||||
|
|
||||||
autonumber
|
|
||||||
|
|
||||||
skinparam sequenceBox {
|
|
||||||
borderColor White
|
|
||||||
}
|
|
||||||
|
|
||||||
participant User
|
|
||||||
|
|
||||||
box "application" #LightBlue
|
|
||||||
|
|
||||||
participant CliWorkplace
|
|
||||||
participant CliWorkplaceParser
|
|
||||||
participant CliWorkplaceCommand
|
|
||||||
participant Application
|
|
||||||
|
|
||||||
end box
|
|
||||||
|
|
||||||
box #White
|
|
||||||
|
|
||||||
participant CliUtils
|
|
||||||
participant "Prov (local or remote...)" as ProvInstance
|
|
||||||
|
|
||||||
end box
|
|
||||||
|
|
||||||
box "domain" #LightGreen
|
|
||||||
|
|
||||||
participant ProvisionWorkplace
|
|
||||||
|
|
||||||
end box
|
|
||||||
|
|
||||||
box "infrastructure" #CornSilk
|
|
||||||
|
|
||||||
participant ConfigRepository
|
|
||||||
participant "Infrastructure functions" as Infrastructure_functions
|
|
||||||
|
|
||||||
end box
|
|
||||||
|
|
||||||
|
|
||||||
User -> CliWorkplace ++ : main(args...)
|
|
||||||
|
|
||||||
CliWorkplace -> CliWorkplaceParser : parseWorkplaceArguments
|
|
||||||
|
|
||||||
CliWorkplace -> CliWorkplaceCommand : isValid ?
|
|
||||||
|
|
||||||
CliWorkplace -> ConfigRepository : getConfig
|
|
||||||
|
|
||||||
CliWorkplace -> CliUtils : createProvInstance
|
|
||||||
ProvInstance <- CliUtils : create
|
|
||||||
|
|
||||||
CliWorkplace -> Application : provision ( config )
|
|
||||||
Application -> ProvInstance : provisionWorkplace ( type, ssh, ...)
|
|
||||||
ProvInstance -> ProvisionWorkplace : provisionWorkplace
|
|
||||||
|
|
||||||
ProvisionWorkplace -> Infrastructure_functions: Various calls like:
|
|
||||||
ProvisionWorkplace -> Infrastructure_functions: install ssh, gpg, git ...
|
|
||||||
ProvisionWorkplace -> Infrastructure_functions: installVirtualBoxGuestAdditions
|
|
||||||
ProvisionWorkplace -> Infrastructure_functions: configureNoSwappiness, ...
|
|
||||||
|
|
||||||
@enduml
|
|
||||||
```
|
|
39
doc/DesktopCliParsingSequence.md
Normal file
39
doc/DesktopCliParsingSequence.md
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
skinparam sequenceBox {
|
||||||
|
borderColor White
|
||||||
|
}
|
||||||
|
|
||||||
|
participant User
|
||||||
|
|
||||||
|
User -> Application ++ : main(args...)
|
||||||
|
Application -> CliArgumentsParser : create
|
||||||
|
CliArgumentsParser -> ArgParser : subcommands
|
||||||
|
Application -> CliArgumentsParser : parseCommand
|
||||||
|
CliArgumentsParser -> ArgParser : super.parse
|
||||||
|
|
||||||
|
CliArgumentsParser -> CliTargetCommand : create()
|
||||||
|
CliTargetCommand -> CliTargetCommand : parseRemoteTarget
|
||||||
|
alt passwordInteractive == true
|
||||||
|
CliTargetCommand -> PromptSecretSource : prompt-for-password
|
||||||
|
end
|
||||||
|
CliArgumentsParser -> DesktopCliCommand : create(desktopType, cliTargetCmd, ...)
|
||||||
|
CliArgumentsParser --> Application: desktopCliCommand
|
||||||
|
Application -> DesktopCliCommand : isValid ?
|
||||||
|
Application -> CliUtils : createProvInstance
|
||||||
|
ProvInstance <- CliUtils : create
|
||||||
|
alt target.isValidLocal
|
||||||
|
CliUtils -> CliUtils : createLocalProv
|
||||||
|
else target.isValidRemote
|
||||||
|
CliUtils -> CliUtils : createRemote
|
||||||
|
end
|
||||||
|
Application -> DesktopService1 : provisionDesktopCommand ( provInstance, desktopCliCommand )
|
||||||
|
DesktopService1 -> DesktopService2 : provisionDesktop( config )
|
||||||
|
DesktopService1 -> ConfigRepository : getConfig
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
|
||||||
|
```
|
|
@ -29,6 +29,6 @@ The success or failure is computed automatically in the following way:
|
||||||
|
|
||||||
## Call hierarchy
|
## Call hierarchy
|
||||||
|
|
||||||
Find below an example of a sequence diagram when provisioning a desktop workplace:
|
In the following link you can find an example of a sequence diagram when provisioning a desktop:
|
||||||
|
|
||||||
![img.png](resources/provision-workplace-sequence.diagram.png)
|
[ProvisionDesktopSequence.md](ProvisionDesktopSequence.md)
|
||||||
|
|
49
doc/ProvisionDesktopSequence.md
Normal file
49
doc/ProvisionDesktopSequence.md
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
```plantuml
|
||||||
|
@startuml
|
||||||
|
|
||||||
|
autonumber
|
||||||
|
|
||||||
|
skinparam sequenceBox {
|
||||||
|
borderColor White
|
||||||
|
}
|
||||||
|
|
||||||
|
participant User
|
||||||
|
|
||||||
|
box "application" #LightBlue
|
||||||
|
participant Application
|
||||||
|
participant CliArgumentsParser
|
||||||
|
participant DesktopCliCommand
|
||||||
|
end box
|
||||||
|
|
||||||
|
box #White
|
||||||
|
participant CliUtils
|
||||||
|
participant "Prov (local or remote...)" as ProvInstance
|
||||||
|
end box
|
||||||
|
|
||||||
|
box "domain" #LightGreen
|
||||||
|
participant "DesktopService\n.provisionDesktopCommand" as DesktopService1
|
||||||
|
participant "DesktopService\n.provisionDesktop" as DesktopService2
|
||||||
|
end box
|
||||||
|
|
||||||
|
box "infrastructure" #CornSilk
|
||||||
|
participant ConfigRepository
|
||||||
|
participant "Various\ninfrastructure functions" as Infrastructure_functions
|
||||||
|
end box
|
||||||
|
|
||||||
|
|
||||||
|
User -> Application ++ : main(args...)
|
||||||
|
Application -> CliArgumentsParser : parseCommand
|
||||||
|
Application -> DesktopCliCommand : isValid ?
|
||||||
|
Application -> CliUtils : createProvInstance
|
||||||
|
ProvInstance <- CliUtils : create
|
||||||
|
Application -> DesktopService1 : provisionDesktopCommand ( provInstance, desktopCliCommand )
|
||||||
|
DesktopService1 -> ConfigRepository : getConfig
|
||||||
|
DesktopService1 -> DesktopService2 : provisionDesktop( config )
|
||||||
|
|
||||||
|
DesktopService2 -> Infrastructure_functions: Various calls like:
|
||||||
|
DesktopService2 -> Infrastructure_functions: install ssh, gpg, git ...
|
||||||
|
DesktopService2 -> Infrastructure_functions: installVirtualBoxGuestAdditions
|
||||||
|
DesktopService2 -> Infrastructure_functions: configureNoSwappiness, ...
|
||||||
|
|
||||||
|
@enduml
|
||||||
|
```
|
|
@ -28,45 +28,3 @@ In the following document we describe how we implement idempotence:
|
||||||
|
|
||||||
https://gitlab.com/domaindrivenarchitecture/overview/-/blob/master/adr-provs/quasi-idempotence.md
|
https://gitlab.com/domaindrivenarchitecture/overview/-/blob/master/adr-provs/quasi-idempotence.md
|
||||||
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
Multiple architectural layers provide different levels of functionality:
|
|
||||||
|
|
||||||
![provs layers](resources/provs-architecture-7.png "Provs architecture")
|
|
||||||
|
|
||||||
|
|
||||||
## Module structure
|
|
||||||
|
|
||||||
For the modules we use domain-drive design according to:
|
|
||||||
|
|
||||||
https://gitlab.com/domaindrivenarchitecture/overview/-/blob/master/adr-provs/ddd-structure.md
|
|
||||||
|
|
||||||
## Module dependencies
|
|
||||||
|
|
||||||
![resources/prov-module-dependencies-5b.png](resources/prov-module-dependencies-5b.png)
|
|
||||||
|
|
||||||
__Explanation__:
|
|
||||||
|
|
||||||
Modules:
|
|
||||||
|
|
||||||
<ol type="A">
|
|
||||||
<li>Common module: has both a domain layer and an infrastructure layer</li>
|
|
||||||
<li>Module with only domain layer: e.g. for very simple logic where no infrastructure layer is needed</li>
|
|
||||||
<li>Module with only infrastructure layer: these are often _utility modules_, which provide a collection of utility functions</li>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
Dependencies:
|
|
||||||
|
|
||||||
1. Domain layer calls (a function in) the infrastructure layer of the same module
|
|
||||||
* _Common practice of dependencies within a module_
|
|
||||||
1. Domain layer calls (a function in) the domain layer another module
|
|
||||||
* _Common practice of dependencies between modules_
|
|
||||||
1. Base layer calls domain layer
|
|
||||||
* _Usually not recommended!_
|
|
||||||
4. Domain layer calls infrastructure layer in another module
|
|
||||||
* _This sometimes can make sense, e.g. if module B just needs some low-level function of module D instead of full provisioning.
|
|
||||||
However, in most cases it is recommended to call the domain layer of module D whenever possible_
|
|
||||||
5. Domain layer calls infrastructure layer in another module, which only has infrastructure layer
|
|
||||||
* _Common practice for calling utility modules, which don't have a domain layer._
|
|
||||||
|
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 33 KiB |
Binary file not shown.
Before Width: | Height: | Size: 51 KiB |
Binary file not shown.
Before Width: | Height: | Size: 100 KiB |
|
@ -3,7 +3,6 @@ package org.domaindrivenarchitecture.provs.configuration.application
|
||||||
import kotlinx.cli.ArgParser
|
import kotlinx.cli.ArgParser
|
||||||
import kotlinx.cli.ArgType
|
import kotlinx.cli.ArgType
|
||||||
import kotlinx.cli.default
|
import kotlinx.cli.default
|
||||||
import org.domaindrivenarchitecture.provs.configuration.domain.TargetCliCommand
|
|
||||||
|
|
||||||
open class CliTargetParser(name: String) : ArgParser(name) {
|
open class CliTargetParser(name: String) : ArgParser(name) {
|
||||||
val target by argument(
|
val target by argument(
|
||||||
|
@ -17,13 +16,3 @@ open class CliTargetParser(name: String) : ArgParser(name) {
|
||||||
"prompt for password for remote target",
|
"prompt for password for remote target",
|
||||||
).default(false)
|
).default(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun parseTarget(
|
|
||||||
programName: String = "provs",
|
|
||||||
args: Array<String>
|
|
||||||
): TargetCliCommand {
|
|
||||||
val parser = CliTargetParser(programName)
|
|
||||||
parser.parse(args)
|
|
||||||
|
|
||||||
return TargetCliCommand(parser.target, parser.passwordInteractive)
|
|
||||||
}
|
|
|
@ -25,12 +25,14 @@ open class CliArgumentsParser(name: String) : CliTargetParser(name) {
|
||||||
|
|
||||||
val module = modules.first { it.parsed }
|
val module = modules.first { it.parsed }
|
||||||
|
|
||||||
return DesktopCliCommand(
|
val targetCliCommand = TargetCliCommand(
|
||||||
DesktopType.valueOf(module.name.uppercase()),
|
|
||||||
TargetCliCommand(
|
|
||||||
target,
|
target,
|
||||||
passwordInteractive
|
passwordInteractive
|
||||||
),
|
)
|
||||||
|
|
||||||
|
return DesktopCliCommand(
|
||||||
|
DesktopType.valueOf(module.name.uppercase()),
|
||||||
|
targetCliCommand,
|
||||||
module.configFileName,
|
module.configFileName,
|
||||||
module.onlyModules
|
module.onlyModules
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,9 +1,21 @@
|
||||||
package org.domaindrivenarchitecture.provs.configuration.application
|
package org.domaindrivenarchitecture.provs.configuration.application
|
||||||
|
|
||||||
|
import org.domaindrivenarchitecture.provs.configuration.domain.TargetCliCommand
|
||||||
import org.junit.jupiter.api.Assertions.*
|
import org.junit.jupiter.api.Assertions.*
|
||||||
import org.junit.jupiter.api.Disabled
|
import org.junit.jupiter.api.Disabled
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
|
||||||
|
private fun parseTarget(
|
||||||
|
args: Array<String>
|
||||||
|
): TargetCliCommand {
|
||||||
|
val parser = CliTargetParser("provs")
|
||||||
|
|
||||||
|
parser.parse(args)
|
||||||
|
|
||||||
|
return TargetCliCommand(parser.target, parser.passwordInteractive)
|
||||||
|
}
|
||||||
|
|
||||||
internal class CliTargetParserTest {
|
internal class CliTargetParserTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.domaindrivenarchitecture.provs.framework.core.cli.getPasswordToConfig
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.local
|
import org.domaindrivenarchitecture.provs.framework.core.local
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.processors.PrintOnlyProcessor
|
import org.domaindrivenarchitecture.provs.framework.core.processors.PrintOnlyProcessor
|
||||||
import org.domaindrivenarchitecture.provs.framework.core.remote
|
import org.domaindrivenarchitecture.provs.framework.core.remote
|
||||||
|
import org.domaindrivenarchitecture.provs.test.tags.NonCi
|
||||||
import org.junit.jupiter.api.AfterAll
|
import org.junit.jupiter.api.AfterAll
|
||||||
import org.junit.jupiter.api.BeforeAll
|
import org.junit.jupiter.api.BeforeAll
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
@ -39,6 +40,7 @@ internal class CliTargetCommandKtTest {
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@NonCi
|
||||||
fun createProvInstance_local() {
|
fun createProvInstance_local() {
|
||||||
// given
|
// given
|
||||||
val cliCommand = TargetCliCommand("local", false)
|
val cliCommand = TargetCliCommand("local", false)
|
||||||
|
|
|
@ -6,7 +6,7 @@ import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
private const val CONTAINER_TEST = "containertest"
|
private const val CONTAINER_TEST = "containertest"
|
||||||
private const val EXTENSIVE_CONTAINER_TEST = "extensivecontainertest"
|
private const val EXTENSIVE_CONTAINER_TEST = "extensivecontainertest"
|
||||||
private const val CONTAINER_TEST_NON_CI = "containernonci"
|
private const val NON_CI = "nonci"
|
||||||
|
|
||||||
|
|
||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||||
|
@ -28,6 +28,7 @@ annotation class ExtensiveContainerTest
|
||||||
|
|
||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
|
||||||
@Retention
|
@Retention
|
||||||
@Tag(CONTAINER_TEST_NON_CI)
|
@Tag(NON_CI)
|
||||||
@Test
|
@Test
|
||||||
|
// For test which do not run in ci pipeline
|
||||||
annotation class NonCi
|
annotation class NonCi
|
Loading…
Reference in a new issue