refactor devops_c4k_mixin to arch

This commit is contained in:
Michael Jerger 2023-03-12 19:09:32 +01:00
parent eec7392470
commit dd85b7b95b
10 changed files with 128 additions and 63 deletions

View file

@ -3,13 +3,38 @@
```mermaid ```mermaid
classDiagram classDiagram
class Build { class Build {
__init__(project, config) stage
do_sth(project) name
project_root_path
module
build_dir_name
} }
class C4kBuild {
executabel_name
c4k_mixin_config
c4k_mixin_auth
}
class DnsRecord {
fqdn
ipv4
ipv6
}
C4kBuild *-- DnsRecord
```
# Infrastructure
```mermaid
classDiagram
class ProjectRepository { class ProjectRepository {
get_build(project): Build get_build(project): Build
set_build(project, build) set_build(project, build)
} }
``` ```

View file

@ -19,8 +19,8 @@ from .devops_terraform_build import DevopsTerraformBuild, create_devops_terrafor
from .devops_build import DevopsBuild, create_devops_build_config, get_devops_build, get_tag_from_latest_commit from .devops_build import DevopsBuild, create_devops_build_config, get_devops_build, get_tag_from_latest_commit
from .credential import gopass_password_from_path, gopass_field_from_path from .credential import gopass_password_from_path, gopass_field_from_path
from .domain import Validateable, Build, DockerBuild, C4kBuild from .domain import Validateable, DnsRecord, Build, DockerBuild, C4kBuild
from .application import DockerBuildService, C4kBuildService from .application import DockerBuildService
from .infrastructure import ProjectRepository, ResourceApi, FileApi, DockerApi, ExecutionApi from .infrastructure import ProjectRepository, ResourceApi, FileApi, DockerApi, ExecutionApi
__version__ = "${version}" __version__ = "${version}"

View file

@ -48,20 +48,3 @@ class DockerBuildService:
def test(self, build: Build): def test(self, build: Build):
self.docker_api.test(build.name(), build.build_path()) self.docker_api.test(build.name(), build.build_path())
class C4kBuildService:
def __init__(self):
self.file_api = FileApi()
self.execution_api = ExecutionApi()
def write_c4k_config(self, c4k_build: C4kBuild):
path = c4k_build.build.build_path() + "/out_c4k_config.yaml"
self.file_api.write_yaml_to_file(path, c4k_build.config())
def write_c4k_auth(self, c4k_build: C4kBuild):
path = c4k_build.build.build_path() + "/out_c4k_auth.yaml"
self.file_api.write_yaml_to_file(path, c4k_build.c4k_mixin_auth)
def c4k_apply(self, c4k_build: C4kBuild, dry_run=False):
return self.execution_api.execute(c4k_build.command(), dry_run)

View file

