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

[Feature] add support for context variables for better use of templating #11

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

Conversation

djivey
Copy link
Contributor

@djivey djivey commented Jan 13, 2025

What does this PR do?

This PR introduces several enhancements to the Kubernetes extension:

  1. Template Context Support

    • Adds context variable support for Kubernetes resource states
    • Enables dynamic template configuration for deployments, pods, services, configmaps, and secrets
  2. Secret Management Improvements

    • Added base64 encoding handling
    • Preserves secret types during updates
  3. Service Specification Enhancement

    • Enhanced service port specifications
  4. Connection Handling

    • Simplified kubeconfig management
    • Removed individual override options
  5. Updated Tests

    • Added unit tests for use of context variables
    • Added functional tests for the state and execution modules kubernetes and kubernetesmod
    • Added integration tests for the state and execution modules kubernetes and kubernetesmod
  6. Renamed the kubernetesmod.py state module to kubernetes.py to resolve conflicts with salt core kubernetes module

What issues does this PR fix or reference?

Fixes: #10 - Add support for context variables in Kubernetes templates.
Potentially fixes - saltstack/salt#59758

Previous Behavior

  • Templates lacked context support
  • Did not handle base64 encoded strings required for secrets
  • Limited service port configuration options

Merge requirements satisfied?

  • Docs - Updated all affected function docstrings
  • Changelog - Added entries in changelog/2.feature.md
  • Tests - Added for all new features

Commits signed with GPG?

Yes

Copy link

codecov bot commented Jan 14, 2025

Codecov Report

Attention: Patch coverage is 89.79821% with 182 lines in your changes missing coverage. Please review.

Project coverage is 79.68%. Comparing base (9df015d) to head (1c09885).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/saltext/kubernetes/modules/kubernetesmod.py 68.65% 54 Missing and 30 partials ⚠️
tests/functional/modules/test_kubernetesmod.py 89.14% 30 Missing and 31 partials ⚠️
tests/conftest.py 79.36% 12 Missing and 1 partial ⚠️
tests/integration/states/test_kubernetes.py 95.65% 8 Missing and 4 partials ⚠️
tests/integration/modules/test_kubernetesmod.py 92.99% 11 Missing ⚠️
tests/functional/states/test_kubernetes.py 99.69% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##             main      #11       +/-   ##
===========================================
+ Coverage   55.63%   79.68%   +24.05%     
===========================================
  Files          13       17        +4     
  Lines        2439     4037     +1598     
  Branches      290      380       +90     
