Merge branch 'master' into local-sudoer-without-pw

This commit is contained in:
az 2023-02-26 20:03:58 +01:00
commit 52641f8665
14 changed files with 114 additions and 125 deletions

View file

@ -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:

View file

@ -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
```

View 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
```

View file

@ -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)

View 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
```

View file

@ -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

View file

@ -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)
}

View file

@ -25,12 +25,14 @@ open class CliArgumentsParser(name: String) : CliTargetParser(name) {
val module = modules.first { it.parsed } val module = modules.first { it.parsed }
val targetCliCommand = TargetCliCommand(
target,
passwordInteractive
)
return DesktopCliCommand( return DesktopCliCommand(
DesktopType.valueOf(module.name.uppercase()), DesktopType.valueOf(module.name.uppercase()),
TargetCliCommand( targetCliCommand,
target,
passwordInteractive
),
module.configFileName, module.configFileName,
module.onlyModules module.onlyModules
) )

View file

@ -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

View file

@ -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)

View file

@ -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