gitops 1.1.1__tar.gz → 1.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. gitops-1.2.0/.release-please-manifest.json +5 -0
  2. {gitops-1.1.1 → gitops-1.2.0}/CHANGELOG.md +20 -0
  3. {gitops-1.1.1 → gitops-1.2.0}/PKG-INFO +1 -1
  4. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/CHANGELOG.md +7 -0
  5. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/Chart.yaml +1 -1
  6. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/deployment.yml +0 -2
  7. {gitops-1.1.1 → gitops-1.2.0}/gitops/__init__.py +1 -1
  8. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/apps.py +15 -1
  9. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/main.py +1 -4
  10. gitops-1.2.0/gitops_server/version.py +1 -0
  11. gitops-1.2.0/gitops_server/workers/__init__.py +1 -0
  12. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/workers/deployer/deploy.py +52 -24
  13. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/workers/deployer/hooks.py +4 -1
  14. {gitops-1.1.1 → gitops-1.2.0}/pyproject.toml +1 -1
  15. {gitops-1.1.1 → gitops-1.2.0}/tests/test_gitops_server.py +0 -11
  16. gitops-1.1.1/.release-please-manifest.json +0 -5
  17. gitops-1.1.1/gitops_server/version.py +0 -1
  18. gitops-1.1.1/gitops_server/workers/__init__.py +0 -2
  19. gitops-1.1.1/gitops_server/workers/status_updater/__init__.py +0 -1
  20. gitops-1.1.1/gitops_server/workers/status_updater/worker.py +0 -126
  21. {gitops-1.1.1 → gitops-1.2.0}/.dockerignore +0 -0
  22. {gitops-1.1.1 → gitops-1.2.0}/.github/workflows/release-please.yaml +0 -0
  23. {gitops-1.1.1 → gitops-1.2.0}/.github/workflows/test.yml +0 -0
  24. {gitops-1.1.1 → gitops-1.2.0}/.gitignore +0 -0
  25. {gitops-1.1.1 → gitops-1.2.0}/.mise.toml +0 -0
  26. {gitops-1.1.1 → gitops-1.2.0}/.pre-commit-config.yaml +0 -0
  27. {gitops-1.1.1 → gitops-1.2.0}/Dockerfile +0 -0
  28. {gitops-1.1.1 → gitops-1.2.0}/LICENSE +0 -0
  29. {gitops-1.1.1 → gitops-1.2.0}/README.md +0 -0
  30. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/.helmignore +0 -0
  31. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/README.md +0 -0
  32. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/_helpers.tpl +0 -0
  33. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/certificate.yml +0 -0
  34. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/environment.yml +0 -0
  35. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/ingress.yml +0 -0
  36. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/issuer.yml +0 -0
  37. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/secrets.yml +0 -0
  38. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/service.yml +0 -0
  39. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/templates/serviceaccount.yaml +0 -0
  40. {gitops-1.1.1 → gitops-1.2.0}/charts/gitops/values.yaml +0 -0
  41. {gitops-1.1.1 → gitops-1.2.0}/docker-compose.yml +0 -0
  42. {gitops-1.1.1 → gitops-1.2.0}/gitops/common/__init__.py +0 -0
  43. {gitops-1.1.1 → gitops-1.2.0}/gitops/common/app.py +0 -0
  44. {gitops-1.1.1 → gitops-1.2.0}/gitops/common/utils.py +0 -0
  45. {gitops-1.1.1 → gitops-1.2.0}/gitops/core.py +0 -0
  46. {gitops-1.1.1 → gitops-1.2.0}/gitops/main.py +0 -0
  47. {gitops-1.1.1 → gitops-1.2.0}/gitops/py.typed +0 -0
  48. {gitops-1.1.1 → gitops-1.2.0}/gitops/settings.py +0 -0
  49. {gitops-1.1.1 → gitops-1.2.0}/gitops/shorthands.py +0 -0
  50. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/__init__.py +0 -0
  51. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/async_runner.py +0 -0
  52. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/cli.py +0 -0
  53. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/exceptions.py +0 -0
  54. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/images.py +0 -0
  55. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/kube.py +0 -0
  56. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/tags.py +0 -0
  57. {gitops-1.1.1 → gitops-1.2.0}/gitops/utils/yaml.py +0 -0
  58. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/CHANGELOG.md +0 -0
  59. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/README.md +0 -0
  60. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/__init__.py +0 -0
  61. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/app.py +0 -0
  62. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/settings.py +0 -0
  63. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/types.py +0 -0
  64. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/utils/__init__.py +0 -0
  65. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/utils/git.py +0 -0
  66. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/utils/github.py +0 -0
  67. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/utils/slack.py +0 -0
  68. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/workers/deployer/__init__.py +0 -0
  69. {gitops-1.1.1 → gitops-1.2.0}/gitops_server/workers/deployer/worker.py +0 -0
  70. {gitops-1.1.1 → gitops-1.2.0}/release-please-config.json +0 -0
  71. {gitops-1.1.1 → gitops-1.2.0}/release.py +0 -0
  72. {gitops-1.1.1 → gitops-1.2.0}/ruff.toml +0 -0
  73. {gitops-1.1.1 → gitops-1.2.0}/secrets.example.env +0 -0
  74. {gitops-1.1.1 → gitops-1.2.0}/setup.cfg +0 -0
  75. {gitops-1.1.1 → gitops-1.2.0}/tests/__init__.py +0 -0
  76. {gitops-1.1.1 → gitops-1.2.0}/tests/conftest.py +0 -0
  77. {gitops-1.1.1 → gitops-1.2.0}/tests/sample_data.py +0 -0
  78. {gitops-1.1.1 → gitops-1.2.0}/tests/test_app.py +0 -0
  79. {gitops-1.1.1 → gitops-1.2.0}/tests/test_core.py +0 -0
  80. {gitops-1.1.1 → gitops-1.2.0}/tests/test_deploy.py +0 -0
  81. {gitops-1.1.1 → gitops-1.2.0}/tests/test_git.py +0 -0
  82. {gitops-1.1.1 → gitops-1.2.0}/tests/test_utils.py +0 -0
  83. {gitops-1.1.1 → gitops-1.2.0}/tests/utils.py +0 -0
  84. {gitops-1.1.1 → gitops-1.2.0}/tests/webhook_sample_data.py +0 -0
  85. {gitops-1.1.1 → gitops-1.2.0}/uv.lock +0 -0
@@ -0,0 +1,5 @@
1
+ {
2
+ ".": "1.2.0",
3
+ "gitops_server": "0.15.1",
4
+ "charts/gitops": "1.1.2"
5
+ }
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.2.0](https://github.com/uptick/gitops/compare/gitops-v1.1.2...gitops-v1.2.0) (2025-03-17)
4
+
5
+
6
+ ### Features
7
+
8
+ * **cli:** allow filtering apps via a csv file ([f465d9a](https://github.com/uptick/gitops/commit/f465d9a8ad565afde1f9bf7f9d1232281352882c))
9
+ * **cli:** allow filtering apps via a csv file ([7fa06cd](https://github.com/uptick/gitops/commit/7fa06cd6d8ca42a2d1e50304ad7cba7e688650e9))
10
+
11
+
12
+ ### Bug Fixes
13
+
14
+ * remove status updater and replace with a post deploy hook ([e72c2ad](https://github.com/uptick/gitops/commit/e72c2ad2b46304f2258d7b3d1bb04e4200ce1602))
15
+
16
+ ## [1.1.2](https://github.com/uptick/gitops/compare/gitops-v1.1.1...gitops-v1.1.2) (2025-02-14)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * **helm:** if a roll back is required; rollback before upgrading ([762cdb3](https://github.com/uptick/gitops/commit/762cdb388162c6b8645ec01f0d1c94c20d948b9f))
22
+
3
23
  ## [1.1.1](https://github.com/uptick/gitops/compare/gitops-v1.1.0...gitops-v1.1.1) (2025-01-24)
4
24
 
5
25
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitops
3
- Version: 1.1.1
3
+ Version: 1.2.0
4
4
  Summary: Manage multiple apps across one or more k8s clusters.
5
5
  Author-email: Jarek Głowacki <jarekwg@gmail.com>
6
6
  License-File: LICENSE
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.1.2](https://github.com/uptick/gitops/compare/helm-v1.1.1...helm-v1.1.2) (2025-02-14)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * remove gitops resource limits ([fcd9680](https://github.com/uptick/gitops/commit/fcd9680f6e94e5cb7a286c269aeaa1626c95a181))
9
+
3
10
  ## [1.1.1](https://github.com/uptick/gitops/compare/helm-v1.1.0...helm-v1.1.1) (2025-01-24)
4
11
 
5
12
 
@@ -2,4 +2,4 @@ apiVersion: v1
2
2
  appVersion: "1.0"
3
3
  description: GitOps Server Helm chart.
4
4
  name: gitops
5
- version: 1.1.1
5
+ version: 1.1.2
@@ -40,8 +40,6 @@ spec:
40
40
  resources:
41
41
  requests:
42
42
  memory: "750Mi"
43
- limits:
44
- memory: "1500Mi"
45
43
 
46
44
  envFrom:
47
45
  - configMapRef:
@@ -6,7 +6,7 @@ from gitops.utils.apps import App, get_app_details, get_apps
6
6
 
7
7
  from .utils.cli import success, warning
8
8
 
9
- __version__ = "1.1.1"
9
+ __version__ = "1.2.0"
10
10
 
11
11
 
12
12
  # Checking gitops version matches cluster repo version.
@@ -1,3 +1,4 @@
1
+ import pathlib
1
2
  import sys
2
3
  from pathlib import Path
3
4
  from typing import Literal
@@ -77,6 +78,9 @@ def get_apps( # noqa: C901
77
78
  `exclude`. The incoming filter and exclude params may come in as a list or commastring.
78
79
  For the purpose of this filtering, app names and image tag prefixes are also considered as
79
80
  tags. For instance, you can do get_apps(tags=[emeriss, production], exclude=[arafire]).
81
+
82
+ If filter is a file like name; read a list of app names from the file.
83
+
80
84
  Calling this method without any args returns all apps.
81
85
  There are three modes for communicating selected apps to the user:
82
86
  - PROMPT: Prints selected apps and asks for confirmation to proceed.
@@ -84,8 +88,13 @@ def get_apps( # noqa: C901
84
88
  - SILENT: Proceeds without printing.
85
89
  Apps with the `inactive` tag are excluded by default, unless requested otherwise.
86
90
  """
91
+ app_names: list[str] = []
92
+
87
93
  if filter == "all":
88
94
  filter = set()
95
+ elif isinstance(filter, str) and pathlib.Path(filter).is_file():
96
+ app_names = [f.strip() for f in pathlib.Path(filter).read_text().splitlines() if f.strip()]
97
+ filter = set()
89
98
  else:
90
99
  filter = set(filter.split(",") if filter and isinstance(filter, str) else filter)
91
100
 
@@ -114,7 +123,12 @@ def get_apps( # noqa: C901
114
123
 
115
124
  tags = set(app.tags + pseudotags)
116
125
  existing_tags |= tags
117
- if filter <= tags and not exclude & tags:
126
+
127
+ # Decide whether to include the app based on the filter and exclude tags.
128
+ if app_names:
129
+ if app.name in app_names:
130
+ apps.append(app)
131
+ elif filter <= tags and not exclude & tags:
118
132
  apps.append(app)
119
133
 
120
134
  validate_tags(filter | exclude, existing_tags)
@@ -13,7 +13,7 @@ from uptick_observability.logging import ( # type: ignore[import-untyped]
13
13
 
14
14
  from gitops_server import settings
15
15
  from gitops_server.app import app
16
- from gitops_server.workers import DeploymentStatusWorker, DeployQueueWorker
16
+ from gitops_server.workers import DeployQueueWorker
17
17
 
18
18
  manually_instrument_logging()
19
19
  manually_instrument_fastapi()
@@ -64,9 +64,6 @@ async def startup_event():
64
64
  deploy_queue_worker = DeployQueueWorker.get_worker()
65
65
  deploy_queue_worker.task = asyncio.ensure_future(deploy_queue_worker.run(), loop=loop)
66
66
 
67
- deployment_status_worker = DeploymentStatusWorker.get_worker()
68
- deployment_status_worker.task = asyncio.ensure_future(deployment_status_worker.run(), loop=loop)
69
-
70
67
 
71
68
  def get_digest(data: bytes) -> str:
72
69
  """Calculate the digest of a webhook body.
@@ -0,0 +1 @@
1
+ __version__ = "1.2.0"
@@ -0,0 +1 @@
1
+ from .deployer import DeployQueueWorker # NOQA
@@ -11,7 +11,7 @@ from opentelemetry import trace
11
11
 
12
12
  from gitops.common.app import App
13
13
  from gitops_server import settings
14
- from gitops_server.types import AppDefinitions, UpdateAppResult
14
+ from gitops_server.types import AppDefinitions, RunOutput, UpdateAppResult
15
15
  from gitops_server.utils import get_repo_name_from_url, github, run, slack
16
16
  from gitops_server.utils.git import temp_repo
17
17
 
@@ -133,6 +133,17 @@ class Deployer:
133
133
  )
134
134
  return update_result
135
135
 
136
+ async def rollback_deployment(self, app: App) -> None:
137
+ with tracer.start_as_current_span("rollback_deployment", attributes={"app": app.name}):
138
+ logger.warning(
139
+ "Rolling back %s deployment due to previous failed helm install",
140
+ app.name,
141
+ )
142
+ await run(
143
+ f"helm rollback --namespace={app.namespace} {app.name}",
144
+ suppress_errors=True,
145
+ )
146
+
136
147
  async def update_app_deployment(self, app: App) -> UpdateAppResult | None:
137
148
  app.set_value("deployment.labels.gitops/deploy_id", self.deploy_id)
138
149
  app.set_value("deployment.labels.gitops/status", github.STATUSES.in_progress)
@@ -155,6 +166,40 @@ class Deployer:
155
166
  os.fsync(cfg.fileno())
156
167
 
157
168
  with tracer.start_as_current_span("helm_upgrade"):
169
+
170
+ async def upgrade_helm_git() -> RunOutput:
171
+ result = await run(
172
+ "helm secrets upgrade --create-namespace"
173
+ f" --history-max {MAX_HELM_HISTORY}"
174
+ " --install"
175
+ " --timeout=600s"
176
+ f"{' --set skip_migrations=true' if self.skip_migrations else ''}"
177
+ f" -f {cfg.name}"
178
+ f" --namespace={app.namespace}"
179
+ f" {app.name}"
180
+ f" {chart_folder_path}",
181
+ suppress_errors=True,
182
+ )
183
+ return result
184
+
185
+ result = await upgrade_helm_git()
186
+ if result["exit_code"] != 0 and "is in progress" in result["output"]:
187
+ await self.rollback_deployment(app)
188
+ result = await upgrade_helm_git()
189
+
190
+ elif app.chart.type == "helm":
191
+ span.set_attribute("gitops.chart.type", "helm")
192
+ with tempfile.NamedTemporaryFile(suffix=".yml") as cfg:
193
+ cfg.write(json.dumps(app.values).encode())
194
+ cfg.flush()
195
+ os.fsync(cfg.fileno())
196
+ chart_version_arguments = f" --version={app.chart.version}" if app.chart.version else ""
197
+ with tracer.start_as_current_span("helm_repo_add"):
198
+ await run(f"helm repo add {app.chart.helm_repo} {app.chart.helm_repo_url}")
199
+
200
+ with tracer.start_as_current_span("helm_upgrade"):
201
+
202
+ async def upgrade_helm_chart() -> RunOutput:
158
203
  result = await run(
159
204
  "helm secrets upgrade --create-namespace"
160
205
  f" --history-max {MAX_HELM_HISTORY}"
@@ -164,32 +209,15 @@ class Deployer:
164
209
  f" -f {cfg.name}"
165
210
  f" --namespace={app.namespace}"
166
211
  f" {app.name}"
167
- f" {chart_folder_path}",
212
+ f" {app.chart.helm_chart} {chart_version_arguments}",
168
213
  suppress_errors=True,
169
214
  )
170
- elif app.chart.type == "helm":
171
- span.set_attribute("gitops.chart.type", "helm")
172
- with tempfile.NamedTemporaryFile(suffix=".yml") as cfg:
173
- cfg.write(json.dumps(app.values).encode())
174
- cfg.flush()
175
- os.fsync(cfg.fileno())
176
- chart_version_arguments = f" --version={app.chart.version}" if app.chart.version else ""
177
- with tracer.start_as_current_span("helm_repo_add"):
178
- await run(f"helm repo add {app.chart.helm_repo} {app.chart.helm_repo_url}")
215
+ return result
179
216
 
180
- with tracer.start_as_current_span("helm_upgrade"):
181
- result = await run(
182
- "helm secrets upgrade --create-namespace"
183
- f" --history-max {MAX_HELM_HISTORY}"
184
- " --install"
185
- " --timeout=600s"
186
- f"{' --set skip_migrations=true' if self.skip_migrations else ''}"
187
- f" -f {cfg.name}"
188
- f" --namespace={app.namespace}"
189
- f" {app.name}"
190
- f" {app.chart.helm_chart} {chart_version_arguments}",
191
- suppress_errors=True,
192
- )
217
+ result = await upgrade_helm_chart()
218
+ if result["exit_code"] != 0 and "is in progress" in result["output"]:
219
+ await self.rollback_deployment(app)
220
+ result = await upgrade_helm_chart()
193
221
  else:
194
222
  logger.warning("Local is not implemented yet")
195
223
  return None
@@ -50,10 +50,13 @@ async def update_issue_from_deployment_url(app: App, deployment_url: str, **kwar
50
50
 
51
51
  async def handle_successful_deploy(app: App, result, deployer, **kwargs) -> UpdateAppResult:
52
52
  github_deployment_url = str(app.values.get("github/deployment_url", ""))
53
+ # I know this shouldn't be uptick specific but for now it is.
54
+ environment_url = app.values.get("github/environment_url", "") or f"https://{app.name}.onuptick.com"
53
55
  await github.update_deployment(
54
56
  github_deployment_url,
55
- status=github.STATUSES.in_progress,
57
+ status=github.STATUSES.success,
56
58
  description="Helm installed app into cluster. Waiting for pods to deploy.",
59
+ environment_url=environment_url,
57
60
  )
58
61
  return result
59
62
 
@@ -1,7 +1,7 @@
1
1
 
2
2
  [project]
3
3
  name = "gitops"
4
- version = "1.1.1"
4
+ version = "1.2.0"
5
5
  description = "Manage multiple apps across one or more k8s clusters."
6
6
  requires-python = ">=3.12"
7
7
  readme = "README.md"
@@ -31,14 +31,3 @@ def test_webhook_returns_200_if_hmac_is_correct():
31
31
 
32
32
  assert response.status_code == 200
33
33
  get_worker_mock.assert_called()
34
-
35
-
36
- @patch("gitops_server.main.settings.GITHUB_WEBHOOK_KEY", "test_key")
37
- def test_webhook_returns_400_if_hmac_is_invalid():
38
- sha_encoding = "INVALID HMAC ENCODING"
39
- headers["X-Hub-Signature"] = f"sha1={sha_encoding}"
40
-
41
- with patch.object(gitops_server.workers.DeploymentStatusWorker, "get_worker", AsyncMock):
42
- response = client.post("/webhook", headers=headers, json=payload)
43
-
44
- assert response.status_code == 400
@@ -1,5 +0,0 @@
1
- {
2
- ".": "1.1.1",
3
- "gitops_server": "0.15.1",
4
- "charts/gitops": "1.1.1"
5
- }
@@ -1 +0,0 @@
1
- __version__ = "1.1.1"
@@ -1,2 +0,0 @@
1
- from .deployer import DeployQueueWorker # NOQA
2
- from .status_updater import DeploymentStatusWorker # NOQA
@@ -1 +0,0 @@
1
- from .worker import DeploymentStatusWorker # NOQA
@@ -1,126 +0,0 @@
1
- """
2
- This async worker keeps tracks of ongoing deployments by polling k8s space (CLUSTER_NAMESPACE).
3
-
4
- The worker polls and checks for deployments with the following labels: gitops/deploy_id and gitops/status=in_progress
5
-
6
- Any failing/successfully deployed deployment is notified to github.
7
- This mechanism will only work if the annotation: github/deployment_url is applied to the deployment.
8
-
9
- TODO
10
- - Update the slack summary message from deploy.py
11
- - @notify the user if the deployment failed
12
- """
13
-
14
- import asyncio
15
- import logging
16
-
17
- import kubernetes_asyncio # type:ignore[import-untyped]
18
- import kubernetes_asyncio.client # type:ignore[import-untyped]
19
- import kubernetes_asyncio.config # type:ignore[import-untyped]
20
-
21
- from gitops_server.settings import CLUSTER_NAMESPACE
22
- from gitops_server.utils import github
23
-
24
- logger = logging.getLogger("deployment_status")
25
-
26
-
27
- async def get_ingress_url(api, namespace: str, app: str):
28
- """Attempts to get domain for the ingress associated with the app"""
29
- ingresses = await kubernetes_asyncio.client.NetworkingV1Api(api).list_namespaced_ingress(
30
- namespace=namespace, label_selector=f"app={app}"
31
- )
32
- environment_url = ""
33
- if ingresses.items:
34
- try:
35
- environment_url = "https://" + ingresses.items[0].spec.rules[0].host
36
- except Exception:
37
- logger.warning(f"Could not find ingress for {app=}")
38
- return environment_url
39
-
40
-
41
- class DeploymentStatusWorker:
42
- """Watches for deployments and updates the github deployment status"""
43
-
44
- _worker = None
45
-
46
- @classmethod
47
- def get_worker(cls):
48
- if not cls._worker:
49
- loop = asyncio.get_running_loop()
50
- cls._worker = cls(loop)
51
- return cls._worker
52
-
53
- def __init__(self, loop):
54
- self.loop = loop
55
-
56
- async def load_config(self):
57
- try:
58
- kubernetes_asyncio.config.load_incluster_config()
59
- except kubernetes_asyncio.config.config_exception.ConfigException:
60
- await kubernetes_asyncio.config.load_kube_config()
61
-
62
- async def process_work(self):
63
- await asyncio.sleep(5)
64
- async with kubernetes_asyncio.client.ApiClient() as api:
65
- apps_api = kubernetes_asyncio.client.AppsV1Api(api)
66
- deployments = await apps_api.list_namespaced_deployment(
67
- # Only things that have gitops/deploy_id aka was deployed
68
- namespace=CLUSTER_NAMESPACE,
69
- label_selector="gitops/deploy_id,gitops/status=in_progress",
70
- )
71
- await asyncio.sleep(5)
72
-
73
- for deployment in deployments.items:
74
- # Deployment status may not exist yet
75
- if not deployment.status:
76
- continue
77
- app = deployment.metadata.labels["app"]
78
- namespace = deployment.metadata.namespace
79
- github_deployment_url = deployment.metadata.annotations.get("github/deployment_url")
80
- conds = {}
81
- for x in deployment.status.conditions:
82
- conds[x.type] = x
83
- status = None
84
- if (
85
- len(conds) == 2
86
- and conds["Available"].status == "True"
87
- and conds["Progressing"].status == "True"
88
- and conds["Progressing"].reason == "NewReplicaSetAvailable"
89
- ):
90
- status = github.STATUSES.success
91
- await github.update_deployment(
92
- github_deployment_url,
93
- status=status,
94
- description="Deployed successfully",
95
- environment_url=await get_ingress_url(api, namespace, app),
96
- )
97
- elif (
98
- "Progressing" in conds
99
- and conds["Progressing"].status == "False"
100
- and conds["Progressing"].reason == "ProgressDeadlineExceeded"
101
- ):
102
- status = github.STATUSES.failure
103
- await github.update_deployment(
104
- github_deployment_url,
105
- status=status,
106
- description="Failed to deploy. Check the pod or migrations.",
107
- )
108
- if status:
109
- logger.info(f"Patching {deployment.metadata.name}.label.gitops/status to {status}")
110
- patch = {"metadata": {"labels": {"gitops/status": status}}}
111
- try:
112
- await apps_api.patch_namespaced_deployment(
113
- deployment.metadata.name, deployment.metadata.namespace, patch
114
- )
115
- except kubernetes_asyncio.client.exceptions.ApiException as e:
116
- logger.warning(e, exc_info=True)
117
-
118
- async def run(self):
119
- logger.info("Starting deployment status watching loop")
120
- logger.info("Loading kubernetes asyncio api")
121
- while True:
122
- try:
123
- await self.load_config()
124
- await self.process_work()
125
- except Exception as e:
126
- logger.error(str(e), exc_info=True)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes