Health check on container instances - #2570
Conversation
Coverage reportClick to see where and how coverage changed
This report was generated by python-coverage-comment-action |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
JimMadge
left a comment
There was a problem hiding this comment.
Oh, interesting 🤔.
Where were you seeing this going in the medium/long term?
Some things feel a bit odd,
- using pytest for these checks
- A CLI for this rather than a dashboard
Those things feel a bit more reasonable when we think about scaling this to other tests though. That said, we are probably only using 1% of pytest and it might be simpler to write test class of our own.
When talking about containers, it would be good to add a health check too, on top of checking the containers are running. I'm not sure if all of the containers we use have an appropriate HEALTHCHECK defined, but we could add them. Looks like in ACI this is called liveness probe.
|
Hi @JimMadge , thanks for your comments. Regarding your questions:
Hopefully this makes sense. Please let me know if you have further questions. |
|
I think the longer term plan makes sense, but we need to do more now to plan what that will look like. Container status/healthchecks feels like a sensible place to start. Running pulumi refresh in check mode also feels like an obvious starting point. I feel pytest is the wrong library to use here. It is really focused on code testing, which isn't what we are doing. Parametrising test functions and formatting the output shouldn't be very difficult, and I think going with pytest we are likely to run in to problems in the future with the way it handles exceptions and reports errors. I think what we really want is a function with returns a test result (or even just a boolean) and then format sensible output from that. |
|
@JimMadge , I'm still not entirely clear on the concrete technical problems we would encounter in a hypothetical future by using However, this feature is not been progressed for two weeks and I'm feeling some urgency for getting closer to the medium/long term plan. Also, as you mentioned, the |
|
@JimMadge here's a pytest-free version of this PR. Still working as expected: |
JimMadge
left a comment
There was a problem hiding this comment.
I think this is looking good. I'm finding the structure quite complex and maybe over engineered though.
Couldn't we just have a HealthCheck ABC, and sublcass it as we need, maybe like ContainerHealthCheck(HeathCheck) PackageContainerHealthCheck(ContainerHealthCheck). Which is, more or less what is here, but I don't like the implicit way typing.Protocol works.
We could also make factories, but I think classes make sense because we are likely to want helper methods as well as the run method.
For executing, I have used decorators before to add functions to a list. So you could have something like,
health_check_instances = []
class MyCheck(HealthCheck):
def run(self, ...):
...
@health_check_instance
MyCheck(case1)
@health_check_instance
MyCheck(case2)
for instances in health_check_instances:
result = instance()
handle_result(result)How does that sound to you?
| container_group_name=self.container_group_name, | ||
| ) | ||
|
|
||
| return typing.cast(list[Container], container_group.containers) |
There was a problem hiding this comment.
Is this because container_group.containers isn't actually a list[Container]?
| @@ -0,0 +1,70 @@ | |||
| from attrs import define | |||
There was a problem hiding this comment.
Any reason to use this over dataclasses.dataclass?
attrs isn't an explicit dependency, and we are already using dataclasses elsewhere.
| self.software_repository_params: dict[str, str] | None = sre_stack.output( | ||
| "software_repositories" | ||
| ) | ||
| self.software_repository_params: dict[str, str] | None = None | ||
|
|
||
| try: | ||
| self.software_repository_params = sre_stack.output("software_repositories") | ||
| except KeyError: | ||
| self.logger.info( | ||
| "There's no software repositories information in the current SRE" | ||
| ) |
There was a problem hiding this comment.
Is this a bug fix, can we put it in a different PR?
We shouldn't use exception handling for flow control if we can avoid it. Hopefully we can do a if "software_repositories" in ... here.
| @define | ||
| class SREHeathCheckPlugin: | ||
|
|
||
| _sre_project_manager: SREProjectManager | ||
| _subscription_name: AzureSubscriptionName | ||
| _sre_config: SREConfig | ||
|
|
||
| @property | ||
| def project_manager(self) -> SREProjectManager: | ||
| return self._sre_project_manager | ||
|
|
||
| @property | ||
| def subscription_name(self) -> AzureSubscriptionName: | ||
| return self._subscription_name | ||
|
|
||
| @property | ||
| def sre_config(self) -> SREConfig: | ||
| return self._sre_config |
There was a problem hiding this comment.
What is this class for? It is just aliasing three variables.
| class HealthCheckTest(Protocol): | ||
|
|
||
| def check(self, plugin: SREHeathCheckPlugin) -> str: ... |
There was a problem hiding this comment.
I don't like the implicit way classes are assigned. I think it would be better to make an ABC for health checks
| class HealthCheckError(Exception): | ||
| pass |
There was a problem hiding this comment.
We collect our exceptions in the exceptions module.
|
|
||
|
|
||
| @define | ||
| class SREHealthCheckRunner: |
There was a problem hiding this comment.
Is there a benefit to this being a class? Feels like it is just a function.
| self._logger.info(f"\u2705 {success_message}") | ||
| except HealthCheckError as error: | ||
| self._logger.info(f"\u274c {error.args[0]}") |
There was a problem hiding this comment.
Rich has support for emoji codes that are more human readable.

✅ Checklist
Enable foobar integrationrather than515 foobar).develop.🚦 Depends on
N/A
dsh sre healthcheck(seesre.py).AzureContainerInstanetype, so it can now return all the containers in the container group (seeazure_container_instance.py). We'll use this method in assertions (seehealthcheck_utils.py).pytest(seesre_healtchcheck_runner.py). To that end, we have developed a plugin to provide tests with information of the stack, the subscription, and the SRE config file (seehealthcheck_plugin.py).test_container_instance.pyandpyproject.toml). We need to add some logic to handle Nexus containers, since it's not deployed in T0/T1.infrastructure/programs/sre/*.py). We use this information to gather container group information.🌂 Related issues
Contributes towards #2568
🔬 Tests
Tested on a Tier 2 and a Tier 0 SREs (below):