Skip to content

Add kind: Elasticsearch to black_list so it is not marked for deletion - #988

Merged
mvallati merged 1 commit into
mainfrom
do-no-prune-es
Oct 20, 2025
Merged

Add kind: Elasticsearch to black_list so it is not marked for deletion#988
mvallati merged 1 commit into
mainfrom
do-no-prune-es

Conversation

@mvallati

@mvallati mvallati commented Oct 15, 2025

Copy link
Copy Markdown
Contributor

TLDR of what we're trying to accomplish with this PR

Relevant issue: https://github.com/shop/issues-search-platform/issues/493

This PR adds the Elasticsearch resource type to the black_list so that it is not marked for deletion if someone removes it from their manifest files. We are also emitting a metric so that we know if an Elasticsearch resource was removed from an app's manifest files so that we can be alerted.

The problem we need to solve

This is a necessary part of the search platform's team to migrate apps over to the search control plane and to the infrastructure monorepo. We have a step-wise process for apps:

  1. migrate to the search control plane and DO NOT delete their kind: Elasticsearch from their manifest files
  2. migrate to the infrastructure monorepo where the kind: Elasticsearch will be removed from their app

Since these 2 steps are not done in immediate succession, there's the opportunity for teams to accidentally delete their kind: Elasticsearch. This is a plausible scenario because their elasticsearch instance is now being deployed via the search control plane, and it's easy for the communication of DO NOT DELETE. to get lost overtime.

If the Elasticsearch resource were to be accidentally deleted, it will break their elasticsearch, and it may not be recoverable. Adding Elasticsearch to the black_list will prevent apps from entering this state, and will ensure their elasticsearch continues to run and exist while they wait to complete step 2 and migrate to the infrastructure monorepo.

Why the metric?

We added the metric so that we can alert on it in the even a team does remove their kind: Elasticsearch from their manifests files. If we do not alert, we will have no way of knowing this has occurred. If the app has not migrated to the infrastructure monorepo and removes their kind: Elasticsearch, we will need to add it back to their manifest files until they have migrated to the monorepo. Otherwise, the Elasticsearch will be orphaned and no longer connected to the app. This will be problematic if the app is migrated to a new cluster (gcp version upgrades, regional evacuation), the Elasticsearch would not be tied to the app and would not migrate with it, and it would likely not be recoverable. We will determine as a team how we want to use this alert and will create a playbook.

Worth mentioning

As a result of this change that no Elasticsearch resources will be deleted. We will either have to manually delete them when apps successfully migrate to the infrastructure monorepo, or they will remained orphaned and will be deleted when the kubernetes cluster is deleted. There is no "problem" with them being orphaned, other than that they are not being used and costing money to do nothing.

@mvallati mvallati changed the title Add kind: Elasticsearch to black_list so it is not pruned Add kind: Elasticsearch to black_list so it is not marked for deletion Oct 15, 2025
@mvallati
mvallati marked this pull request as ready for review October 15, 2025 12:40
Comment thread lib/krane/cluster_resource_discovery.rb Outdated
result = fetch_resources(namespaced: namespaced).map do |resource|
next unless resource["verbs"].one? { |v| v == "delete" }
if resource["kind"] == "Elasticsearch"
elasticsearch_found = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be simplified if we don't use the elasticsearch_found variable entirely and instead just emit the metric here like:

StatsD.client.gauge('elasticsearch_resources.count', 1, tags: @namespace_tags) if resource["kind"] == "Elasticsearch"

Comment thread lib/krane/cluster_resource_discovery.rb Outdated
next unless resource["verbs"].one? { |v| v == "delete" }
if resource["kind"] == "Elasticsearch"
elasticsearch_found = true
next

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This next is a bit redundant since the next line:

next if black_list.include?(resource["kind"])

would cover Elasticsearch anyways.

Comment thread lib/krane/cluster_resource_discovery.rb Outdated
[resource["apigroup"], resource["version"], resource["kind"]].compact.join("/")
end.compact

StatsD.client.gauge('elasticsearch_resources.count', 1, tags: @namespace_tags) if elasticsearch_found

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both can work but I think a counter could make more sense here instead of a gauge since the number of times that a specific app can fail will keep going up.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming of the metric could be something more specific as well. Essentially this metric tells us when the resource was attempted to be deleted so the name should reflect that as well.

Comment thread lib/krane/cluster_resource_discovery.rb Outdated
[resource["apigroup"], resource["version"], resource["kind"]].compact.join("/")
end.compact

StatsD.client.gauge('elasticsearch_resources.count', 1, tags: @namespace_tags) if elasticsearch_found

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you verify what is actually stored in @namespace_tags at this point in time? Tracing back where it is used in this file in the CustomResourceDefinition model which inherits from the KubernetesResrouce model, the constructor makes it seem like its for extra optional statsd tags

Comment thread lib/krane/cluster_resource_discovery.rb Outdated
black_list = %w(Namespace Node ControllerRevision Event)
fetch_resources(namespaced: namespaced).map do |resource|
black_list = %w(Namespace Node ControllerRevision Event Elasticsearch)
result = fetch_resources(namespaced: namespaced).map do |resource|

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could probably keep what was previously there and no need to assign this to result and instead just have fetch_resources() as the last function call in this function.

Comment thread lib/krane/cluster_resource_discovery.rb Outdated
[resource["apigroup"], resource["version"], resource["kind"]].compact.join("/")
end.compact

result

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can remove this, see previous comment

Comment thread lib/krane/cluster_resource_discovery.rb Outdated
fetch_resources(namespaced: namespaced).map do |resource|
next unless resource["verbs"].one? { |v| v == "delete" }
if resource["kind"] == "Elasticsearch"
StatsD.client.count('elasticsearch_resource_deletion_attempt.count', 1, tags: namespace)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The format that tags expects is something on the lines of https://github.com/Shopify/krane/blob/main/lib/krane/kubernetes_resource.rb#L602-L614

So its <label>:<value> stored in an array

@mvallati
mvallati force-pushed the do-no-prune-es branch 2 times, most recently from 3bf1922 to 2b780c6 Compare October 15, 2025 20:46
@mvallati
mvallati requested a review from kkwan3 October 16, 2025 13:21
Comment thread lib/krane/cluster_resource_discovery.rb Outdated
fetch_resources(namespaced: namespaced).map do |resource|
next unless resource["verbs"].one? { |v| v == "delete" }
if resource["kind"] == "Elasticsearch"
StatsD.client.count('elasticsearch_resource_deletion_attempt.count', 1, %W(context:#{context} namespace:#{namespace}))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tags need to be in the tags key when emitting the metric. Similar to

StatsD.client.increment('kubectl.error', 1, tags: { context: context, namespace: namespace, cmd: cmd[1],

Both count and increment should do very similar things but I would use whichever function is more used in this repo just to remain consistent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed it to increment to match existing code

@mvallati
mvallati requested a review from kkwan3 October 16, 2025 14:03
@mvallati
mvallati force-pushed the do-no-prune-es branch 3 times, most recently from 6048bd5 to df3ac2f Compare October 16, 2025 14:55
@mvallati
mvallati merged commit f4bdedb into main Oct 20, 2025
129 checks passed
@mvallati mvallati mentioned this pull request Oct 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants