diff --git a/CHANGELOG.md b/CHANGELOG.md index c5dee934b..f831dc423 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## next +*Other* +- Deprecate `kubernetes-deploy.shopify.io` annotations in favour of `krane.shopify.io`. + ## 0.27.0 *Enhancements* - (alpha) Introduce a new `-f` flag for `kubernetes-deploy`. Allows passing in of multiple directories and/or filenames. Currently only usable by `kubernetes-deploy`, not `kubernetes-render`. [#514](https://github.com/Shopify/kubernetes-deploy/pull/514) @@ -8,9 +11,6 @@ - **[Breaking change]** Added ServiceAccount, PodTemplate, ReplicaSet, Role, and RoleBinding to the prune whitelist. * To see what resources may be affected, run `kubectl get $RESOURCE -o jsonpath='{ range .items[*] }{.metadata.namespace}{ "\t" }{.metadata.name}{ "\t" }{.metadata.annotations}{ "\n" }{ end }' --all-namespaces | grep "last-applied"` * To exclude a resource from kubernetes-deploy (and kubectl apply) management, remove the last-applied annotation `kubectl annotate $RESOURCE $SECRET_NAME kubectl.kubernetes.io/last-applied-configuration-`. - -*Other* -- Deprecate `kubernetes-deploy.shopify.io` annotations in favour of `krane.shopify.io`. *Bug Fixes* - StatefulSets with 0 replicas explicitly specified don't fail deploy. [#540](https://github.com/Shopify/kubernetes-deploy/pull/540) diff --git a/lib/kubernetes-deploy/kubernetes_resource.rb b/lib/kubernetes-deploy/kubernetes_resource.rb index a5eaad930..7bfa40f66 100644 --- a/lib/kubernetes-deploy/kubernetes_resource.rb +++ b/lib/kubernetes-deploy/kubernetes_resource.rb @@ -95,7 +95,7 @@ def timeout def timeout_override return @timeout_override if defined?(@timeout_override) - @timeout_override = DurationParser.new(timeout_annotation).parse!.to_i + @timeout_override = DurationParser.new(krane_annotation_value("timeout-override")).parse!.to_i rescue DurationParser::ParsingError @timeout_override = nil end @@ -409,33 +409,35 @@ def global? private def validate_timeout_annotation - return if timeout_annotation.nil? + return if krane_annotation_value("timeout-override").nil? - override = DurationParser.new(timeout_annotation).parse! + override = DurationParser.new(krane_annotation_value("timeout-override")).parse! if override <= 0 - @validation_errors << "#{annotation_prefix} annotation is invalid: Value must be greater than 0" + @validation_errors << "#{timeout_annotation_key} annotation is invalid: Value must be greater than 0" elsif override > 24.hours - @validation_errors << "#{annotation_prefix} annotation is invalid: Value must be less than 24h" + @validation_errors << "#{timeout_annotation_key} annotation is invalid: Value must be less than 24h" end rescue DurationParser::ParsingError => e - @validation_errors << "#{annotation_prefix} annotation is invalid: #{e}" + @validation_errors << "#{timeout_annotation_key} annotation is invalid: #{e}" end def validate_annotation_version annotation_keys = @definition.dig("metadata", "annotations")&.keys - annotation_keys&.any? do |annotation| + annotation_keys&.each do |annotation| if annotation.include?("kubernetes-deploy.shopify.io") - @validation_warnings << "#{annotation} is deprecated: Use 'krane.shopify.io' annotations instead" + annotation_prefix = annotation.split('/').first + @validation_warnings << "#{annotation_prefix} as a prefix for annotations is deprecated: "\ + "Use the 'krane.shopify.io' annotation prefix instead" end end end - def timeout_annotation - @definition.dig("metadata", "annotations", TIMEOUT_OVERRIDE_ANNOTATION_DEPRECATED) || - @definition.dig("metadata", "annotations", TIMEOUT_OVERRIDE_ANNOTATION) + def krane_annotation_value(suffix) + @definition.dig("metadata", "annotations", "kubernetes-deploy.shopify.io/#{suffix}") || + @definition.dig("metadata", "annotations", "krane.shopify.io/#{suffix}") end - def annotation_prefix + def timeout_annotation_key if @definition.dig("metadata", "annotations").key?(TIMEOUT_OVERRIDE_ANNOTATION) TIMEOUT_OVERRIDE_ANNOTATION else diff --git a/lib/kubernetes-deploy/kubernetes_resource/custom_resource_definition.rb b/lib/kubernetes-deploy/kubernetes_resource/custom_resource_definition.rb index 63ea09573..dc9bbe804 100644 --- a/lib/kubernetes-deploy/kubernetes_resource/custom_resource_definition.rb +++ b/lib/kubernetes-deploy/kubernetes_resource/custom_resource_definition.rb @@ -4,7 +4,6 @@ class CustomResourceDefinition < KubernetesResource TIMEOUT = 2.minutes ROLLOUT_CONDITIONS_ANNOTATION_DEPRECATED = "kubernetes-deploy.shopify.io/instance-rollout-conditions" ROLLOUT_CONDITIONS_ANNOTATION = "krane.shopify.io/instance-rollout-conditions" - TIMEOUT_FOR_INSTANCE_ANNOTATION_DEPRECATED = "kubernetes-deploy.shopify.io/instance-timeout" TIMEOUT_FOR_INSTANCE_ANNOTATION = "krane.shopify.io/instance-timeout" GLOBAL = true @@ -21,7 +20,7 @@ def timeout_message end def timeout_for_instance - timeout = timeout_for_instance_annotation + timeout = krane_annotation_value("instance-timeout") DurationParser.new(timeout).parse!.to_i rescue DurationParser::ParsingError nil @@ -52,36 +51,20 @@ def name end def prunable? - prunable = prunable_annotation + prunable = krane_annotation_value("prunable") prunable == "true" end def predeployed? - predeployed = predeployed_annotation + predeployed = krane_annotation_value("predeployed") predeployed.nil? || predeployed == "true" end - def prunable_annotation - if @definition.dig("metadata", "annotations").key?("kubernetes-deploy.shopify.io/prunable") - @definition.dig("metadata", "annotations", "kubernetes-deploy.shopify.io/prunable") - elsif @definition.dig("metadata", "annotations").key?("krane.shopify.io/prunable") - @definition.dig("metadata", "annotations", "krane.shopify.io/prunable") - end - end - - def predeployed_annotation - if @definition.dig("metadata", "annotations").key?("kubernetes-deploy.shopify.io/predeployed") - @definition.dig("metadata", "annotations", "kubernetes-deploy.shopify.io/predeployed") - elsif @definition.dig("metadata", "annotations").key?("krane.shopify.io/predeployed") - @definition.dig("metadata", "annotations", "krane.shopify.io/predeployed") - end - end - def rollout_conditions return @rollout_conditions if defined?(@rollout_conditions) - @rollout_conditions = if rollout_conditions_annotation - RolloutConditions.from_annotation(rollout_conditions_annotation) + @rollout_conditions = if krane_annotation_value("instance-rollout-conditions") + RolloutConditions.from_annotation(krane_annotation_value("instance-rollout-conditions")) end rescue RolloutConditionsError @rollout_conditions = nil @@ -92,12 +75,12 @@ def validate_definition(*) validate_rollout_conditions rescue RolloutConditionsError => e - @validation_errors << "Annotation #{rollout_conditions_annotation_prefix} on #{name} is invalid: #{e}" + @validation_errors << "Annotation #{rollout_conditions_annotation_key} on #{name} is invalid: #{e}" end def validate_rollout_conditions - if rollout_conditions_annotation && @rollout_conditions_validated.nil? - conditions = RolloutConditions.from_annotation(rollout_conditions_annotation) + if krane_annotation_value("instance-rollout-conditions") && @rollout_conditions_validated.nil? + conditions = RolloutConditions.from_annotation(krane_annotation_value("instance-rollout-conditions")) conditions.validate! end @@ -115,22 +98,12 @@ def names_accepted_status names_accepted_condition["status"] end - def rollout_conditions_annotation_prefix + def rollout_conditions_annotation_key if @definition.dig("metadata", "annotations").key?(ROLLOUT_CONDITIONS_ANNOTATION_DEPRECATED) ROLLOUT_CONDITIONS_ANNOTATION_DEPRECATED elsif @definition.dig("metadata", "annotations").key?(ROLLOUT_CONDITIONS_ANNOTATION) ROLLOUT_CONDITIONS_ANNOTATION end end - - def rollout_conditions_annotation - @definition.dig("metadata", "annotations", ROLLOUT_CONDITIONS_ANNOTATION_DEPRECATED) || - @definition.dig("metadata", "annotations", ROLLOUT_CONDITIONS_ANNOTATION) - end - - def timeout_for_instance_annotation - @definition.dig("metadata", "annotations", TIMEOUT_FOR_INSTANCE_ANNOTATION_DEPRECATED) || - @definition.dig("metadata", "annotations", TIMEOUT_FOR_INSTANCE_ANNOTATION) - end end end diff --git a/lib/kubernetes-deploy/kubernetes_resource/deployment.rb b/lib/kubernetes-deploy/kubernetes_resource/deployment.rb index bcb45199f..12deb7f2c 100644 --- a/lib/kubernetes-deploy/kubernetes_resource/deployment.rb +++ b/lib/kubernetes-deploy/kubernetes_resource/deployment.rb @@ -104,7 +104,7 @@ def validate_definition(*) strategy = @definition.dig('spec', 'strategy', 'type').to_s if required_rollout.downcase == 'maxunavailable' && strategy.present? && strategy.downcase != 'rollingupdate' - @validation_errors << "'#{rollout_annotation_prefix}: #{required_rollout}' is incompatible "\ + @validation_errors << "'#{rollout_annotation_key}: #{required_rollout}' is incompatible "\ "with strategy '#{strategy}'" end @@ -149,14 +149,14 @@ def progress_deadline end def rollout_annotation_err_msg - "'#{rollout_annotation_prefix}: #{required_rollout}' is invalid. "\ + "'#{rollout_annotation_key}: #{required_rollout}' is invalid. "\ "Acceptable values: #{REQUIRED_ROLLOUT_TYPES.join(', ')}" end - def rollout_annotation_prefix + def rollout_annotation_key if @definition.dig("metadata", "annotations").key?(REQUIRED_ROLLOUT_ANNOTATION) REQUIRED_ROLLOUT_ANNOTATION - elsif @definition.dig("metadata", "annotations").key?(REQUIRED_ROLLOUT_ANNOTATION_DEPRECATED) + else REQUIRED_ROLLOUT_ANNOTATION_DEPRECATED end end @@ -210,8 +210,7 @@ def max_unavailable end def required_rollout - @definition.dig('metadata', 'annotations', REQUIRED_ROLLOUT_ANNOTATION_DEPRECATED).presence || - @definition.dig('metadata', 'annotations', REQUIRED_ROLLOUT_ANNOTATION).presence || DEFAULT_REQUIRED_ROLLOUT + krane_annotation_value("required-rollout") || DEFAULT_REQUIRED_ROLLOUT end def percent?(value) diff --git a/test/fixtures/pvc/pod.yml b/test/fixtures/pvc/pod.yml index 44f83d952..74c7dfa14 100644 --- a/test/fixtures/pvc/pod.yml +++ b/test/fixtures/pvc/pod.yml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Pod metadata: annotations: - kubernetes-deploy.shopify.io/timeout-override: 10s + krane.shopify.io/timeout-override: 10s name: pvc labels: type: unmanaged-pod diff --git a/test/fixtures/pvc/pvc.yml b/test/fixtures/pvc/pvc.yml index 38f649b71..cb844ef55 100644 --- a/test/fixtures/pvc/pvc.yml +++ b/test/fixtures/pvc/pvc.yml @@ -2,7 +2,7 @@ apiVersion: v1 kind: PersistentVolumeClaim metadata: annotations: - kubernetes-deploy.shopify.io/timeout-override: 10s + krane.shopify.io/timeout-override: 10s name: with-storage-class spec: accessModes: diff --git a/test/integration-serial/serial_deploy_test.rb b/test/integration-serial/serial_deploy_test.rb index 3de3f42a9..9983b1f3f 100644 --- a/test/integration-serial/serial_deploy_test.rb +++ b/test/integration-serial/serial_deploy_test.rb @@ -144,6 +144,8 @@ def test_crd_pruning_deprecated "Phase 3: Deploying all resources", "CustomResourceDefinition/mail.stable.example.io (timeout: 120s)", %r{CustomResourceDefinition/mail.stable.example.io\s+Names accepted}, + "Template warning:", + "kubernetes-deploy.shopify.io as a prefix for annotations is deprecated:", ]) assert_deploy_success(deploy_fixtures("crd", subset: %w(mail_cr.yml widgets_cr.yml configmap-data.yml))) # Deploy any other non-priority (predeployable) resource to trigger pruning diff --git a/test/unit/kubernetes-deploy/kubernetes_resource/deployment_test.rb b/test/unit/kubernetes-deploy/kubernetes_resource/deployment_test.rb index 26cc5464d..40eeb1f07 100644 --- a/test/unit/kubernetes-deploy/kubernetes_resource/deployment_test.rb +++ b/test/unit/kubernetes-deploy/kubernetes_resource/deployment_test.rb @@ -160,7 +160,7 @@ def test_deploy_succeeded_with_max_unavailable_as_percent def test_deploy_succeeded_raises_with_invalid_rollout_annotation_deprecated deploy = build_synced_deployment( - template: build_deployment_template_deprecated(rollout: 'bad'), + template: build_deployment_template(rollout: 'bad', use_deprecated: true), replica_sets: [build_rs_template] ) msg = "'#{KubernetesDeploy::Deployment::REQUIRED_ROLLOUT_ANNOTATION_DEPRECATED}: bad' is "\ @@ -183,7 +183,10 @@ def test_deploy_succeeded_raises_with_invalid_rollout_annotation end def test_validation_fails_with_invalid_rollout_annotation_deprecated - deploy = build_synced_deployment(template: build_deployment_template_deprecated(rollout: 'bad'), replica_sets: []) + deploy = build_synced_deployment( + template: build_deployment_template(rollout: 'bad', use_deprecated: true), + replica_sets: [] + ) kubectl.expects(:run).with('create', '-f', anything, '--dry-run', '--output=name', anything).returns( ["", "super failed", SystemExit.new(1)] ) @@ -220,7 +223,10 @@ def test_validation_with_percent_rollout_annotation end def test_validation_with_number_rollout_annotation_deprecated - deploy = build_synced_deployment(template: build_deployment_template_deprecated(rollout: '10'), replica_sets: []) + deploy = build_synced_deployment( + template: build_deployment_template(rollout: '10', use_deprecated: true), + replica_sets: [] + ) kubectl.expects(:run).with('create', '-f', anything, '--dry-run', '--output=name', anything).returns( ["", "super failed", SystemExit.new(1)] ) @@ -249,7 +255,7 @@ def test_validation_with_number_rollout_annotation def test_validation_fails_with_invalid_mix_of_annotation_deprecated deploy = build_synced_deployment( - template: build_deployment_template_deprecated(rollout: 'maxUnavailable', strategy: 'Recreate'), + template: build_deployment_template(rollout: 'maxUnavailable', strategy: 'Recreate', use_deprecated: true), replica_sets: [build_rs_template] ) kubectl.expects(:run).with('create', '-f', anything, '--dry-run', '--output=name', anything).returns( @@ -422,40 +428,18 @@ def test_deploy_timed_out_based_on_progress_deadline_ignores_statuses_for_older_ private - def build_deployment_template_deprecated(status: { 'replicas' => 3 }, rollout: nil, - strategy: 'rollingUpdate', max_unavailable: nil) - - base_deployment_manifest = fixtures.find { |fixture| fixture["kind"] == "Deployment" } - result = base_deployment_manifest.deep_merge("status" => status) - if rollout - result["metadata"]["annotations"][KubernetesDeploy::Deployment::REQUIRED_ROLLOUT_ANNOTATION_DEPRECATED] = rollout - end - - if (spec_override = status["replicas"].presence) # ignores possibility of surge; need a spec_replicas arg for that - result["spec"]["replicas"] = spec_override - end - - if strategy == "Recreate" - result["spec"]["strategy"] = { "type" => strategy } - end + def build_deployment_template(status: { 'replicas' => 3 }, rollout: nil, + strategy: 'rollingUpdate', max_unavailable: nil, use_deprecated: false) - if strategy.nil? - result["spec"]["strategy"] = nil + required_rollout_annotation = if use_deprecated + KubernetesDeploy::Deployment::REQUIRED_ROLLOUT_ANNOTATION_DEPRECATED + else + KubernetesDeploy::Deployment::REQUIRED_ROLLOUT_ANNOTATION end - if max_unavailable - result["spec"]["strategy"]["rollingUpdate"] = { "maxUnavailable" => max_unavailable } - end - - result - end - - def build_deployment_template(status: { 'replicas' => 3 }, rollout: nil, - strategy: 'rollingUpdate', max_unavailable: nil) - base_deployment_manifest = fixtures.find { |fixture| fixture["kind"] == "Deployment" } result = base_deployment_manifest.deep_merge("status" => status) - result["metadata"]["annotations"][KubernetesDeploy::Deployment::REQUIRED_ROLLOUT_ANNOTATION] = rollout if rollout + result["metadata"]["annotations"][required_rollout_annotation] = rollout if rollout if (spec_override = status["replicas"].presence) # ignores possibility of surge; need a spec_replicas arg for that result["spec"]["replicas"] = spec_override diff --git a/test/unit/kubernetes-deploy/kubernetes_resource_test.rb b/test/unit/kubernetes-deploy/kubernetes_resource_test.rb index 1bd600f23..44a35c8de 100644 --- a/test/unit/kubernetes-deploy/kubernetes_resource_test.rb +++ b/test/unit/kubernetes-deploy/kubernetes_resource_test.rb @@ -98,11 +98,11 @@ def test_fetch_events_returns_empty_hash_when_kubectl_results_empty end def test_deprecated_annotation_generates_warning - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("60S")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("60S", use_deprecated: true)) customized_resource.validate_definition(kubectl) assert(customized_resource.has_warnings?, "Deprecated annotation did not generate a warning") - assert_equal("kubernetes-deploy.shopify.io/timeout-override is deprecated: "\ - "Use 'krane.shopify.io' annotations instead", + assert_equal("kubernetes-deploy.shopify.io as a prefix for annotations is deprecated: "\ + "Use the 'krane.shopify.io' annotation prefix instead", customized_resource.validation_warning_msg) end @@ -116,13 +116,13 @@ def test_can_override_hardcoded_timeout_via_an_annotation_deprecated basic_resource = DummyResource.new assert_equal(300, basic_resource.timeout) - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("60S")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("60S", use_deprecated: true)) assert_equal(60, customized_resource.timeout) - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("60M")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("60M", use_deprecated: true)) assert_equal(3600, customized_resource.timeout) - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("1H")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("1H", use_deprecated: true)) assert_equal(3600, customized_resource.timeout) end @@ -141,7 +141,7 @@ def test_can_override_hardcoded_timeout_via_an_annotation end def test_blank_timeout_annotation_is_invalid_deprecated - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("", use_deprecated: true)) customized_resource.validate_definition(kubectl) assert(customized_resource.validation_failed?, "Blank annotation was valid") assert_equal("#{timeout_override_err_prefix_deprecated}: Invalid ISO 8601 duration: \"\" is empty duration", @@ -164,19 +164,19 @@ def test_lack_of_timeout_annotation_does_not_fail_validation end def test_timeout_override_lower_bound_validation_deprecation - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("-1S")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("-1S", use_deprecated: true)) customized_resource.validate_definition(kubectl) assert(customized_resource.validation_failed?, "Annotation with '-1' was valid") assert_equal("#{timeout_override_err_prefix_deprecated}: Value must be greater than 0", customized_resource.validation_error_msg) - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("0S")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("0S", use_deprecated: true)) customized_resource.validate_definition(kubectl) assert(customized_resource.validation_failed?, "Annotation with '0' was valid") assert_equal("#{timeout_override_err_prefix_deprecated}: Value must be greater than 0", customized_resource.validation_error_msg) - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("1S")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("1S", use_deprecated: true)) customized_resource.validate_definition(kubectl) refute(customized_resource.validation_failed?, "Annotation with '1' was invalid") end @@ -200,13 +200,13 @@ def test_timeout_override_lower_bound_validation end def test_timeout_override_upper_bound_validation_deprecated - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("24H1S")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("24H1S", use_deprecated: true)) customized_resource.validate_definition(kubectl) assert(customized_resource.validation_failed?, "Annotation with '24H1S' was valid") expected_message = "#{timeout_override_err_prefix_deprecated}: Value must be less than 24h" assert_equal(expected_message, customized_resource.validation_error_msg) - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("24H")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("24H", use_deprecated: true)) customized_resource.validate_definition(kubectl) refute(customized_resource.validation_failed?, "Annotation with '24H' was invalid") end @@ -235,7 +235,7 @@ def test_validate_definition_doesnt_log_raw_output_for_sensitive_resources end def test_annotation_and_kubectl_error_messages_are_combined_deprecated - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("bad")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("bad", use_deprecated: true)) kubectl.expects(:run).returns([ "{}", "Error from kubectl: Something else in this template was not valid", @@ -269,7 +269,7 @@ def test_annotation_and_kubectl_error_messages_are_combined end def test_calling_timeout_before_validation_with_invalid_annotation_does_not_raise_deprecated - customized_resource = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("bad")) + customized_resource = DummyResource.new(definition_extras: build_timeout_metadata("bad", use_deprecated: true)) assert_equal(300, customized_resource.timeout) assert_nil(customized_resource.timeout_override) end @@ -296,7 +296,7 @@ def test_deploy_timed_out_respects_hardcoded_timeouts def test_deploy_timed_out_respects_annotation_based_timeouts_deprecated Timecop.freeze do - custom_dummy = DummyResource.new(definition_extras: build_timeout_metadata_deprecated("3s")) + custom_dummy = DummyResource.new(definition_extras: build_timeout_metadata("3s", use_deprecated: true)) refute custom_dummy.deploy_timed_out? assert_equal 3, custom_dummy.timeout @@ -468,23 +468,18 @@ def timeout_override_err_prefix "krane.shopify.io/timeout-override annotation is invalid" end - def build_timeout_metadata_deprecated(value) - { - "metadata" => { - "name" => "customized", - "annotations" => { - KubernetesDeploy::KubernetesResource::TIMEOUT_OVERRIDE_ANNOTATION_DEPRECATED => value, - }, - }, - } - end + def build_timeout_metadata(value, use_deprecated: false) + timeout_override_annotation = if use_deprecated + KubernetesDeploy::KubernetesResource::TIMEOUT_OVERRIDE_ANNOTATION_DEPRECATED + else + KubernetesDeploy::KubernetesResource::TIMEOUT_OVERRIDE_ANNOTATION + end - def build_timeout_metadata(value) { "metadata" => { "name" => "customized", "annotations" => { - KubernetesDeploy::KubernetesResource::TIMEOUT_OVERRIDE_ANNOTATION => value, + timeout_override_annotation => value, }, }, }