===========================================
+ Hits         1357     3217     +1860     
+ Misses       1066      709      -357     
- Partials       16      111       +95     
Flag Coverage Δ
Linux 79.68% <89.79%> (+24.13%) ⬆️
macOS 42.46% <20.29%> (+7.67%) ⬆️
project 63.06% <70.52%> (+26.01%) ⬆️
py310 79.63% <89.63%> (+23.95%) ⬆️
py39 79.68% <89.79%> (+24.13%) ⬆️
salt_3006_9 79.68% <89.79%> (+24.05%) ⬆️
salt_3007_1 79.63% <89.63%> (+23.95%) ⬆️
tests 91.26% <93.46%> (+3.73%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@djivey djivey marked this pull request as ready for review January 14, 2025 14:39
@djivey djivey marked this pull request as draft January 15, 2025 14:10
@djivey
Copy link
Contributor Author

djivey commented Jan 15, 2025

I have some more changes for this pr, but having issues with new unit tests.

@djivey djivey marked this pull request as ready for review January 16, 2025 15:06
@djivey djivey marked this pull request as draft January 18, 2025 18:48
@djivey
Copy link
Contributor Author

djivey commented Jan 18, 2025

I marked this back to draft, I am going to try and write functional/integration tests for it.

@djivey
Copy link
Contributor Author

djivey commented Jan 27, 2025

@lkubb I think I am finished writing tests for this now. Although, I may need to reassess some of the asserts I used early on. I may have over done it with spec validation and looking back on it; I probably should have done some of the testing I did in functional tests in unit tests instead. Given how much error testing I did in the execution module functional tests -> I lightened up on the rest of the tests and focused on correct usage. Thank you for your help to get this done. The versions of kubernetes I chose was based on these release notes https://github.com/kubernetes-sigs/kind/releases/tag/v0.25.0.

@benfiedler If you have time, can you test this PR in your environment? You may need to clear cache and remove the old version of the state module file kubernetesmod.py as I renamed the module due to a conflict with the existing kubernetes.py in salt core code. It works in my environment.

Side Note: I do not like the way the state module is not actually idempotent. If it has an existing resource the module replaces it instead of saying it exists and exit. I think we should only replace if we pass in an arg/kwarg replace=true, but I think that is too much work for this PR and should be a separate issue.

@djivey djivey marked this pull request as ready for review January 27, 2025 23:07
…dle everything, also added metadata and type args needed
@djivey
Copy link
Contributor Author

djivey commented Jan 29, 2025

Thanks to some testing by @benfiedler I realized that I over complicated secrets management. Should be good now.

…neType error, and remove default to opaque type
@djivey
Copy link
Contributor Author

djivey commented Jan 30, 2025

This last change was due to a use case @benfiedler gave me where when creating a secret with data as an empty dictionary, kubernetes will generate the token automatically. So, I added a test for this use case, and updated secrets to handle the NoneType error and remove the default to type opaque.

@benfiedler
Copy link

Thanks, as @djivey mentioned my tests were successful after some minor tweaks.

There was a minor issue during testing with one of my source+context secrets that renders data that is already base64 encoded - it gets double base64 encoded, but I was able to workaround it by updating my source file to just instead have it in plain text.

I can investigate that one later when I have more time to see if I can find out how/why that's happening.

…4 values and update is_base64 to remove whitespace and use to confirm base64
@djivey
Copy link
Contributor Author

djivey commented Feb 3, 2025

Thanks, as @djivey mentioned my tests were successful after some minor tweaks.

There was a minor issue during testing with one of my source+context secrets that renders data that is already base64 encoded - it gets double base64 encoded, but I was able to workaround it by updating my source file to just instead have it in plain text.

I can investigate that one later when I have more time to see if I can find out how/why that's happening.

It is related to a use case where I was not handling newlines/whitespace in the __is_base64 function and returns false causing the double encoding.

Example data:

type: "kubernetes.io/tls"
data:
  tls.crt: |
      "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUM5akNDQWQ2Z0F3SUJBZ0lSQVA4"
      "Y3NuYmovVS9nWHJ4VDR5dXk5OUF3RFFZSktvWklodmNOQVFFTEJRQXcKRlRFVE1CRUdB"
      "MVVFQXhNS2EzVmlaWEp1WlhSbGN6QWVGdzB5TkRBeE1UY3hOekEwTWpkYUZ3MHpOREF4"
      "TVRReApOekEwTWpkYU1CVXhFekFSQmdOVkJBTVRDbXQxWW1WeWJtVjBaWE13Z2dFaU1B"
      "MEdDU3FHU0liM0RRRUJBUVVBQ"
  tls.key: |
      "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcw"
      "QkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQzFyZkdjdGhFaXk3K0YKLzdSOEd6TmFh"
      "d29PdEVHVHZvWWFPMlF1b2JEcUd0NitTZFZ1Y2NTS2dDYWh3V09XN0dTTzhNRjJzaEtE"
      "WHlsegp1VzZySjN2WlJOaVgyMy9TV1J3d0xXYzBHZUNVT3VXQVlVR2N1THQ5OVplUzRQ"
      "eWQ5UmRnNTRZRlhMZ1FKV0"

I updated the function to support this use case and added a test case in the module functional tests to validate functionality.

@lkubb lkubb self-assigned this Feb 5, 2025
Copy link
Member

@lkubb lkubb left a comment

Choose a reason for hiding this comment

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

Thanks a lot (once again =D) for going beyond and implementing a proper functional/integration test suite + sorry for taking so long to review it. This PR gives the extension a solid foundation for future changes.

Edit: Not sure if you'll notice this edit, but I forgot mentioning: Something that would be nice is some functional tests for the state module that verify that test=True works as expected (correctly reports changes/no changes) and especially does not apply these changes.

@@ -290,7 +290,7 @@ def _lint(session, rcfile, flags, paths, tee_output=True):
stdout.seek(0)
contents = stdout.read()
if contents:
contents = contents.decode("utf-8")
Copy link
Member

Choose a reason for hiding this comment

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

question: Is this change intentional?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried a lot of things through this process, I could have dropped that on accident, will test it and make sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

reverted

@@ -71,11 +73,16 @@ lint = [
]
tests = [
"pytest>=7.2.0",
"pytest-salt-factories>=1.0.0",
"pytest-custom-exit-code>=0.3",
"pytest-salt-factories>=1.0.0rc19",
Copy link
Member

Choose a reason for hiding this comment

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

issue: I don't think the version bound should be lowered.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay

Comment on lines +81 to +83
"PyYAML>=5.3.1",
"mock>=4.0.3",
"pytest-custom-exit-code>=0.3",
Copy link
Member

Choose a reason for hiding this comment

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

question: Why did you add these test dependencies?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Dropped these and reinitiated a venv to validate tests still worked.

Comment on lines +206 to +207
context
Variables to be passed into the template.
Copy link
Member

Choose a reason for hiding this comment

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

note: We need to ensure this change is documented prominently since before this patch, this parameter was used for something unrelated.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Where do I document this better? Module docstring?

Copy link
Member

@lkubb lkubb Mar 4, 2025

Choose a reason for hiding this comment

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

This was mostly intended to be a reminder, it's probably fine if it's mentioned in the changelog like I proposed, especially since this module has likely been broken for quite some time.

Copy link
Member

@lkubb lkubb Mar 4, 2025

Choose a reason for hiding this comment

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

issue: This news fragment needs to render to a bullet point in the changelog list, which won't work because it contains newlines, headers and lists itself.

note: You don't need to add testing infrastructure changes here, it's just for user-facing changes.

In essence, please cut this down to a single line like: Added support for specifying template context variables (or something that you feel describes the initial motivation for this PR). Additionally, we need to document breaking changes, which should get their own news fragment. They don't need their own issue. Example:

echo 'Removed the ability to override minion configuration in function parameters (`context`, `kubeconfig`, `kubeconfig_data`)' > changelog/+config.removed.md
echo 'Reused the removed `context` parameter for Jinja2 context variables! Take care when upgrading from earlier versions.' > changelog/+context.breaking.md

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay

source=None,
template=None,
context=None,
saltenv="base",
Copy link
Member

Choose a reason for hiding this comment

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

note: I think this is a breaking change as well, right? We're going from saltenv=__env__ to saltenv="base".

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I was having a lot of trouble in the integration tests here, I will test this out again.

Comment on lines +600 to +608
try:
ret["changes"] = {
# Omit values from the return. They are unencrypted
# and can contain sensitive data.
"data": list(res["data"])
}
# TypeError: 'NoneType' object is not iterable
except TypeError:
ret["changes"] = {"data": []}
Copy link
Member

Choose a reason for hiding this comment

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

suggestion: If you only need to protect against None here, you can just do this instead:

Suggested change
try:
ret["changes"] = {
# Omit values from the return. They are unencrypted
# and can contain sensitive data.
"data": list(res["data"])
}
# TypeError: 'NoneType' object is not iterable
except TypeError:
ret["changes"] = {"data": []}
ret["changes"] = {
# Omit values from the return. They are unencrypted
# and can contain sensitive data.
"data": list(res["data"] or [])
}

cluster.create()

# Initial wait for cluster to start
time.sleep(10)
Copy link
Member

Choose a reason for hiding this comment

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

question: Is this idle time necessary? Can we just remove it and adjust the retries below?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed, the retries that exist are sufficient

log.error("stdout: %s", exc.stdout)
log.error("stderr: %s", exc.stderr)
raise
time.sleep(10)
Copy link
Member

Choose a reason for hiding this comment

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

question: Don't the called commands above wait?

If not:

note: I'd much prefer this decreased to 1s and the retries adjusted accordingly because we don't want to waste time in CI.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

removed

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

Successfully merging this pull request may close these issues.

[FEATURE REQUEST] Add functionality for using context values for jinja templating in kubernetesmod.
3 participants