Skip to content
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

Use merge policy instead of fallbacks for KubeResourceConfig #309

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

azorej
Copy link

@azorej azorej commented Mar 17, 2024

What

Fix for airbytehq/airbyte#33068

But the problem is more complex.
Logic in io.airbyte.commons.workers.config.WorkerConfigsProvider is opaque.
The main strategy of resolving KubeResourceConfig is to fallback to the default for the whole config: if we cannot find the exact key, we will choose the closest default section.
However, there are some exceptions: annotations and ResourceRequirements (cpu/memory limits/requests). If any of these are empty, we will attempt to update them using the default config.

In addition, the current fallback logic does not work well for Helm OSS installations.
We parameterize config values via environment variables.
And there is no way to remove a section from the application.yml without using a custom image.
So one must setup all variables JOB_KUBE_LABELS, CHECK_JOB_KUBE_LABELS, DISCOVER_JOB_KUBE_LABELS, REPLICATION_JOB_KUBE_LABELS, SPEC_JOB_KUBE_LABELS in case they want to use common k8s labels (for example, azure.workload.identity/use).

The last issue I have is that I am not sure how to set a null value for a field in a KubeResourceConfig using environment variables.

How

I suggest to introduce two breaking changes:

  1. Use a merge strategy to resolve KubeResourceConfig. It's more intuitive and powerful.
  2. Use the literal <EMPTY> to differentiate between empty and null fields.

The merge strategy will use the same order as previously: variant, type, subtype.
But it will try to merge configs based on COALESCE(value, default_value) for every field in KubeResourceConfig for every key part.
With this we don't need custom logic for annotations and ResourceRequirements.

<EMPTY> literal is needed to override defaults with empty values.

Recommended reading order

  1. airbyte-commons-with-dependencies/src/test/resources/application-config-test.yaml
  2. airbyte-commons-with-dependencies/src/main/java/io/airbyte/commons/workers/config/WorkerConfigsProvider.java
  3. airbyte-commons-with-dependencies/src/main/java/io/airbyte/commons/workers/config/KubeResourceConfig.java
  4. all other files

Can this PR be safely reverted / rolled back?

If you know that your PR is backwards-compatible and can be simply reverted or rolled back, check the YES box.

Otherwise if your PR has a breaking change, like a database migration for example, check the NO box.

If unsure, leave it blank.

  • YES πŸ’š
  • NO ❌

🚨 User Impact 🚨

Are there any breaking changes? What is the end result perceived by the user? If yes, please merge this PR with the 🚨🚨 emoji so changelog authors can further highlight this if needed.

@CLAassistant
Copy link

CLAassistant commented Mar 17, 2024

CLA assistant check
All committers have signed the CLA.

Copy link

sonarcloud bot commented Mar 17, 2024

Quality Gate Passed Quality Gate passed

Issues
0 New issues
0 Accepted issues

Measures
0 Security Hotspots
No data about Coverage
0.0% Duplication on New Code

See analysis details on SonarCloud

@azorej azorej marked this pull request as ready for review March 17, 2024 02:09
@@ -38,6 +39,7 @@ airbyte:
cpu-request: 42
micronauttest-source:
cpu-limit: 5
cpu-request: <EMPTY> # Disable inheritance, force empty value
Copy link
Author

Choose a reason for hiding this comment

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

Be careful: that's a breaking change

@@ -104,6 +104,7 @@ airbyte:
kube-job-configs:
default:
annotations: ${JOB_KUBE_ANNOTATIONS:}
labels: ${JOB_KUBE_LABELS:}
Copy link
Author

Choose a reason for hiding this comment

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

Comment on lines +10 to +11
cpu-request: default cpu request
memory-request: default memory request
Copy link
Author

Choose a reason for hiding this comment

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

Previous test cases weren't consistent

check:
annotations: ${CHECK_JOB_KUBE_ANNOTATIONS:check annotations}
annotations: ${CHECK_JOB_KUBE_ANNOTATIONS:check_annotation_key=check_annotation_value}
Copy link
Author

Choose a reason for hiding this comment

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

We didn't check annotation overrides earlier

assertNull(specKubeResourceConfig.getCpuLimit());
assertNull(specKubeResourceConfig.getCpuRequest());
assertEquals("", specKubeResourceConfig.getCpuLimit());
assertEquals("", specKubeResourceConfig.getCpuRequest());
Copy link
Author

Choose a reason for hiding this comment

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

We consider nulls as empty strings for KubeResourceConfig now

Comment on lines -372 to 378
private ResourceRequirements getResourceRequirementsFrom(final KubeResourceConfig kubeResourceConfig, final KubeResourceConfig defaultConfig) {
private ResourceRequirements getResourceRequirementsFrom(final KubeResourceConfig kubeResourceConfig) {
return new ResourceRequirements()
.withCpuLimit(useDefaultIfEmpty(kubeResourceConfig.getCpuLimit(), defaultConfig.getCpuLimit()))
.withCpuRequest(useDefaultIfEmpty(kubeResourceConfig.getCpuRequest(), defaultConfig.getCpuRequest()))
.withMemoryLimit(useDefaultIfEmpty(kubeResourceConfig.getMemoryLimit(), defaultConfig.getMemoryLimit()))
.withMemoryRequest(useDefaultIfEmpty(kubeResourceConfig.getMemoryRequest(), defaultConfig.getMemoryRequest()));
}

private static String useDefaultIfEmpty(final String value, final String defaultValue) {
return (value == null || value.isBlank()) ? defaultValue : value;
.withCpuLimit(kubeResourceConfig.getCpuLimit())
.withCpuRequest(kubeResourceConfig.getCpuRequest())
.withMemoryLimit(kubeResourceConfig.getMemoryLimit())
.withMemoryRequest(kubeResourceConfig.getMemoryRequest());
}
Copy link
Author

Choose a reason for hiding this comment

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

Remove custom fallbacks since we don't need them anymore

Comment on lines -234 to -242
// if annotations are not defined for this specific resource, then fallback to the default
// resource's annotations
final Map<String, String> annotations;
if (Strings.isNullOrEmpty(kubeResourceConfig.getAnnotations())) {
annotations = splitKVPairsFromEnvString(workerConfigsDefaults.defaultKubeResourceConfig.getAnnotations());
} else {
annotations = splitKVPairsFromEnvString(kubeResourceConfig.getAnnotations());
}

Copy link
Author

Choose a reason for hiding this comment

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

Remove custom fallbacks since we don't need them anymore

@azorej azorej force-pushed the feature/ISSUE-33068_worker_config_default_fallbacks branch from b092c44 to 147f247 Compare April 23, 2024 17:05
@mhemken-vts
Copy link

Can ALL the resource settings be exposed please?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
3 participants