Compare commits

..

24 commits

Author SHA1 Message Date
2682cca424 Update with real local dev options 2024-06-27 16:23:34 +02:00
edbe56055d Empty 2024-06-27 16:23:16 +02:00
d6a1f2b655 Update command for live exec 2024-06-27 16:23:01 +02:00
eb18eb03bc Add todo 2024-06-27 16:22:22 +02:00
8c8219b5fa Sleep 3 secs 2024-06-27 15:40:05 +02:00
24579506ae Linting 2024-06-27 14:24:53 +02:00
07169c5b3d Remove todos 2024-06-27 14:19:27 +02:00
872b29179e Update tests 2024-06-27 14:19:19 +02:00
a0dbb79d30 Add initial tests 2024-06-27 12:43:51 +02:00
26da85487f Add TODOs 2024-06-27 12:43:38 +02:00
d6b6cb7a72 Lint 2024-06-27 12:43:24 +02:00
ff61ff383e Rename to backend 2024-06-27 11:48:17 +02:00
170d9bc6d0 Implement missing methods 2024-06-27 11:42:09 +02:00
7f2c78ba97 Remove unused import, arguments 2024-06-27 11:41:42 +02:00
e72ac8882e Rename for better semantics 2024-06-27 11:40:01 +02:00
de23855d65 All upper case TODO 2024-06-27 11:39:45 +02:00
a6b6a6b8bc Typo 2024-06-27 10:18:44 +02:00
9cdd647514 Add resource files 2024-06-26 16:52:59 +02:00
f9f2389c95 Update provider with correct vars 2024-06-26 16:52:40 +02:00
ce9d3fdee6 Pass env credentials to start command 2024-06-26 16:52:04 +02:00
4eadad3940 Rename to TERRAFORM_BACKEND_GIT 2024-06-26 15:25:34 +02:00
6e5275b56b Implement backend git api and respective checks 2024-06-26 15:23:20 +02:00
14db8bed54 Adhere to naming convention 2024-06-26 13:12:08 +02:00
4539b84d6c WIP implement tf backend git provider 2024-06-26 10:35:53 +02:00
38 changed files with 249 additions and 174 deletions

View file

@ -87,3 +87,10 @@ kotlin-image-publish:
stage: image
script:
- cd infrastructure/kotlin && pyb image publish
backup-image-publish:
<<: *img
<<: *tag_only
stage: image
script:
- cd infrastructure/backup && pyb image publish

View file

