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

OpenAPI field should support merging #4613

Open
gruberrichard opened this issue Apr 29, 2022 · 18 comments
Open

OpenAPI field should support merging #4613

gruberrichard opened this issue Apr 29, 2022 · 18 comments
Labels
kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature. lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one.

Comments

@gruberrichard
Copy link

Describe the bug

We have four directories:

deployment-base - A simple Deployment resource

resources:
- deployment.yaml

deployment-patch - Patch for deployment-base's Deployment resource

resources:
- ../deployment_base

patches:
- deploy_patch.yaml

rollout-base - A Rollout resource with its openapi definition

resources:
- rollout.yaml

openapi:
  path: rollout_cr_schema.json

rollout-patch - Patch for rollout-base's Rollout resource

resources:
- ../rollout_base

patches:
- rollout_patch.yaml

If I run kustomize build deployment-patch it works as expected and it does patch the Deployment resource

If I run kustomize build rollout-patch it works as expected and it does patch the Rollout resource

If I run kustomize build with the following kustomization.yaml then it works as expected (and both resources are patched properly):

resources:
- deployment_patch
- rollout_patch

But when I change the sequence to the following

resources:
- rollout_patch
- deployment_patch

then Rollout resource is still patched properly but at Deployment resource the container definition does not contain properties that are defined only in base.

I have prepared a repo with the details and examples:
https://github.com/gruberrichard/kustomize-bug-with-openapi

Expected output

I would expect that the generated manifests are the same (and patching of Deployment resource does not break) if I change the sequence of resource directories

Kustomize version

{Version:kustomize/v4.4.1 GitCommit:b2d65ddc98e09187a8e38adc27c30bab078c1dbf BuildDate:2021-11-11T23:36:27Z GoOs:darwin GoArch:amd64}

Platform

macOS

@gruberrichard gruberrichard added the kind/bug Categorizes issue or PR as related to a bug. label Apr 29, 2022
@k8s-ci-robot k8s-ci-robot added the needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. label Apr 29, 2022
@dan-j
Copy link

dan-j commented Jun 29, 2022

I've just ran into this issue with a Deployment's containers object not merging properly with my openapi definition just containing a Knative service schema. Is it not intended behaviour to merge the definitions provided by openapi: with the builtin definitions? Or do I need to commit the whole output of kustomize openapi fetch to my repository and then manually add the CRD?

@perenesenko
Copy link

I'm facing issues when trying to patch different resources at a time: rollout, services, etc.

Once I specified the openapi.path field to the rollout schema the other components (services) are not merging as expected anymore.
Feeling like there is some built-in schema exists if no openapi.path field is provided. But once you provide your custom one then the build-in schema is not respected anymore.

Is there a way to add/append your custom schema to the existing built-in so all the resources will be patched as expected?

@michaelmohamed
Copy link

I am having the same issue where when openapi path is added, my deployments are missing specified resource limits that are added with a patch.

If I remove the openapi path then my deployment limit is patched properly.

@zachaller
Copy link

Argo project will have a workaround for this soon with a blog post detailing how we came about it. But you can peak at this as well https://github.com/argoproj/argo-schema-generator

@michaelmohamed
Copy link

Thanks @zachaller, I used the https://raw.githubusercontent.com/argoproj/argo-schema-generator/main/schema/argo_all_k8s_kustomize_schema.json contents as my openapi.path and that worked well. My resource limits and requests all rendered correctly.

@dan-j, I also verified that your solution worked. I used the output of kustomize openapi fetch as my openapi.path and everything rendered correctly; however, I think that this assumes that argo has been installed in your cluster previously.

I opted for @zachaller since it seemed clean and also resulted in a smaller schema size.

Thank @zachaller

@KnVerey
Copy link
Contributor

KnVerey commented Aug 23, 2022

Those who commented that the openapi field requires the full schema, not just additions, are correct. So it isn't a bug, but there are a few related problems:

  • The docs for the openapi field show it being used to add a schema containing a single definition. While the example works (because its resources only have the type in question), it is not representative of a real use case.
  • The openapi field needs to be reconciled with the crds field (which is additive) in general: Reconcile crds and openapi fields #3944
  • The desired behaviour in this issue is essentially a feature request that @natasha41575 and I agreed to in general terms in the above issue: there should be a way to merge the schemas provided in openapi with the built-ins ( perhaps a behavior: merge|replace field, like ConfigMapGenerator?).

/triage accepted
/kind feature
/kind documentation
/retitle OpenAPI field should support merging