@ -1,9 +1,11 @@
from .domain import C4kBuild from .domain import C4kBuild, DnsRecord
from .application import C4kBuildService
from .devops_build import DevopsBuild from .devops_build import DevopsBuild
from .credential import gopass_field_from_path, gopass_password_from_path from .credential import gopass_field_from_path, gopass_password_from_path
from .infrastructure import ProjectRepository, FileApi, ExecutionApi
@deprecation.deprecated(deprecated_in="3.2")
# create objects direct instead
def add_c4k_mixin_config( def add_c4k_mixin_config(
config, config,
c4k_config_dict, c4k_config_dict,
@ -42,17 +44,32 @@ def add_c4k_mixin_config(
return config return config
#TODO: refactor this to C4kBuild
class C4kMixin(DevopsBuild): class C4kMixin(DevopsBuild):
def __init__(self, project, config): def __init__(self, project, config):
super().__init__(project, config) super().__init__(project, config)
self.c4k_build = C4kBuild(self.build, project, config) self.execution_api = ExecutionApi()
self.c4k_build_service = C4kBuildService() c4k_build = C4kBuild(config)
self.repo.set_c4k_build(self.project, c4k_build)
def update_runtime_config(self, dns_record: DnsRecord):
c4k_build = self.repo.get_c4k_build(self.project)
c4k_build.update_runtime_config(dns_record)
self.repo.set_c4k_build(self.project, c4k_build)
def write_c4k_config(self): def write_c4k_config(self):
self.c4k_build_service.write_c4k_config(self.c4k_build) build = self.repo.get_build(self.project)
c4k_build = self.repo.get_c4k_build(self.project)
path = build.build_path() + "/out_c4k_config.yaml"
self.file_api.write_yaml_to_file(path, c4k_build.config())
def write_c4k_auth(self): def write_c4k_auth(self):
self.c4k_build_service.write_c4k_auth(self.c4k_build) build = self.repo.get_build(self.project)
c4k_build = self.repo.get_c4k_build(self.project)
path = build.build_path() + "/out_c4k_auth.yaml"
self.file_api.write_yaml_to_file(path, c4k_build.c4k_mixin_auth)
def c4k_apply(self, dry_run=False): def c4k_apply(self, dry_run=False):
self.c4k_build_service.c4k_apply(self.c4k_build, dry_run) build = self.repo.get_build(self.project)
c4k_build = self.repo.get_c4k_build(self.project)
return self.execution_api.execute(c4k_build.command(build), dry_run)

View file

@ -2,7 +2,8 @@ import deprecation
from .domain import Build from .domain import Build
from .infrastructure import ProjectRepository, FileApi from .infrastructure import ProjectRepository, FileApi
@deprecation.deprecated(deprecated_in="3.2")
# create objects direct instead
def create_devops_build_config( def create_devops_build_config(
stage, project_root_path, module, build_dir_name="target" stage, project_root_path, module, build_dir_name="target"
): ):
@ -51,4 +52,5 @@ class DevopsBuild:
return build.build_path() return build.build_path()
def initialize_build_dir(self): def initialize_build_dir(self):
build = self.repo.get_build(self.project)
self.file_api.clean_dir(build.build_path()) self.file_api.clean_dir(build.build_path())

View file

@ -2,7 +2,8 @@ from .domain import DockerBuild
from .application import DockerBuildService from .application import DockerBuildService
from .devops_build import DevopsBuild, create_devops_build_config from .devops_build import DevopsBuild, create_devops_build_config
@deprecation.deprecated(deprecated_in="3.2")
# create objects direct instead
def create_devops_docker_build_config( def create_devops_docker_build_config(
stage, stage,
project_root_path, project_root_path,

View file

@ -18,6 +18,20 @@ class Validateable:
return len(self.validate()) < 1 return len(self.validate()) < 1
class DnsRecord(Validateable):
def __init__(self, fqdn, ipv4=None, ipv6=None):
self.fqdn = fqdn
self.ipv4 = ipv4
self.ipv6 = ipv6
def validate(self) -> List[str]:
result = []
result += self.__validate_is_not_empty__("fqdn")
if (not self.ipv4) and (not self.ipv6):
result.append("ipv4 & ipv6 may not both be empty.")
return result
class Build(Validateable): class Build(Validateable):
def __init__(self, config): def __init__(self, config):
self.stage = config["stage"] self.stage = config["stage"]
@ -37,12 +51,6 @@ class Build(Validateable):
path = [self.project_root_path, self.build_dir_name, self.name, self.module] path = [self.project_root_path, self.build_dir_name, self.name, self.module]
return "/".join(filter_none(path)) return "/".join(filter_none(path))
# TODO: these functions should be located at TerraformBuild later on.
def update_runtime_config(self, fqdn, ipv4, ipv6):
self.__put__("fqdn", fqdn)
self.__put__("ipv4", ipv4)
self.__put__("ipv6", ipv6)
def __put__(self, key, value): def __put__(self, key, value):
self.stack[key] = value self.stack[key] = value
@ -57,7 +65,7 @@ class Build(Validateable):
class DockerBuild(Validateable): class DockerBuild(Validateable):
def __init__(self, config): def __init__(self, config: map):
self.dockerhub_user = config["dockerhub_user"] self.dockerhub_user = config["dockerhub_user"]
self.dockerhub_password = config["dockerhub_password"] self.dockerhub_password = config["dockerhub_password"]
self.use_package_common_files = config["use_package_common_files"] self.use_package_common_files = config["use_package_common_files"]
@ -71,31 +79,37 @@ class DockerBuild(Validateable):
class C4kBuild(Validateable): class C4kBuild(Validateable):
def __init__(self, build: Build, project, config): def __init__(self, config: map):
self.build = build
tmp_executabel_name = config["C4kMixin"]["executabel_name"] tmp_executabel_name = config["C4kMixin"]["executabel_name"]
if not tmp_executabel_name: if not tmp_executabel_name:
tmp_executabel_name = self.build.module tmp_executabel_name = config["module"]
self.executabel_name = tmp_executabel_name self.executabel_name = tmp_executabel_name
self.c4k_mixin_config = config["C4kMixin"]["config"] self.c4k_mixin_config = config["C4kMixin"]["config"]
self.c4k_mixin_auth = config["C4kMixin"]["auth"] self.c4k_mixin_auth = config["C4kMixin"]["auth"]
tmp = self.c4k_mixin_config["mon-cfg"] tmp = self.c4k_mixin_config["mon-cfg"]
tmp.update( tmp.update({"cluster-name": config["module"], "cluster-stage": config["stage"]})
{"cluster-name": self.build.module, "cluster-stage": self.build.stage}
)
self.c4k_mixin_config.update({"mon-cfg": tmp}) self.c4k_mixin_config.update({"mon-cfg": tmp})
self.dns_record = None
def update_runtime_config(self, fqdn, ipv4, ipv6): # TODO: these functions should be located at TerraformBuild later on.
self.build.update_runtime_config(fqdn, ipv4, ipv6) def update_runtime_config(self, dns_record: DnsRecord):
self.dns_record = dns_record
def validate(self) -> List[str]:
result = []
result += self.__validate_is_not_empty__("fqdn")
if self.dns_record:
result += self.dns_record.validate()
return result
def config(self): def config(self):
fqdn = self.build.__get__("fqdn") fqdn = self.dns_record.fqdn
self.c4k_mixin_config.update({"fqdn": fqdn}) self.c4k_mixin_config.update({"fqdn": fqdn})
return self.c4k_mixin_config return self.c4k_mixin_config
def command(self): def command(self, build: Build):
module = self.build.module module = build.module
build_path = self.build.build_path() build_path = build.build_path()
config_path = f"{build_path}/out_c4k_config.yaml" config_path = f"{build_path}/out_c4k_config.yaml"
auth_path = f"{build_path}/out_c4k_auth.yaml" auth_path = f"{build_path}/out_c4k_auth.yaml"
output_path = f"{build_path}/out_{module}.yaml" output_path = f"{build_path}/out_{module}.yaml"

View file

@ -3,7 +3,7 @@ from sys import stdout
from pkg_resources import resource_string from pkg_resources import resource_string
from os import chmod from os import chmod
import yaml import yaml
from .domain import Build, DockerBuild from .domain import Build, DockerBuild, C4kBuild
from .python_util import execute from .python_util import execute
@ -20,6 +20,12 @@ class ProjectRepository:
def set_docker_build(self, project, build: DockerBuild): def set_docker_build(self, project, build: DockerBuild):
project.set_property("docker_build", build) project.set_property("docker_build", build)
def get_c4k_build(self, project) -> C4kBuild:
return project.get_property("c4k_build")
def set_c4k_build(self, project, build: C4kBuild):
project.set_property("c4k_build", build)
class ResourceApi: class ResourceApi:
def read_resource(self, path: str) -> bytes: def read_resource(self, path: str) -> bytes:

View file

@ -1,5 +1,6 @@
import os import os
from pybuilder.core import Project from pybuilder.core import Project
from src.main.python.ddadevops.domain import DnsRecord
from src.main.python.ddadevops.c4k_mixin import C4kMixin, add_c4k_mixin_config from src.main.python.ddadevops.c4k_mixin import C4kMixin, add_c4k_mixin_config
class MyC4kMixin(C4kMixin): class MyC4kMixin(C4kMixin):
@ -32,14 +33,15 @@ def test_c4k_mixin(tmp_path):
mixin.initialize_build_dir() mixin.initialize_build_dir()
assert mixin.build_path() == f'{tmp_path_str}/{build_dir}/{project_name}/{module_name}' assert mixin.build_path() == f'{tmp_path_str}/{build_dir}/{project_name}/{module_name}'
mixin.build.update_runtime_config('test.de', None, None) mixin.update_runtime_config(DnsRecord('test.de', ipv6="1::"))
sut = mixin.repo.get_c4k_build(mixin.project)
assert 'fqdn' in sut.config()
assert 'mon-cfg' in sut.config()
assert 'mon-auth' in sut.c4k_mixin_auth
mixin.write_c4k_config() mixin.write_c4k_config()
assert 'fqdn' in mixin.c4k_build.config()
assert 'mon-cfg' in mixin.c4k_build.config()
assert os.path.exists(f'{mixin.build_path()}/out_c4k_config.yaml') assert os.path.exists(f'{mixin.build_path()}/out_c4k_config.yaml')
mixin.write_c4k_auth() mixin.write_c4k_auth()
assert 'mon-auth' in mixin.c4k_build.c4k_mixin_auth
assert os.path.exists(f'{mixin.build_path()}/out_c4k_auth.yaml') assert os.path.exists(f'{mixin.build_path()}/out_c4k_auth.yaml')

View file

@ -1,5 +1,5 @@
from pybuilder.core import Project from pybuilder.core import Project
from src.main.python.ddadevops.domain import Validateable, C4kBuild, Build from src.main.python.ddadevops.domain import Validateable, DnsRecord, C4kBuild, Build
from src.main.python.ddadevops.c4k_mixin import add_c4k_mixin_config from src.main.python.ddadevops.c4k_mixin import add_c4k_mixin_config
@ -41,6 +41,20 @@ def test_validate_with_reason():
assert sut.validate()[0] == "Field 'field' may not be empty." assert sut.validate()[0] == "Field 'field' may not be empty."
def test_should_validate_DnsRecord():
sut = DnsRecord(None)
assert not sut.is_valid()
sut = DnsRecord('name')
assert not sut.is_valid()
sut = DnsRecord('name', ipv4='1.2.3.4')
assert sut.is_valid()
sut = DnsRecord('name', ipv6='1::')
assert sut.is_valid()
def test_c4k_build_should_update_fqdn(tmp_path): def test_c4k_build_should_update_fqdn(tmp_path):
project = Project(str(tmp_path), name="name") project = Project(str(tmp_path), name="name")
project_config = { project_config = {
@ -63,8 +77,9 @@ def test_c4k_build_should_update_fqdn(tmp_path):
grafana_cloud_user="user", grafana_cloud_user="user",
grafana_cloud_password="password", grafana_cloud_password="password",
) )
sut = C4kBuild(Build(project_config), project, project_config) build = Build(project_config)
sut.update_runtime_config("test.de", None, None) sut = C4kBuild(project_config)
sut.update_runtime_config(DnsRecord("test.de", ipv6="1::"))
assert { assert {
"issuer": "staging", "issuer": "staging",
@ -85,8 +100,6 @@ def test_c4k_build_should_update_fqdn(tmp_path):
}, },
} == sut.c4k_mixin_auth } == sut.c4k_mixin_auth
sut.update_runtime_config
def test_c4k_build_should_calculate_command(tmp_path): def test_c4k_build_should_calculate_command(tmp_path):
project = Project(str(tmp_path), name="name") project = Project(str(tmp_path), name="name")
@ -104,13 +117,14 @@ def test_c4k_build_should_calculate_command(tmp_path):
grafana_cloud_user="user", grafana_cloud_user="user",
grafana_cloud_password="password", grafana_cloud_password="password",
) )
sut = C4kBuild(Build(project_config), project, project_config) build = Build(project_config)
sut = C4kBuild(project_config)
assert ( assert (
"c4k-module-standalone.jar " "c4k-module-standalone.jar "
+ "/target/name/module/out_c4k_config.yaml " + "/target/name/module/out_c4k_config.yaml "
+ "/target/name/module/out_c4k_auth.yaml > " + "/target/name/module/out_c4k_auth.yaml > "
+ "/target/name/module/out_module.yaml" + "/target/name/module/out_module.yaml"
== sut.command() == sut.command(build)
) )
project_config = { project_config = {
@ -128,12 +142,13 @@ def test_c4k_build_should_calculate_command(tmp_path):
grafana_cloud_user="user", grafana_cloud_user="user",
grafana_cloud_password="password", grafana_cloud_password="password",
) )
sut = C4kBuild(Build(project_config), project, project_config) build = Build(project_config)
sut = C4kBuild(project_config)
assert ( assert (
"c4k-executabel_name-standalone.jar " "c4k-executabel_name-standalone.jar "
+ "/target/name/module/out_c4k_config.yaml " + "/target/name/module/out_c4k_config.yaml "
+ "/target/name/module/out_c4k_auth.yaml > " + "/target/name/module/out_c4k_auth.yaml > "
+ "/target/name/module/out_module.yaml" + "/target/name/module/out_module.yaml"
== sut.command() == sut.command(build)
) )