@ -1,6 +1,6 @@
# dda-devops-build
[![Slack](https://img.shields.io/badge/chat-clojurians-green.svg?style=flat)](https://clojurians.slack.com/messages/#dda-pallet/) | [<img src="https://domaindrivenarchitecture.org/img/delta-chat.svg" width=20 alt="DeltaChat"> chat over e-mail](mailto:buero@meissa-gmbh.de?subject=community-chat) | [<img src="https://meissa.de/images/parts/contact/mastodon36_hue9b2464f10b18e134322af482b9c915e_5501_filter_14705073121015236177.png" width=20 alt="M"> meissa@social.meissa-gmbh.de](https://social.meissa-gmbh.de/@meissa) | [Blog](https://domaindrivenarchitecture.org) | [Website](https://meissa.de)
[![Slack](https://img.shields.io/badge/chat-clojurians-green.svg?style=flat)](https://clojurians.slack.com/messages/#dda-pallet/) | [<img src="https://meissa-gmbh.de/img/community/Mastodon_Logotype.svg" width=20 alt="team@social.meissa-gmbh.de"> team@social.meissa-gmbh.de](https://social.meissa-gmbh.de/@team) | [Website & Blog](https://domaindrivenarchitecture.org)
dda-devops-build integrates all the tools we use to work with clouds & provide some nice functions around.

View file

@ -33,7 +33,7 @@ default_task = "dev"
name = "ddadevops"
MODULE = "not-used"
PROJECT_ROOT_PATH = "."
version = "4.13.2-dev"
version = "4.12.1-dev"
summary = "tools to support builds combining gopass, terraform, dda-pallet, aws & hetzner-cloud"
description = __doc__
authors = [Author("meissa GmbH", "buero@meissa-gmbh.de")]
@ -97,6 +97,7 @@ def initialize(project):
"mixin_types": ["RELEASE"],
"release_primary_build_file": "build.py",
"release_secondary_build_files": [
"infrastructure/backup/build.py",
"infrastructure/python/build.py",
"infrastructure/dind/build.py",
"infrastructure/ddadevops/build.py",
@ -140,7 +141,13 @@ def lint(project):
shell=True,
check=True,
)
run(
"pylint -d W0511,R0903,C0301,W0614,C0114,C0115,C0116,similarities,W1203,W0702,W0702,"
+ "R0913,R0902,R0914,R1732,R1705,W0707,C0123,W0703,C0103 src/main/python/ddadevops/",
shell=True,
check=True,
)
@task
def patch(project):

View file

@ -35,7 +35,6 @@ classDiagram
| release_organisation | Optional: The repository organisation name | |
| release_repository_name | Optional: The repository name name | |
| release_artifacts | Optional: The list of artifacts to publish to the release generated name | [] |
| release_tag_prefix | Optional: Prefix of tag | "" |
## Example Usage just for creating releases

View file

@ -1,15 +1,26 @@
# Dev Setup
## For local development
# For local development
```
```bash
python3 -m venv ~/.venv --upgrade
source ~/.venv/bin/activate
pip3 install --upgrade -r dev_requirements.txt
pip3 install --upgrade -r requirements.txt
```
# For testing a dev version
```
## For testing a dev version
With uploading to pypi
```bash
pyb publish upload
pip3 install --upgrade ddadevops --pre
```
With locally installing the package
```bash
pyb publish
pip3 install --upgrade -e /home/${USER}/repo/opensource/dda-devops-build/target/dist/ddadevops-4.12.1-dev/
```

View file

@ -7,7 +7,7 @@ import logging
name = 'dda-backup'
MODULE = 'NOT_SET'
PROJECT_ROOT_PATH = '../..'
version = "4.12.2-dev"
version = "4.12.1-dev"
@init
@ -38,11 +38,6 @@ def image(project):
build = get_devops_build(project)
build.image()
@task
def test(project):
build = get_devops_build(project)
build.test()
@task
def drun(project):
build = get_devops_build(project)

View file

@ -42,7 +42,6 @@ function backup-fs-from-directory() {
}
# Das tut so nicht!
function restore-directory() {
local directory="$1"; shift
local snapshot_id="${1:-latest}"; shift

View file

@ -1,7 +0,0 @@
FROM dda-backup:latest
# install it
RUN apt update && apt install -qqy openjdk-17-jre-headless
ADD resources /tmp/
RUN rm -rf /root/.m2
RUN /tmp/install-test.bb

View file

@ -1,4 +0,0 @@
{:deps {org.clojure/spec.alpha {:mvn/version "0.4.233"}
orchestra/orchestra {:mvn/version "2021.01.01-1"}
org.domaindrivenarchitecture/dda-backup {:mvn/version "0.1.1-SNAPSHOT"}}}

View file

@ -1,32 +0,0 @@
#!/usr/bin/env bb
(require '[babashka.tasks :as tasks])
(defn curl-and-check!
[filename artifact-url sha256-url]
(let [filepath (str "/tmp/" filename)]
(tasks/shell "curl" "-SsLo" filepath artifact-url)
(tasks/shell "curl" "-SsLo" "/tmp/checksum" sha256-url)
(tasks/shell "bash" "-c" (str "echo \" " filepath "\"|tee -a /tmp/checksum"))
;(tasks/shell "sha256sum" "-c" "--status" "/tmp/checksum")
))
(defn tar-install!
[filename binname]
(let [filepath (str "/tmp/" filename)]
(tasks/shell "tar" "-C" "/tmp" "-xzf" filepath)
(tasks/shell "install" "-m" "0700" "-o" "root" "-g" "root" (str "/tmp/" binname) "/usr/local/bin/")))
(defn install!
[filename]
(tasks/shell "install" "-m" "0700" "-o" "root" "-g" "root" (str "/tmp/" filename) "/usr/local/bin/"))
(tasks/shell "bb" "/tmp/test.bb")
(curl-and-check!
"provs-syspec.jar"
"https://repo.prod.meissa.de/attachments/0a1da41e-aa5b-4a3e-a3b1-215cf2d5b021"
"https://repo.prod.meissa.de/attachments/f227cf65-cb0f-46a7-a6cd-28f46917412a")
(install! "provs-syspec.jar")
(tasks/shell "apt" "update")
(tasks/shell "apt" "install" "-qqy" "openjdk-17-jre-headless")
(tasks/shell "java" "-jar" "/usr/local/bin/provs-syspec.jar" "local" "-c" "/tmp/spec.yml" )

View file

@ -1,7 +0,0 @@
package:
- name: "restic"
command:
- command: "bb -h"
- command: "/tmp/test.bb"

View file

@ -1,27 +0,0 @@
#!/usr/bin/env bb
(require '[babashka.tasks :as tasks]
'[dda.backup.management :as mgm])
(defn restic-repo-init!
[]
(spit "restic-pwd" "ThePassword")
(mgm/init! {:password-file "restic-pwd"
:restic-repository "restic-repo"}))
(defn restic-backup!
[]
(tasks/shell "mkdir" "test-backup")
(spit "test-backup/file" "I was here")
(tasks/shell "restic" "backup" "--password-file" "restic-pwd" "--repo" "restic-repo" "test-backup"))
(defn restic-restore!
[]
(tasks/shell "mkdir" "test-restore")
(tasks/shell "restic" "restore" "--password-file" "restic-pwd" "--repo" "restic-repo" "--target" "test-restore" "latest")
)
(restic-repo-init!)
(restic-backup!)
(restic-restore!)

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = "ddadevops"
MODULE = "clj-cljs"
PROJECT_ROOT_PATH = "../.."
version = "4.13.2-dev"
version = "4.12.1-dev"
@init
def initialize(project):

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = "ddadevops"
MODULE = "clj"
PROJECT_ROOT_PATH = "../.."
version = "4.13.2-dev"
version = "4.12.1-dev"
@init
def initialize(project):

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = "ddadevops"
MODULE = "ddadevops"
PROJECT_ROOT_PATH = "../.."
version = "4.13.2-dev"
version = "4.12.1-dev"
@init

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = "ddadevops"
MODULE = "dind"
PROJECT_ROOT_PATH = "../.."
version = "4.13.2-dev"
version = "4.12.1-dev"
@init

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = "ddadevops"
MODULE = "kotlin"
PROJECT_ROOT_PATH = "../.."
version = "4.13.2-dev"
version = "4.12.1-dev"
@init

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = "ddadevops"
MODULE = "python"
PROJECT_ROOT_PATH = "../.."
version = "4.13.2-dev"
version = "4.12.1-dev"
@init

View file

@ -53,8 +53,7 @@ class ReleaseService:
bump_version = release_version.create_bump()
release_message = f"release: {release_version.to_string()}"
bump_message = f"bump version to: {bump_version.to_string()}"
release_tag = f"{release.release_tag_prefix}{release_version.to_string()}"
self.git_api.tag_annotated(release_tag, release_message, 0)
self.git_api.tag_annotated(release_version.to_string(), release_message, 0)
self.__set_version_and_commit__(
bump_version,
release.build_files(),

View file

@ -3,17 +3,18 @@ from dda_python_terraform import Terraform, IsFlagged
from packaging import version
from ..domain import Devops, BuildType
from ..infrastructure import FileApi, ResourceApi, TerraformApi
from ..infrastructure import FileApi, ResourceApi, TerraformApi, TerraformBackendGitApi
# TODO: mv more fkt to Terraform_api ?
class TerraformService:
def __init__(
self, file_api: FileApi, resource_api: ResourceApi, terraform_api: TerraformApi
self, file_api: FileApi, resource_api: ResourceApi, terraform_api: TerraformApi, tf_backend_api: TerraformBackendGitApi
):
self.file_api = file_api
self.resource_api = resource_api
self.terraform_api = terraform_api
self.tf_backend_git_api = tf_backend_api
@classmethod
def prod(cls):
@ -21,6 +22,7 @@ class TerraformService:
FileApi(),
ResourceApi(),
TerraformApi(),
TerraformBackendGitApi(),
)
def initialize_build_dir(self, devops: Devops):
@ -35,6 +37,15 @@ class TerraformService:
self.file_api.cp("*.tfvars", devops.build_path(), check=False)
self.file_api.cp_recursive("scripts", devops.build_path(), check=False)
def start_tf_backend_git_daemon(self, devops: Devops):
terraform_domain = devops.specialized_builds[BuildType.TERRAFORM]
credentials = terraform_domain.env_credentials()
self.tf_backend_git_api.start(credentials)
def uses_backend_git(self, devops: Devops) -> bool:
terraform_domain = devops.specialized_builds[BuildType.TERRAFORM]
return terraform_domain.uses_backend_git()
def read_output(self, devops: Devops) -> map:
terraform_domain = devops.specialized_builds[BuildType.TERRAFORM]
return self.file_api.read_json_fro_file(
@ -154,6 +165,7 @@ class TerraformService:
def post_build(self, devops: Devops):
self.__rescue_local_state__(devops)
self.tf_backend_git_api.stop()
def __copy_build_resource_file_from_package__(self, resource_name, devops: Devops):
data = self.resource_api.read_resource(

View file

@ -13,44 +13,52 @@ class DevopsTerraformBuild(DevopsBuild):
inp["mixin_types"] = config.get("mixin_types", [])
super().__init__(project, inp)
project.build_depends_on("dda-python-terraform")
self.teraform_service = TerraformService.prod()
self.terraform_service = TerraformService.prod()
# TODO: we might want to make this private in the future, keeping this for compatibility
def initialize_build_dir(self):
super().initialize_build_dir()
devops = self.devops_repo.get_devops(self.project)
self.teraform_service.initialize_build_dir(devops)
self.terraform_service.initialize_build_dir(devops)
def pre_build(self):
self.initialize_build_dir()
devops = self.devops_repo.get_devops(self.project)
if self.terraform_service.uses_backend_git(devops):
self.terraform_service.start_tf_backend_git_daemon(devops)
# TODO: Do we want a time.sleep(1) for usability?
def post_build(self):
devops = self.devops_repo.get_devops(self.project)
self.teraform_service.post_build(devops)
self.terraform_service.post_build(devops)
def read_output_json(self) -> map:
devops = self.devops_repo.get_devops(self.project)
return self.teraform_service.read_output(devops)
return self.terraform_service.read_output(devops)
def plan(self):
devops = self.devops_repo.get_devops(self.project)
self.teraform_service.plan(devops)
self.terraform_service.plan(devops)
self.post_build()
def plan_fail_on_diff(self):
devops = self.devops_repo.get_devops(self.project)
self.teraform_service.plan(devops, fail_on_diff=True)
self.terraform_service.plan(devops, fail_on_diff=True)
self.post_build()
def apply(self, auto_approve=False):
devops = self.devops_repo.get_devops(self.project)
self.teraform_service.apply(devops, auto_approve=auto_approve)
self.terraform_service.apply(devops, auto_approve=auto_approve)
self.post_build()
def refresh(self):
devops = self.devops_repo.get_devops(self.project)
self.teraform_service.refresh(devops)
self.terraform_service.refresh(devops)
self.post_build()
def destroy(self, auto_approve=False):
devops = self.devops_repo.get_devops(self.project)
self.teraform_service.destroy(devops, auto_approve=auto_approve)
self.terraform_service.destroy(devops, auto_approve=auto_approve)
self.post_build()
def tf_import(
@ -59,5 +67,5 @@ class DevopsTerraformBuild(DevopsBuild):
tf_import_resource,
):
devops = self.devops_repo.get_devops(self.project)
self.teraform_service.tf_import(devops, tf_import_name, tf_import_resource)
self.terraform_service.tf_import(devops, tf_import_name, tf_import_resource)
self.post_build()

View file

@ -15,6 +15,7 @@ from .terraform import TerraformDomain
from .provider_digitalocean import Digitalocean
from .provider_hetzner import Hetzner
from .provider_aws import Aws
from .backend_tf_backend_git import TerraformBackendGit
from .provs_k3s import K3s
from .release import Release
from .artifact import Artifact

View file

@ -0,0 +1,72 @@
from typing import List, Dict, Set, Any
from .common import Validateable, CredentialMappingDefault
class TerraformBackendGit(Validateable, CredentialMappingDefault):
def __init__(
self,
inp: dict,
):
self.stage = inp.get("stage")
self.module = inp.get("module")
self.git_backend_repo = inp.get("git_backend_repo")
self.git_backend_ref = inp.get("git_backend_ref")
self.git_backend_state = inp.get("git_backend_state")
self.git_backend_username = inp.get("git_backend_username")
self.git_backend_token = inp.get("git_backend_token")
def validate(self) -> List[str]:
result = []
result += self.__validate_is_not_empty__("stage")
result += self.__validate_is_not_empty__("module")
result += self.__validate_is_not_empty__("git_backend_repo")
result += self.__validate_is_not_empty__("git_backend_ref")
result += self.__validate_is_not_empty__("git_backend_state")
result += self.__validate_is_not_empty__("git_backend_username")
result += self.__validate_is_not_empty__("git_backend_token")
return result
# See: https://developer.hashicorp.com/terraform/language/settings/backends/configuration#command-line-key-value-pairs
# and https://github.com/plumber-cd/terraform-backend-git?tab=readme-ov-file#standalone-terraform-http-backend-mode
def backend_config(self) -> Dict[str, Any]:
return {
"address": self.__make_http_backend_address__(),
"lock_address": self.__make_http_backend_address__(),
"unlock_address": self.__make_http_backend_address__(),
}
def resources_from_package(self) -> Set[str]:
return {"tf_backend_git_backend.tf", "tf_backend_git_backend_vars.tf"}
# TODO: This can not be used for backend, as the backend block can not reference vars.
# This is another reason to introduce a 'backend' object
def project_vars(self) -> Dict[str, Any]:
return {
"": ""
}
def is_local_state(self):
return False
def __make_http_backend_address__(self) -> str:
# TODO Should we make this configurable?
base_string = "http://localhost:6061/?type=git"
state = f"{self.stage}/{self.module}/{self.git_backend_state}"
return f"{base_string}&repository={self.git_backend_repo}&ref={self.git_backend_ref}&state={state}"
# TODO: Implement ssh auth too
@classmethod
def get_mapping_default(cls) -> List[Dict[str, str]]:
return [
{
"gopass_path": "server/meissa/repo/terraform-backend-git-test",
"gopass_field": "user",
"name": "git_backend_username",
},
{
"gopass_path": "server/meissa/repo/terraform-backend-git-test",
"gopass_field": "token",
"name": "git_backend_token",
},
]

View file

@ -11,7 +11,6 @@ class BuildFileType(Enum):
JS = ".json"
JAVA_GRADLE = ".gradle"
JAVA_CLOJURE = ".clj"
JAVA_CLOJURE_EDN = ".edn"
PYTHON = ".py"
@ -42,8 +41,6 @@ class BuildFile(Validateable):
result = BuildFileType.JAVA_CLOJURE
case ".py":
result = BuildFileType.PYTHON
case ".edn":
result = BuildFileType.JAVA_CLOJURE_EDN
case _:
result = None
return result
@ -51,13 +48,11 @@ class BuildFile(Validateable):
def __get_file_type_regex_str(self, file_type: BuildFileType):
match file_type:
case BuildFileType.JAVA_GRADLE:
return r"(?P<pre_version>\bversion\s?=\s?)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT)?)\""
return r'(?P<pre_version>\bversion\s?=\s?)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT)?)\"'
case BuildFileType.PYTHON:
return r"(?P<pre_version>\bversion\s?=\s?)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT|-dev\d*)?)\""
return r'(?P<pre_version>\bversion\s?=\s?)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT|-dev\d*)?)\"'
case BuildFileType.JAVA_CLOJURE:
return r"(?P<pre_version>\(defproject\s(\S)*\s)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT)?)\""
case BuildFileType.JAVA_CLOJURE_EDN:
return r"(?P<pre_version>\:version\s+)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT)?)\""
return r'(?P<pre_version>\(defproject\s(\S)*\s)\"(?P<version>\d*\.\d*\.\d*(-SNAPSHOT)?)\"'
case _:
return ""
@ -67,15 +62,8 @@ class BuildFile(Validateable):
match build_file_type:
case BuildFileType.JS:
version_str = json.loads(self.content)["version"]
case (
BuildFileType.JAVA_GRADLE
| BuildFileType.PYTHON
| BuildFileType.JAVA_CLOJURE
| BuildFileType.JAVA_CLOJURE_EDN
):
version_str = re.search(
self.__get_file_type_regex_str(build_file_type), self.content
).group("version")
case BuildFileType.JAVA_GRADLE | BuildFileType.PYTHON | BuildFileType.JAVA_CLOJURE:
version_str = re.search(self.__get_file_type_regex_str(build_file_type), self.content).group("version")
except:
raise RuntimeError(f"Version not found in file {self.file_path}")
@ -96,15 +84,10 @@ class BuildFile(Validateable):
json_data = json.loads(self.content)
json_data["version"] = new_version.to_string()
self.content = json.dumps(json_data, indent=4)
case (
BuildFileType.JAVA_GRADLE
| BuildFileType.PYTHON
| BuildFileType.JAVA_CLOJURE
| BuildFileType.JAVA_CLOJURE_EDN
):
case BuildFileType.JAVA_GRADLE | BuildFileType.PYTHON | BuildFileType.JAVA_CLOJURE:
substitute = re.sub(
self.__get_file_type_regex_str(build_file_type),
rf'\g<pre_version>"{new_version.to_string()}"',
fr'\g<pre_version>"{new_version.to_string()}"',
self.content,
1,
)

View file

@ -13,10 +13,12 @@ class BuildType(Enum):
TERRAFORM = 3
# TODO: We could follow domain implications and make a 'BackendType' enum
class ProviderType(Enum):
DIGITALOCEAN = 0
HETZNER = 1
AWS = 2
TERRAFORM_BACKEND_GIT = 3
class MixinType(Enum):
@ -78,12 +80,6 @@ class DnsRecord(Validateable):
result.append("ipv4 & ipv6 may not both be empty.")
return result
def ip(self) -> str:
if (self.ipv4):
return self.ipv4
else:
return self.ipv6
class Devops(Validateable):
def __init__(

View file

@ -6,6 +6,7 @@ from .devops_factory import DevopsFactory
from .terraform import TerraformDomain
from .provider_digitalocean import Digitalocean
from .provider_hetzner import Hetzner
from .backend_tf_backend_git import TerraformBackendGit
from .c4k import C4k
from .image import Image
from .release import ReleaseType, Release
@ -60,6 +61,8 @@ class InitService:
default_mappings += Digitalocean.get_mapping_default()
if ProviderType.HETZNER in provider_types:
default_mappings += Hetzner.get_mapping_default()
if ProviderType.TERRAFORM_BACKEND_GIT in provider_types:
default_mappings += TerraformBackendGit.get_mapping_default()
if MixinType.RELEASE in mixin_types:
primary_build_file_id = inp.get(

View file

@ -86,7 +86,7 @@ class K3s(Validateable):
cmd = [
"provs-server.jar",
"k3s",
f"{self.k3s_provision_user}@{self.provision_dns.ip()}",
f"{self.k3s_provision_user}@{self.provision_dns.fqdn}",
"-c",
f"{devops.build_path()}/out_k3sServerConfig.yaml",
"-a",

View file

@ -24,7 +24,6 @@ class Release(Validateable):
"release_secondary_build_files", []
)
self.version = version
self.release_tag_prefix = inp.get("release_tag_prefix", "")
self.release_artifact_server_url = inp.get("release_artifact_server_url")
self.release_organisation = inp.get("release_organisation")
self.release_repository_name = inp.get("release_repository_name")

View file

@ -8,6 +8,7 @@ from .common import (
from .provider_digitalocean import Digitalocean
from .provider_hetzner import Hetzner
from .provider_aws import Aws
from .backend_tf_backend_git import TerraformBackendGit
class TerraformDomain(Validateable):
@ -42,6 +43,8 @@ class TerraformDomain(Validateable):
self.providers[ProviderType.HETZNER] = Hetzner(inp)
if ProviderType.AWS in provider_types:
self.providers[ProviderType.AWS] = Aws(inp)
if ProviderType.TERRAFORM_BACKEND_GIT in provider_types:
self.providers[ProviderType.TERRAFORM_BACKEND_GIT] = TerraformBackendGit(inp)
def validate(self) -> List[str]:
result = []
@ -86,6 +89,21 @@ class TerraformDomain(Validateable):
result = result and provider.is_local_state()
return result
def uses_backend_git(self) -> bool:
if ProviderType.TERRAFORM_BACKEND_GIT in self.providers:
return True
return False
# TODO: Add ssh method case and make this default
def env_credentials(self) -> Dict[str, str]:
tf_backend_git = self.providers[ProviderType.TERRAFORM_BACKEND_GIT]
if tf_backend_git.git_backend_token != "":
return {
"GITHUB_TOKEN": tf_backend_git.git_backend_token,
"GIT_USERNAME": tf_backend_git.git_backend_username,
}
return {"": ""}
def backend_config(self) -> Dict[str, Any]:
result = {}
for provider in self.providers.values():

View file

@ -7,6 +7,7 @@ from .infrastructure import (
CredentialsApi,
GitApi,
TerraformApi,
TerraformBackendGitApi,
ArtifactDeploymentApi,
)
from .repository import DevopsRepository, BuildFileRepository

View file

@ -1,4 +1,5 @@
from subprocess import Popen, PIPE, run, CalledProcessError
from typing import Dict
from pathlib import Path
from sys import stdout
from os import chmod, environ
@ -216,6 +217,20 @@ class TerraformApi:
pass
class TerraformBackendGitApi:
def __init__(self):
self.execution_api = ExecutionApi()
def start(self, credentials: Dict[str, str]):
env = ""
for key in credentials:
env = env + f'{key}' + "=" + f'{credentials[key]}' + " "
self.execution_api.execute_live(f"{env} nohup terraform-backend-git &")
def stop(self):
self.execution_api.execute("terraform-backend-git stop")
class ArtifactDeploymentApi:
def __init__(self):
self.execution_api = ExecutionApi()

View file

@ -0,0 +1,3 @@
terraform {
backend "http" {}
}

View file

@ -24,7 +24,7 @@ def devops_config(overrides: dict) -> dict:
"k3s_letsencrypt_endpoint": "k3s_letsencrypt_endpoint",
"k3s_enable_echo": "false",
"k3s_app_filename_to_provision": "k3s_app.yaml",
"tf_provider_types": ["DIGITALOCEAN", "HETZNER", "AWS"],
"tf_provider_types": ["DIGITALOCEAN", "HETZNER", "AWS", "TERRAFORM_BACKEND_GIT"],
"tf_additional_vars": [],
"tf_output_json_name": "the_out.json",
"tf_use_workspace": None,
@ -58,6 +58,11 @@ def devops_config(overrides: dict) -> dict:
"release_artifact_server_url": None,
"release_organisation": None,
"release_repository_name": None,
"git_backend_repo": "https://repo.example.com/meissa/infra-states",
"git_backend_ref": "main",
"git_backend_state": "test.json",
"git_backend_username": "tf_backend_user",
"git_backend_token": "324asd234df435sfdgh",
"credentials_mappings": [
{
"gopass_path": "a/path",

View file

@ -183,34 +183,6 @@ def test_should_parse_and_set_version_for_clj():
== sut.content
)
def test_should_parse_and_set_version_for_clj_edn():
sut = BuildFile(
Path("./deps.edn"),
"""
{:project {:name org.domaindrivenarchitecture/dda-backup
:version "1.1.5-SNAPSHOT"}
}
""",
)
assert sut.get_version() == Version.from_str("1.1.5-SNAPSHOT", "SNAPSHOT")
sut = BuildFile(
Path("./deps.edn"),
"""
{:project {:name org.domaindrivenarchitecture/dda-backup
:version "1.1.5-SNAPSHOT"}
}
""",
)
sut.set_version(Version.from_str("1.1.5-SNAPSHOT", "SNAPSHOT").create_major())
assert (
'\n{:project {:name org.domaindrivenarchitecture/dda-backup\n :version "2.0.0"}\n\n}\n'
== sut.content
)
def test_should_throw_for_clj_wrong_version():
sut = BuildFile(
Path("./project.clj"),

View file

@ -0,0 +1,30 @@
from pybuilder.core import Project
from pathlib import Path
from src.main.python.ddadevops.domain import (
BuildType,
TerraformBackendGit,
)
from .helper import devops_config
def test_tf_backend_git_creation():
sut = TerraformBackendGit(
{
"module": "module",
"stage": "test",
"git_backend_repo": "https://repo.example.com/meissa/infra-states",
"git_backend_ref": "main",
"git_backend_state": "test.json",
"git_backend_username": "tf_backend_user",
"git_backend_token": "324asd234df435sfdgh",
}
)
assert sut is not None
assert sut.is_valid()
def test_should_calculate_backend_config():
sut = TerraformBackendGit(devops_config({}))
assert {
"address": "http://localhost:6061/?type=git&repository=https://repo.example.com/meissa/infra-states&ref=main&state=test/module/test.json",
"lock_address": "http://localhost:6061/?type=git&repository=https://repo.example.com/meissa/infra-states&ref=main&state=test/module/test.json",
"unlock_address": "http://localhost:6061/?type=git&repository=https://repo.example.com/meissa/infra-states&ref=main&state=test/module/test.json",
} == sut.backend_config()

View file

@ -24,7 +24,7 @@ def test_should_calculate_command():
assert (
"provs-server.jar "
+ "k3s "
+ "k3s_provision_user@::1 "
+ "k3s_provision_user@example.org "
+ "-c "
+ "root_path/target/name/module/out_k3sServerConfig.yaml "
+ "-a "

View file

@ -17,6 +17,7 @@ def test_creation():
assert sut.providers[ProviderType.DIGITALOCEAN]
assert sut.providers[ProviderType.HETZNER]
assert sut.providers[ProviderType.AWS]
assert sut.providers[ProviderType.TERRAFORM_BACKEND_GIT]
def test_should_calculate_output_json_name():
@ -77,6 +78,7 @@ def test_should_calculate_project_vars():
{
"do_as_backend": False,
"aws_as_backend": False,
"tf_provider_types": ["DIGITALOCEAN", "HETZNER", "AWS"]
}
)
sut = TerraformDomain(config)
@ -166,6 +168,17 @@ def test_should_calculate_resources_from_package():
"aws_provider_vars.tf",
"aws_backend_wkms_vars.tf",
"my.file",
"tf_backend_git_backend_vars.tf",
"tf_backend_git_backend.tf",
} == sut.resources_from_package()
config = devops_config({"tf_provider_types": ["TERRAFORM_BACKEND_GIT"]})
sut = TerraformDomain(config)
assert {
"versions.tf",
"terraform_build_vars.tf",
"tf_backend_git_backend_vars.tf",
"tf_backend_git_backend.tf",
} == sut.resources_from_package()
@ -188,3 +201,7 @@ def test_should_calculate_local_state_handling():
)
)
assert not sut.is_local_state()
def test_should_use_backend_git():
sut = TerraformDomain(devops_config({}))
assert sut.uses_backend_git()