From a648e7f7a7965c5ca845be259e6dc8151f0409dc Mon Sep 17 00:00:00 2001 From: Mark Schuit Date: Wed, 8 May 2024 20:30:16 +0800 Subject: [PATCH] [IMP] Added namespace prefix to application sets to be able to deploy to different namespaces. --- argocd_deployer/__manifest__.py | 2 + .../data/application_namespace_prefix.xml | 8 ++++ argocd_deployer/data/application_set.xml | 2 + .../data/application_set_template.xml | 10 ++-- argocd_deployer/menuitems.xml | 7 +++ argocd_deployer/models/__init__.py | 1 + .../models/application_namespace_prefix.py | 31 +++++++++++++ argocd_deployer/models/application_set.py | 3 ++ argocd_deployer/tests/__init__.py | 1 + .../test_application_namespace_prefix.py | 24 ++++++++++ argocd_deployer/tests/test_application_set.py | 46 ++++++++++++++++++- .../application_namespace_prefix_view.xml | 18 ++++++++ .../views/application_set_view.xml | 1 + 13 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 argocd_deployer/data/application_namespace_prefix.xml create mode 100644 argocd_deployer/models/application_namespace_prefix.py create mode 100644 argocd_deployer/tests/test_application_namespace_prefix.py create mode 100644 argocd_deployer/views/application_namespace_prefix_view.xml diff --git a/argocd_deployer/__manifest__.py b/argocd_deployer/__manifest__.py index 3d8b75d..f733b84 100644 --- a/argocd_deployer/__manifest__.py +++ b/argocd_deployer/__manifest__.py @@ -7,6 +7,7 @@ "version": "16.0.1.1.0", "data": [ "data/ir_config_parameter_data.xml", + "data/application_namespace_prefix.xml", "data/application_set_template.xml", "data/application_set.xml", "views/application_template_view.xml", @@ -15,6 +16,7 @@ "views/application_value_view.xml", "views/application_view.xml", "views/application_set_view.xml", + "views/application_namespace_prefix_view.xml", "templates/application_description.xml", "security/ir.model.access.csv", "menuitems.xml", diff --git a/argocd_deployer/data/application_namespace_prefix.xml b/argocd_deployer/data/application_namespace_prefix.xml new file mode 100644 index 0000000..2266907 --- /dev/null +++ b/argocd_deployer/data/application_namespace_prefix.xml @@ -0,0 +1,8 @@ + + + flavoured-odoo- + + + application-set- + + diff --git a/argocd_deployer/data/application_set.xml b/argocd_deployer/data/application_set.xml index 7ad8646..4163970 100644 --- a/argocd_deployer/data/application_set.xml +++ b/argocd_deployer/data/application_set.xml @@ -8,6 +8,7 @@ /home/tarteo/repo application_sets + True @@ -20,6 +21,7 @@ %(application_name)s.curq.k8s.onestein.eu %(subdomain)s.%(application_name)s.curq.k8s.onestein.eu + False diff --git a/argocd_deployer/data/application_set_template.xml b/argocd_deployer/data/application_set_template.xml index 575f5ba..38382ef 100644 --- a/argocd_deployer/data/application_set_template.xml +++ b/argocd_deployer/data/application_set_template.xml @@ -17,7 +17,7 @@ spec: - path: {{.config.deployment_directory}}/**/application_set.yaml template: metadata: - name: "application-set-{{ "{{ " }}.path.basename{{ " }}" }}" + name: "{{.application_set.namespace_prefix}}{{ "{{ " }}.path.basename{{ " }}" }}" spec: project: "default" source: @@ -26,7 +26,7 @@ spec: path: "{{ "{{ " }}.path.filename{{ " }}" }}" destination: name: in-cluster - namespace: "application-set-{{ "{{ " }}.path.basename{{ " }}" }}" + namespace: "{{.application_set.namespace_prefix}}{{ "{{ " }}.path.basename{{ " }}" }}" syncPolicy: syncOptions: - CreateNamespace=true @@ -40,7 +40,7 @@ spec: apiVersion: argoproj.io/v1alpha1 kind: ApplicationSet metadata: - name: "flavoured-odoo-{{.application_set.name}}" + name: "{{.application_set.namespace_prefix}}{{.application_set.name}}" namespace: argocd spec: goTemplate: true @@ -52,7 +52,7 @@ spec: - path: {{.application_set.deployment_directory}}/**/config.yaml template: metadata: - name: "flavoured-odoo-{{ .path.basename }}" + name: "{{.application_set.namespace_prefix}}{{ .path.basename }}" spec: project: "default" source: @@ -64,7 +64,7 @@ spec: {{ .helm }} destination: name: in-cluster - namespace: "flavoured-odoo-{{ .path.basename }}" + namespace: "{{.application_set.namespace_prefix}}{{ .path.basename }}" syncPolicy: syncOptions: - CreateNamespace=true diff --git a/argocd_deployer/menuitems.xml b/argocd_deployer/menuitems.xml index a6d175b..255781c 100644 --- a/argocd_deployer/menuitems.xml +++ b/argocd_deployer/menuitems.xml @@ -37,4 +37,11 @@ parent="config_menu" sequence="30" /> + + diff --git a/argocd_deployer/models/__init__.py b/argocd_deployer/models/__init__.py index 35f7525..29e08db 100644 --- a/argocd_deployer/models/__init__.py +++ b/argocd_deployer/models/__init__.py @@ -5,3 +5,4 @@ from . import application_tag from . import application_tag_domain_override from . import application_value +from . import application_namespace_prefix diff --git a/argocd_deployer/models/application_namespace_prefix.py b/argocd_deployer/models/application_namespace_prefix.py new file mode 100644 index 0000000..23986bd --- /dev/null +++ b/argocd_deployer/models/application_namespace_prefix.py @@ -0,0 +1,31 @@ +import re + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class ApplicationNamespacePrefix(models.Model): + _name = "argocd.application.namespace.prefix" + _description = "Application Namespace Prefix" + + name = fields.Char(required=True) + + _sql_constraints = [ + ("application_namespace_name_prefix_unique", "unique(name)", "Already exists"), + ( + "app_namespace_prefix_unique", + "unique(name)", + "A namespace prefix with that name was already defined.", + ), + ] + + @api.constrains("name") + def _constrain_name(self): + if not re.match( + "^[a-z0-9-]{1,100}$", self.name + ): # lowercase a to z, 0 to 9 and - (dash) are allowed + raise ValidationError( + _( + "Only lowercase letters, numbers and dashes are allowed in the name (max 100 characters)." + ) + ) diff --git a/argocd_deployer/models/application_set.py b/argocd_deployer/models/application_set.py index 390d88f..931acb1 100644 --- a/argocd_deployer/models/application_set.py +++ b/argocd_deployer/models/application_set.py @@ -48,6 +48,7 @@ class ApplicationSet(models.Model): help="The domain format used to build the domain for the deployment.", default="-", ) + namespace_prefix_id = fields.Many2one("argocd.application.namespace.prefix") _sql_constraints = [ ("application_set_name_unique", "unique(name)", "Already exists"), @@ -257,6 +258,8 @@ def _get_argocd_template(self): "{{.application_set.branch}}": self.branch or "", "{{.application_set.deployment_directory}}": self.deployment_directory or "", + "{{.application_set.namespace_prefix}}": self.namespace_prefix_id.name + or "", } template_yaml = self.template_id.yaml for key, value in replacements.items(): diff --git a/argocd_deployer/tests/__init__.py b/argocd_deployer/tests/__init__.py index 5b5206c..030a132 100644 --- a/argocd_deployer/tests/__init__.py +++ b/argocd_deployer/tests/__init__.py @@ -1,3 +1,4 @@ from . import test_application from . import test_application_set from . import test_application_tag +from . import test_application_namespace_prefix diff --git a/argocd_deployer/tests/test_application_namespace_prefix.py b/argocd_deployer/tests/test_application_namespace_prefix.py new file mode 100644 index 0000000..b7ffd1b --- /dev/null +++ b/argocd_deployer/tests/test_application_namespace_prefix.py @@ -0,0 +1,24 @@ +from odoo.exceptions import ValidationError +from odoo.tests.common import TransactionCase + + +class TestApplicationNamespacePrefix(TransactionCase): + def test_name(self): + """Name may only contain lowercase letters, digits and underscores.""" + with self.assertRaisesRegex( + ValidationError, "Only lowercase letters, numbers and dashes" + ): + self.env["argocd.application.namespace.prefix"].create({"name": "Hello"}) + + with self.assertRaisesRegex(ValidationError, "max 100 characters"): + self.env["argocd.application.namespace.prefix"].create( + { + "name": "this-name-is-waaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay-" + "toooooooooooooooooooooo-ridiculously-long-and should-" + "totally-not-be-allowed" + } + ) + + self.env["argocd.application.namespace.prefix"].create( + {"name": "hello-the-namespace"} + ) diff --git a/argocd_deployer/tests/test_application_set.py b/argocd_deployer/tests/test_application_set.py index 7c7f21a..90f5eeb 100644 --- a/argocd_deployer/tests/test_application_set.py +++ b/argocd_deployer/tests/test_application_set.py @@ -1,6 +1,6 @@ from unittest.mock import MagicMock, mock_open, patch -from odoo.exceptions import UserError +from odoo.exceptions import UserError, ValidationError from odoo.tests import TransactionCase APPLICATION_SET_PATCH = ( @@ -25,6 +25,8 @@ def setUpClass(cls): revision: {{.config.branch}} path: {{.config.deployment_directory}} template-path: {{.path.path}} + destination: + namespace: {{.application_set.namespace_prefix}}{{.path.basename}} """, } ) @@ -36,6 +38,9 @@ def setUpClass(cls): "template_id": cls.application_set_template.id, "repository_directory": "/home/test", "deployment_directory": "instances", + "namespace_prefix_id": cls.env.ref( + "argocd_deployer.namespace_prefix_application_set" + ).id, } ) @@ -53,8 +58,47 @@ def setUpClass(cls): revision: {cls.master_application_set.branch} path: {cls.master_application_set.deployment_directory} template-path: {{{{.path.path}}}} + destination: + namespace: application-set-{{{{.path.basename}}}} """ + def test_name(self): + """Name may only contain lowercase letters, digits and underscores.""" + params = { + "template_id": self.env.ref( + "argocd_deployer.application_set_template_default" + ).id, + "repository_url": "git@github.com:odoo/odoo-no-exist.git", + "repository_directory": "/home/test", + } + + with self.assertRaisesRegex( + ValidationError, "Only lowercase letters, numbers and dashes" + ): + self.env["argocd.application.set"].create( + { + **params, + "name": "Hello", + } + ) + + with self.assertRaisesRegex(ValidationError, "max 100 characters"): + self.env["argocd.application.set"].create( + { + **params, + "name": "this-name-is-waaaaaaaaaaaaaaaaaaaaaaaaaaaaaaay-" + "toooooooooooooooooooooo-ridiculously-long-and should-" + "totally-not-be-allowed", + } + ) + + self.env["argocd.application.set"].create( + { + **params, + "name": "hello-the-namespace", + } + ) + def test_get_master_repository_directory(self): """The master repository directory is stored in the config. Check that it behaves.""" diff --git a/argocd_deployer/views/application_namespace_prefix_view.xml b/argocd_deployer/views/application_namespace_prefix_view.xml new file mode 100644 index 0000000..7c53892 --- /dev/null +++ b/argocd_deployer/views/application_namespace_prefix_view.xml @@ -0,0 +1,18 @@ + + + + argocd.application.namespace.prefix + + + + + + + + + Namespace prefixes + ir.actions.act_window + argocd.application.namespace.prefix + tree + + diff --git a/argocd_deployer/views/application_set_view.xml b/argocd_deployer/views/application_set_view.xml index be69fb3..65cde76 100644 --- a/argocd_deployer/views/application_set_view.xml +++ b/argocd_deployer/views/application_set_view.xml @@ -79,6 +79,7 @@ +