@k8s-ci-robot k8s-ci-robot changed the title Issue with Deployment resource patching when Rollout resources openapi definition is included OpenAPI field should support merging Aug 23, 2022
@k8s-ci-robot k8s-ci-robot added triage/accepted Indicates an issue or PR is ready to be actively worked on. kind/feature Categorizes issue or PR as related to a new feature. kind/documentation Categorizes issue or PR as related to documentation. and removed needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. labels Aug 23, 2022
@KnVerey KnVerey removed the kind/bug Categorizes issue or PR as related to a bug. label Aug 23, 2022
@natasha41575
Copy link
Contributor

@KnVerey FYI, I have an umbrella issue with some of the things I want to do with openapi: #4569

It includes a note that the supplied openapi should be an addition to what's builtin, rather than replacing it all.

@zachaller
Copy link

I have a blog post that should be posted this Thursday (8/25/2022) here that will also go into some of these issues as well. But really looking forward to either changes from kustomize or k8s to help with this issue as well.

@zachaller
Copy link

For those interested https://blog.argoproj.io/argo-crds-and-kustomize-the-problem-of-patching-lists-5cfc43da288c

@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs.

This bot triages issues and PRs according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Mark this issue or PR as fresh with /remove-lifecycle stale
  • Mark this issue or PR as rotten with /lifecycle rotten
  • Close this issue or PR with /close
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle stale

@k8s-ci-robot k8s-ci-robot added the lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. label Nov 23, 2022
@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.

This bot triages issues and PRs according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Mark this issue or PR as fresh with /remove-lifecycle rotten
  • Close this issue or PR with /close
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/lifecycle rotten

@k8s-ci-robot k8s-ci-robot added lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed. and removed lifecycle/stale Denotes an issue or PR has remained open with no activity and has become stale. labels Dec 23, 2022
@k8s-triage-robot
Copy link

The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.

This bot triages issues according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Reopen this issue with /reopen
  • Mark this issue as fresh with /remove-lifecycle rotten
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/close not-planned

@k8s-ci-robot
Copy link
Contributor

@k8s-triage-robot: Closing this issue, marking it as "Not Planned".

In response to this:

The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs.

This bot triages issues according to the following rules:

  • After 90d of inactivity, lifecycle/stale is applied
  • After 30d of inactivity since lifecycle/stale was applied, lifecycle/rotten is applied
  • After 30d of inactivity since lifecycle/rotten was applied, the issue is closed

You can:

  • Reopen this issue with /reopen
  • Mark this issue as fresh with /remove-lifecycle rotten
  • Offer to help out with Issue Triage

Please send feedback to sig-contributor-experience at kubernetes/community.

/close not-planned

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@k8s-ci-robot k8s-ci-robot closed this as not planned Won't fix, can't repro, duplicate, stale Jan 22, 2023
@KnVerey
Copy link
Contributor

KnVerey commented Jan 24, 2023

/lifecycle frozen

@KnVerey KnVerey reopened this Jan 24, 2023
@k8s-ci-robot k8s-ci-robot added lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. and removed lifecycle/rotten Denotes an issue or PR that has aged beyond stale and will be auto-closed. labels Jan 24, 2023
@larsks
Copy link
Contributor

larsks commented Nov 1, 2023

The custom openapi example in the documentation suggests strongly that the openapi keyword merges in the custom schema rather than completely replacing the compiled-in schema.

We should update the example to point out that it is replacing the default schema and with that example, kustomize will no longer correctly handle lists in native resources like pods, deployments, etc.

larsks added a commit to larsks/nerc-ocp-config that referenced this issue Nov 2, 2023
`spec.containers` field of Pods:

    spec:
      containers:
        - name: container1
          image: example
        - name: container2
          image: example

Kustomize is able to apply a strategic merge patch to specific
elements in this list by matching the patch against a "merge key".
That is, if we want to add an `env` attribute to `container2`, we can
apply a patch like this:

    apiVersion: v1
    kind: Pod
    metadata:
      name: example
    spec:
      containers:
        - name: container2
          env:
            - MYVAR=somevalue

Kustomize "knows" to patch the list item with `name` equal to
`container2` because it has a compiled in schema for native kubernetes
resources that identifies the appropriate merge keys (the `name`
field). We end up with:

    spec:
      containers:
        - name: container1
          image: example
        - name: container2
          image: example
          env:
            - MYVAR=somevalue

