-
Notifications
You must be signed in to change notification settings - Fork 244
add setup_namespace_services #4167
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
af4acb5 to
529251a
Compare
this manages per-namespace k8s services in a cluster. largely based on what had previously been build in setup_istio_mesh.py, which is now unused. tidy up what's left of the old setup_istio_mesh code, too.
529251a to
3953cb2
Compare
nemacysts
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mostly just nits outside of get_service_kube_namespace() probably needing to actually read the service config to get the correct k8s namespace
| def get_service_kube_namespace(service: str) -> str: | ||
| return f"paastasvc-{sanitise_kubernetes_name(service)}" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think we'll need to load the actual config so that we can use the namespace getter - we allow folks to set custom namespaces and there's a small number of services still in the paasta namespace :(
| def is_external_routing_enabled(config: Mapping) -> bool: | ||
| """Check if external routing is enabled for a namespace config. | ||
|
|
||
| Args: | ||
| config: Namespace configuration dict | ||
|
|
||
| Returns: | ||
| True if routing.external is set to True | ||
| """ | ||
| routing_cfg = config.get("routing", {}) | ||
| if not isinstance(routing_cfg, Mapping): | ||
| return False | ||
| return bool(routing_cfg.get("external")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo, this might be better placed in the instance class (and we can probably assume that these are in the right format/type due to the schema, right?)
| if prometheus_port and all( | ||
| port.container_port != prometheus_port for port in ports | ||
| ): | ||
| ports.append(V1ContainerPort(container_port=prometheus_port)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if prometheus_port and all( | |
| port.container_port != prometheus_port for port in ports | |
| ): | |
| ports.append(V1ContainerPort(container_port=prometheus_port)) | |
| if prometheus_port and prometheus_port != self.get_container_port(): | |
| ports.append(V1ContainerPort(container_port=prometheus_port)) |
should be the same since the only other port we're adding a V1ContainerPort for is the app one, right?
| try: | ||
| with open(file_path) as f: | ||
| svc_namespaces = yaml.safe_load(f) | ||
| if not isinstance(svc_namespaces, Mapping): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo, we can probably skip the isinstance checks - we should be guaranteed to see valid smartstack.yaml files since there's a schema
| return f"paastasvc-{sanitise_kubernetes_name(service)}" | ||
|
|
||
|
|
||
| def is_external_routing_enabled(config: Mapping) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
heh, i guess we don't have a typed dict for smartstack configs - maybe next year (:p)!
| patch_kwargs = dict( | ||
| name=service.metadata.name, | ||
| namespace=kube_namespace, | ||
| body=serialized, | ||
| field_manager=FIELD_MANAGER, | ||
| force=True, | ||
| content_type="application/apply-patch+yaml", | ||
| ) | ||
| if dry_run: | ||
| patch_kwargs["dry_run"] = "All" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
imo, it'd be nice to keep using client-side apply just to avoid having to manage these kwargs dicts :p
(paasta is the only thing managing these, so SSA/client-side shouldn't be particularly different)
it is somewhat nice to have the server do validation for dry-runs, but not 100% sure how much more safety that buys us since these are pretty simple objects
| try: | ||
| kube_client.core.create_namespaced_service(**create_kwargs) | ||
| created = True | ||
| if not dry_run: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
technically we don't need this since we're setting dry_run to true, right?
|
|
||
| create_kwargs = dict(namespace=kube_namespace, body=service) | ||
| if dry_run: | ||
| create_kwargs["dry_run"] = "All" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we wanna SSA this, we're missing the other kwargs here, right?
| if created and not dry_run: | ||
| log.warning( | ||
| f"Rolling back Service {kube_namespace}/{service.metadata.name} after apply error" | ||
| ) | ||
| try: | ||
| kube_client.core.delete_namespaced_service( | ||
| name=service.metadata.name, | ||
| namespace=kube_namespace, | ||
| ) | ||
| except Exception: | ||
| log.exception( | ||
| f"Failed to rollback Service {kube_namespace}/{service.metadata.name} after apply error" | ||
| ) | ||
| raise |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I wonder if we should just create the Service as we'd want it to look over Create+Patch?
(i think that's the pattern we take in skj and whatnot - 3 different paths for create vs modify vs delete)
| svc = build_namespace_service(kube_namespace, namespace) | ||
| try: | ||
| server_side_apply_service(kube_client, kube_namespace, svc, dry_run) | ||
| yield (True, f"Reconciled Service {kube_namespace}/{svc.metadata.name}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume we're using an iterator here to avoid having to maintain a list of results to return at the end?
building on @wjhoward's work in #4164 manage per-namespace k8s services in a cluster. largely based on what had previously been build in setup_istio_mesh.py, which is now unused.
tidy up what's left of the old setup_istio_mesh code, too.
Notable changes:
nameparam to theContainerPortwe add for the service. This means I don't have to lookup the correct container_port for the service (and hope they're not different between backends in a service), but k8s can figure out which one to use by name. NB: will trigger a big bounceLimitations:
paastasvc-$servicewon't show up.registrationsfor a namespace belonging to a different service won't show up.