This won't work by default for custom resources. For example, if we
have a resource like this:

    apiVersion: multicluster.openshift.io/v1
    kind: MultiClusterEngine
    metadata:
      name: multiclusterengine
    spec:
      overrides:
        components:
        - enabled: true
          name: local-cluster
        - enabled: true
          name: assisted-service
        - enabled: false
          name: hypershift-preview

And we try to modify it with a patch like this:

    apiVersion: multicluster.openshift.io/v1
    kind: MultiClusterEngine
    metadata:
      name: multiclusterengine
    spec:
      overrides:
        components:
        - enabled: true
          name: hypershift-preview

We will see that rather than making the expected change (setting
`enabled` to `true` for the list item with `name:
hypershift-preview`), this will simply *replace* the entire content of
the `components` key.

It is possible to provide Kustomize with a custom openapi schema that
informs of it of the appropriate merge keys for this sort of custom
resource. There is documentation and an example at [1], but
unfortunately this example is misleading. After reading that document
you may believe that you can provide a schema specific to the custom
resources you want to patch, but that is not the case: a custom schema
*completely replaces* the compiled-in schema, so for example with the
configuration shown in that example, Kustomize would no longer be able
to correctly patch containers in Pods and Deployments. This problem is
more fully discussed in [2], and there is some discussion in
kubernetes/kubernetes#82942 and kubernetes-sigs/kustomize#4613.

[1]: https://github.com/kubernetes-sigs/kustomize/blob/master/examples/customOpenAPIschema.md
[2]: https://blog.argoproj.io/argo-crds-and-kustomize-the-problem-of-patching-lists-5cfc43da288c

Strategic merge patches are the only way to patch lists by
object id, rather than by index, so it's functionality we need. To
support this, that means we need to dump the complete openapi schema
from our clusters to a file and make that available to Kustomize. This
commit introduces an initial version of this schema, but we will need
to update this in the future whenever we want to patch CRDs that
weren't available at the time we last generated this schema dump.
@snuggie12
Copy link

I agree the docs could be more clear. I noticed under openapi there is no list, just path so I figured all CRDs I want to edit need to be in the same file but didn't imagine it was everything.

I'm going to try and implement a relatively not too complex system for this using kustomize and some text parsing.

If you download all the schemas and store them in their own kustomize directories, attach a random GVK, patch the schemas you want to patch, run a kustomize that calls all the directories, chop off the random GVK and add in definitions at the top you got yourself a patching system for schemas:

$ head rt.openapi.yaml
apiVersion: v12
kind: OpenApi
metadata:
  name: io.solo.gateway.v1.RouteTable
def:
  io.solo.gateway.v1.RouteTable:
    properties:
      apiVersion:
        description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
        type: string

$ cat rt.openapi.patch.yaml
apiVersion: v12
kind: OpenApi
metadata:
  name: io.solo.gateway.v1.RouteTable
def:
  io.solo.gateway.v1.RouteTable:
    properties:
      spec:
        properties:
          routes:
            x-kubernetes-patch-merge-key: name
            x-kubernetes-patch-strategy: merge

$ kust build | yq '.def."io.solo.gateway.v1.RouteTable".properties.spec.properties.routes | keys'
- items
- type
- x-kubernetes-patch-merge-key
- x-kubernetes-patch-strategy

@larsks
Copy link
Contributor

larsks commented Nov 9, 2023

@snuggie12 I've implemented something like that here.

larsks added a commit to larsks/nerc-ocp-config that referenced this issue Nov 9, 2023
Due to issues with the way Kustomize handles patching lists in custom
resource types, we need to provide a complete OpenAPI schema that
includes schema definitions for any CRDs we wish to patch. See
kubernetes-sigs/kustomize#4613 for more
discussion on this topic.

See `cluster-scope/base/openapi/README.md` for more information.
@k8s-triage-robot
Copy link

This issue has not been updated in over 1 year, and should be re-triaged.

You can:

  • Confirm that this issue is still relevant with /triage accepted (org members only)
  • Close this issue with /close

For more details on the triage process, see https://www.kubernetes.dev/docs/guide/issue-triage/

/remove-triage accepted

@k8s-ci-robot k8s-ci-robot added needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one. and removed triage/accepted Indicates an issue or PR is ready to be actively worked on. labels Nov 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind/documentation Categorizes issue or PR as related to documentation. kind/feature Categorizes issue or PR as related to a new feature. lifecycle/frozen Indicates that an issue or PR should not be auto-closed due to staleness. needs-triage Indicates an issue or PR lacks a `triage/foo` label and requires one.
Projects
None yet
Development

No branches or pull requests