mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-06-30 01:46:23 +00:00
Compare commits
74 Commits
api/v0.14.
...
revert-533
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbbd1599f2 | ||
|
|
4b34ff3075 | ||
|
|
654d7953d9 | ||
|
|
7911b2c001 | ||
|
|
e3b9afcfaa | ||
|
|
af781bfa5e | ||
|
|
7dd9637b1a | ||
|
|
ddce57b585 | ||
|
|
11fc419cee | ||
|
|
a8dec66a84 | ||
|
|
7e541ca380 | ||
|
|
1bd58bdc15 | ||
|
|
9107fa3c81 | ||
|
|
433be59ea7 | ||
|
|
2c444d6bf4 | ||
|
|
59696d1ace | ||
|
|
d30e457031 | ||
|
|
ae041b5c54 | ||
|
|
a2b60e4bcb | ||
|
|
9d126f6dd8 | ||
|
|
bd8045b648 | ||
|
|
5c1a022a3c | ||
|
|
e19ca5405a | ||
|
|
56d37acc7d | ||
|
|
0571a2f15d | ||
|
|
0cdfa5b3dc | ||
|
|
7c36ed21b3 | ||
|
|
985835f96f | ||
|
|
f81765b96e | ||
|
|
a2ceaff053 | ||
|
|
94181b1be7 | ||
|
|
169fdd7330 | ||
|
|
78b8139d46 | ||
|
|
76f8d2828b | ||
|
|
b692e49b1e | ||
|
|
bd7f001c26 | ||
|
|
d6ff768298 | ||
|
|
4947a905fa | ||
|
|
cd9a16cfab | ||
|
|
02a53f193d | ||
|
|
b1717c8a97 | ||
|
|
911ddcda40 | ||
|
|
9f1d5acdc8 | ||
|
|
9756d92a91 | ||
|
|
d32d1937e6 | ||
|
|
ddcbae54ab | ||
|
|
ca748faa3f | ||
|
|
5e6cbac589 | ||
|
|
ff75dd6cd5 | ||
|
|
f8391994b4 | ||
|
|
5ce14e5024 | ||
|
|
ee22c9cab7 | ||
|
|
4a893ce8c6 | ||
|
|
9ce923ebeb | ||
|
|
494a807f28 | ||
|
|
820f17c73b | ||
|
|
cd7ba1744e | ||
|
|
da4e881007 | ||
|
|
878cda7c55 | ||
|
|
47327616df | ||
|
|
eeff67d88d | ||
|
|
6adf4f294a | ||
|
|
5e7cc3437d | ||
|
|
096b2c4435 | ||
|
|
129d0f90af | ||
|
|
c76fd5eb85 | ||
|
|
691b7d1df3 | ||
|
|
91078545e6 | ||
|
|
467633c2de | ||
|
|
e44df7b386 | ||
|
|
bbff6768da | ||
|
|
0020a496f7 | ||
|
|
9eddc3c5a7 | ||
|
|
7aa33ff471 |
36
.github/workflows/apidiff.yml
vendored
Normal file
36
.github/workflows/apidiff.yml
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
name: APIDiff
|
||||||
|
|
||||||
|
# Trigger the workflow on pull requests and direct pushes to any branch
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
go-apidiff:
|
||||||
|
name: Verify API differences
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Pull requests from different repository only trigger this checks
|
||||||
|
if: (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository)
|
||||||
|
steps:
|
||||||
|
- name: Clone the code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Setup Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version-file: go.work
|
||||||
|
- name: Execute go-apidiff
|
||||||
|
uses: joelanford/go-apidiff@v0.6.0
|
||||||
|
with:
|
||||||
|
compare-imports: true
|
||||||
|
print-compatible: true
|
||||||
|
- name: Report failure
|
||||||
|
uses: nashmaniac/create-issue-action@v1.1
|
||||||
|
# Only report failures of pushes (PRs have are visible through the Checks section) to the default branch
|
||||||
|
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||||
|
with:
|
||||||
|
title: 🐛 go-apidiff failed for ${{ github.sha }}
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
labels: kind/bug
|
||||||
|
body: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||||
27
.github/workflows/release.yaml
vendored
Normal file
27
.github/workflows/release.yaml
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
name: release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- kyaml/v*
|
||||||
|
- cmd/config/v*
|
||||||
|
- api/v*
|
||||||
|
- kustomize/v*
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code into the Go module directory
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Set up Go 1.x
|
||||||
|
uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version-file: go.work
|
||||||
|
id: go
|
||||||
|
- run: ./releasing/create-release.sh "${tag}"
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tag: ${{ github.ref_name }}
|
||||||
129
CONTRIBUTING.md
129
CONTRIBUTING.md
@@ -59,11 +59,140 @@ Kustomize follows the [Kubernetes Community Membership] contributor ladder. Role
|
|||||||
|
|
||||||
The kyaml module within the Kustomize repo has additional owners following the same ladder.
|
The kyaml module within the Kustomize repo has additional owners following the same ladder.
|
||||||
|
|
||||||
|
For the kustomize project, we have defined some specific guidelines on each step of the ladder:
|
||||||
|
|
||||||
|
To reach reviewer status, you must:
|
||||||
|
- Have been actively involved in kustomize for 3+ months
|
||||||
|
- Review at least 8 PRs that have been driven through to completion (see the reviewer guide below)
|
||||||
|
- Author at least 5 PRs that have been approved and merged
|
||||||
|
- Be a member of the kubernetes-sigs org. This should not be a blocker though, as once you meet the requirements for reviewer here,
|
||||||
|
the existing kustomize maintainers will be happy to sponsor your request to join the kubernetes-sigs org.
|
||||||
|
- Once you have met the above requirements, you may submit a PR adding yourself to the kustomize reviewers list, with links to your
|
||||||
|
contributions in the description.
|
||||||
|
|
||||||
|
To reach approver status, you must:
|
||||||
|
- Meet all the requirements of a reviewer
|
||||||
|
- Have been actively involved in kustomize for 6+ months
|
||||||
|
- Review at least 15 PRs that have been driven through to completion (see the reviewer guide below)
|
||||||
|
- Authored PRs meeting *either* of the following requirements:
|
||||||
|
- 15 PRs that have been approved and merged
|
||||||
|
- *OR* 10 PRs that have been approved and merged where some were more difficult, required greater thought/design,
|
||||||
|
or built up to larger features/long-term goals.
|
||||||
|
- File 3 issues. This can be any number of things, including but not limited to:
|
||||||
|
- Bugs with kustomize usage that you've found
|
||||||
|
- CI or release improvements
|
||||||
|
- Creating subtasks of a larger feature or project that you are in charge of.
|
||||||
|
- Long term improvements for the health of the project
|
||||||
|
- Triage at least 10 untriaged issues, including at least 1 feature request. The kustomize bug scrub is a great place to get practice with doing this, but you can
|
||||||
|
also follow the triage guide below to get started on your own.
|
||||||
|
- Demonstrate deeper understanding of kustomize goals. This can take many forms and is a bit subjective, but here are a few examples:
|
||||||
|
- saying no to an eschewed feature, instead recommending an alternative solution that is more aligned with the declarative configuration model
|
||||||
|
- active participation in discussion on a feature request issue
|
||||||
|
- filing an issue describing a long term problem and solution aligned with kustomize goals, for example: https://github.com/kubernetes-sigs/kustomize/issues/5140
|
||||||
|
- writing up KEPs for features that will improve the kustomize workflow while being aligned with kustomize goals, for example: https://github.com/kubernetes-sigs/kustomize/pull/4558
|
||||||
|
- Regularly interact with the existing kustomize maintainers, with clear communication about what you are working on or planning to work on. The kustomize
|
||||||
|
maintainers should know who you are and be familiar with your contributions.
|
||||||
|
- If you meet *most* of the above requirements while going above and beyond in a few areas, we will still consider your request to become an approver even
|
||||||
|
if you are missing one or two of the requirements. Please contact the maintainers directly to ask about getting approver status if you fall into this category.
|
||||||
|
- Otherwise, once you meet all the above requirements, you may:
|
||||||
|
- request to be added to the kustomize maintainer meeting that occurs each week with the kustomize PMs.
|
||||||
|
- submit a PR adding yourself to the kustomize approvers list, with links to your contributions in the description.
|
||||||
|
|
||||||
|
To reach owner status, you must:
|
||||||
|
- Meet all the requirements of an approver
|
||||||
|
- Have been actively involved with kustomize for 1+ year
|
||||||
|
- Assisted the current owner in driving the roadmap. This can be explicit or implicit help, such as:
|
||||||
|
- Editing the roadmap directly
|
||||||
|
- Reviewing the roadmap
|
||||||
|
- Providing suggestions for issues or prioritization in meetings that indirectly influence the roadmap
|
||||||
|
- Regularly triage issues and attend the kustomize bug scrub
|
||||||
|
- Regularly review PRs (1-2 a week)
|
||||||
|
- Periodically lead the kustomize bug scrub
|
||||||
|
- Periodically release kustomize (ensuring that there are no release blockers and that release notes are clean)
|
||||||
|
- Be the primary owner or point of contact for a particular project or area of code
|
||||||
|
- Ideally, there should be 2-3 owners at a time. Reach out to the current owners if you are interested in ownership. These
|
||||||
|
requirements are not strict and evaluation is somewhat subjective.
|
||||||
|
|
||||||
|
## Reviewer guide
|
||||||
|
Please watch this talk on how to review code from Tim Hockin: https://www.youtube.com/watch?v=OZVv7-o8i40
|
||||||
|
|
||||||
|
For reviewing PRs in kustomize, we have some specific guidelines:
|
||||||
|
- If the PR is introducing a new feature:
|
||||||
|
- *It must be implementing an issue that has already been triage/accepted or
|
||||||
|
a KEP that has been approved.* If it is not, then request the PR author to first file an issue.
|
||||||
|
- The PR must include thorough tests for the new feature, including unit and integration tests
|
||||||
|
- The code must be clean and readable, with thought given to how we will maintain the code in the future
|
||||||
|
- If the feature requires being broken up into multiple PRs to ease review, the feature should not be exposed to users
|
||||||
|
until the feature is completed in the last PR. For example, while we were building `kustomize localize`, we
|
||||||
|
built the feature almost entirely under the `api` module as a library with all the needed tests. There was no way
|
||||||
|
for users to invoke the localize code until the last PR that actually exposed the `kustomize localize` command in the
|
||||||
|
kustomize binary. This allowed us to continue development of `kustomize localize` without blocking kustomize releases.
|
||||||
|
If this type of development is not possible, then new features requiring multiple PRs should be
|
||||||
|
developed in their own feature branch.
|
||||||
|
- If the PR is introducing a bug fix:
|
||||||
|
- If the PR is not fixing an issue that has already been triage/accepted, follow the triage guide below on bug
|
||||||
|
fixes to decide if this is a PR we want to accept.
|
||||||
|
- The PR should have two distinct commits:
|
||||||
|
- The first commit should add a test demonstrating incorrect behavior
|
||||||
|
- The second commit should include the bug fix
|
||||||
|
- Some sample PRs:
|
||||||
|
- https://github.com/kubernetes-sigs/kustomize/pull/5263/commits
|
||||||
|
- https://github.com/kubernetes-sigs/kustomize/pull/3931/commits
|
||||||
|
- The regression test is absolutely required, and we cannot accept bug fixes without tests.
|
||||||
|
- If the PR is introducing a performance improvement:
|
||||||
|
- The PR description should give an indication of how much the performance is being improved and how we
|
||||||
|
can measure it - benchmark tests are fantastic.
|
||||||
|
- Other PRs (documentation, CI improvements, etc.) should be reviewed based on your best judgment.
|
||||||
|
|
||||||
|
## Triage guide
|
||||||
|
The possible triage labels are listed here: https://github.com/kubernetes-sigs/kustomize/labels?q=triage.
|
||||||
|
|
||||||
|
Triaging a feature request means:
|
||||||
|
- Understand what the user is asking for, and their use case.
|
||||||
|
- Verify that it is not an [eschewed feature](https://kubectl.docs.kubernetes.io/faq/kustomize/eschewedfeatures/#build-time-side-effects-from-cli-args-or-env-variables)
|
||||||
|
- Verify that it is not a duplicate issue.
|
||||||
|
- Look into workarounds. Is there another way that the user can achieve their use case with existing features?
|
||||||
|
- If you are new to this role, prior to leaving a comment on the issue, please bring it to weekly standup
|
||||||
|
for group discussion to make sure that we are all on the same page.
|
||||||
|
- Once you feel ready, you can label it with a triage label. Here's an [example](https://github.com/kubernetes-sigs/kustomize/issues/5049). You can also
|
||||||
|
look at other feature request issues to see how they were triaged and resolved. There are a few different triage labels that you can use, you can see the
|
||||||
|
full list [here](https://github.com/kubernetes-sigs/kustomize/labels?q=triage).
|
||||||
|
|
||||||
|
Triaging a bug means:
|
||||||
|
- First, verify that you can reproduce the issue. If you cannot reproduce the issue or need more information to give
|
||||||
|
it a go, triage it accordingly.
|
||||||
|
- Try to understand if this is really a bug or if this is intended behavior from kustomize. If it seems like intended
|
||||||
|
behavior, do your best to explain to the user why this is the case.
|
||||||
|
- If it seems to be a genuine bug, you can /triage accept the issue. In addition, investigate if there are workarounds or
|
||||||
|
alternative solutions for the user that they can try until the issue gets resolved.
|
||||||
|
|
||||||
Administrative notes:
|
Administrative notes:
|
||||||
|
|
||||||
- The [OWNERS file spec] is a useful resources in making changes.
|
- The [OWNERS file spec] is a useful resources in making changes.
|
||||||
- Maintainers and admins must be added to the appropriate lists in both [Kustomize OWNERS_ALIASES] and [SIG-CLI Teams]. If this isn't done, the individual in question will lack either PR approval rights (Kustomize list) or the appropriate Github repository permissions (community list).
|
- Maintainers and admins must be added to the appropriate lists in both [Kustomize OWNERS_ALIASES] and [SIG-CLI Teams]. If this isn't done, the individual in question will lack either PR approval rights (Kustomize list) or the appropriate Github repository permissions (community list).
|
||||||
|
|
||||||
|
## Project/Product Managers
|
||||||
|
|
||||||
|
Kustomize will have opportunities to join in a project/product manager role. You can reach out to
|
||||||
|
the existing kustomize maintainers if you are interested in this type of role. Project management work
|
||||||
|
can greatly help supplement your contributions as you climb from reviewer to approver
|
||||||
|
to owner.
|
||||||
|
|
||||||
|
Expectations for this role are:
|
||||||
|
|
||||||
|
- Triage 1 feature request each week, and bring it to weekly stand-up for discussion. Feature
|
||||||
|
requests are issues labeled kind/feature, and you can find them [here](https://github.com/kubernetes-sigs/kustomize/issues?q=is%3Aissue+is%3Aopen+kind+feature+label%3Akind%2Ffeature).
|
||||||
|
Please view the above triage guide for details on how to approach feature request triage.
|
||||||
|
- Monitor the kustomize Slack channel and try to help users if you can. It is a pretty
|
||||||
|
active channel, so responding to 4-5 users per week is sufficient even if some
|
||||||
|
questions go unanswered. If there is an interesting topic or a recurring problem that many
|
||||||
|
users are having, please bring it up in weekly stand-up.
|
||||||
|
- Keeping track of a queue of backlog issues or PRs that are not being actively looked at in any existing project board.
|
||||||
|
- Organizing or reorganizing project tracking boards when it makes sense.
|
||||||
|
|
||||||
|
You will also be asked to help with roadmap planning, deprecation communication, prioritization,
|
||||||
|
and doing research on kustomize usage when appropriate, though these responsibilities will occur less
|
||||||
|
frequently.
|
||||||
|
|
||||||
## Contact Information
|
## Contact Information
|
||||||
|
|
||||||
|
|||||||
10
Makefile
10
Makefile
@@ -3,7 +3,7 @@
|
|||||||
#
|
#
|
||||||
# Makefile for kustomize CLI and API.
|
# Makefile for kustomize CLI and API.
|
||||||
|
|
||||||
LATEST_RELEASE=v5.0.3
|
LATEST_RELEASE=v5.1.1
|
||||||
|
|
||||||
SHELL := /usr/bin/env bash
|
SHELL := /usr/bin/env bash
|
||||||
GOOS = $(shell go env GOOS)
|
GOOS = $(shell go env GOOS)
|
||||||
@@ -126,6 +126,14 @@ check-license: $(MYGOBIN)/addlicense
|
|||||||
lint: $(MYGOBIN)/golangci-lint $(MYGOBIN)/goimports $(builtinplugins)
|
lint: $(MYGOBIN)/golangci-lint $(MYGOBIN)/goimports $(builtinplugins)
|
||||||
./hack/for-each-module.sh "make lint"
|
./hack/for-each-module.sh "make lint"
|
||||||
|
|
||||||
|
.PHONY: apidiff
|
||||||
|
apidiff: go-apidiff ## Run the go-apidiff to verify any API differences compared with origin/master
|
||||||
|
$(GOBIN)/go-apidiff master --compare-imports --print-compatible --repo-path=.
|
||||||
|
|
||||||
|
.PHONY: go-apidiff
|
||||||
|
go-apidiff:
|
||||||
|
go install github.com/joelanford/go-apidiff@v0.6.0
|
||||||
|
|
||||||
.PHONY: test-unit-all
|
.PHONY: test-unit-all
|
||||||
test-unit-all: \
|
test-unit-all: \
|
||||||
test-unit-non-plugin \
|
test-unit-non-plugin \
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ aliases:
|
|||||||
- knverey
|
- knverey
|
||||||
- natasha41575
|
- natasha41575
|
||||||
- annasong20
|
- annasong20
|
||||||
|
- koba1t
|
||||||
kustomize-reviewers:
|
kustomize-reviewers:
|
||||||
- knverey
|
- knverey
|
||||||
- natasha41575
|
- natasha41575
|
||||||
|
|||||||
84
README.md
84
README.md
@@ -36,11 +36,16 @@ be updated on a regular basis going forward, and such updates
|
|||||||
will be reflected in the Kubernetes release notes.
|
will be reflected in the Kubernetes release notes.
|
||||||
|
|
||||||
| Kubectl version | Kustomize version |
|
| Kubectl version | Kustomize version |
|
||||||
| --- | --- |
|
| --------------- | ----------------- |
|
||||||
| < v1.14 | n/a |
|
| < v1.14 | n/a |
|
||||||
| v1.14-v1.20 | v2.0.3 |
|
| v1.14-v1.20 | v2.0.3 |
|
||||||
| v1.21 | v4.0.5 |
|
| v1.21 | v4.0.5 |
|
||||||
| v1.22 | v4.2.0 |
|
| v1.22 | v4.2.0 |
|
||||||
|
| v1.23 | v4.4.1 |
|
||||||
|
| v1.24 | v4.5.4 |
|
||||||
|
| v1.25 | v4.5.7 |
|
||||||
|
| v1.26 | v4.5.7 |
|
||||||
|
| v1.27 | v5.0.1 |
|
||||||
|
|
||||||
[v2.0.3]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.0.3
|
[v2.0.3]: https://github.com/kubernetes-sigs/kustomize/releases/tag/v2.0.3
|
||||||
[#2506]: https://github.com/kubernetes-sigs/kustomize/issues/2506
|
[#2506]: https://github.com/kubernetes-sigs/kustomize/issues/2506
|
||||||
@@ -63,7 +68,37 @@ This file should declare those resources, and any
|
|||||||
customization to apply to them, e.g. _add a common
|
customization to apply to them, e.g. _add a common
|
||||||
label_.
|
label_.
|
||||||
|
|
||||||
![base image][imageBase]
|
```
|
||||||
|
|
||||||
|
base: kustomization + resources
|
||||||
|
|
||||||
|
kustomization.yaml deployment.yaml service.yaml
|
||||||
|
+---------------------------------------------+ +-------------------------------------------------------+ +-----------------------------------+
|
||||||
|
| apiVersion: kustomize.config.k8s.io/v1beta1 | | apiVersion: apps/v1 | | apiVersion: v1 |
|
||||||
|
| kind: Kustomization | | kind: Deployment | | kind: Service |
|
||||||
|
|.commonLabels: | | metadata: | | metadata: |
|
||||||
|
| app: myapp | | name: myapp | | name: myapp |
|
||||||
|
| resources: | | spec: | | spec: |
|
||||||
|
| - deployment.yaml | | selector: | | selector: |
|
||||||
|
| - service.yaml | | matchLabels: | | app: myapp |
|
||||||
|
| configMapGenerator: | | app: myapp | | ports: |
|
||||||
|
| - name: myapp-map | | template: | | - port: 6060 |
|
||||||
|
| literals: | | metadata: | | targetPort: 6060 |
|
||||||
|
| - KEY=value | | labels: | +-----------------------------------+
|
||||||
|
+---------------------------------------------+ | app: myapp |
|
||||||
|
| spec: |
|
||||||
|
| containers: |
|
||||||
|
| - name: myapp |
|
||||||
|
| image: myapp |
|
||||||
|
| resources: |
|
||||||
|
| limits: |
|
||||||
|
| memory: "128Mi" |
|
||||||
|
| cpu: "500m" |
|
||||||
|
| ports: |
|
||||||
|
| - containerPort: 6060 |
|
||||||
|
+-------------------------------------------------------+
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
File structure:
|
File structure:
|
||||||
|
|
||||||
@@ -99,20 +134,41 @@ Manage traditional [variants] of a configuration - like
|
|||||||
_development_, _staging_ and _production_ - using
|
_development_, _staging_ and _production_ - using
|
||||||
[overlays] that modify a common [base].
|
[overlays] that modify a common [base].
|
||||||
|
|
||||||
![overlay image][imageOverlay]
|
```
|
||||||
|
|
||||||
|
overlay: kustomization + patches
|
||||||
|
|
||||||
|
kustomization.yaml replica_count.yaml cpu_count.yaml
|
||||||
|
+-----------------------------------------------+ +-------------------------------+ +------------------------------------------+
|
||||||
|
| apiVersion: kustomize.config.k8s.io/v1beta1 | | apiVersion: apps/v1 | | apiVersion: apps/v1 |
|
||||||
|
| kind: Kustomization | | kind: Deployment | | kind: Deployment |
|
||||||
|
| commonLabels: | | metadata: | | metadata: |
|
||||||
|
| variant: prod | | name: myapp | | name: myapp |
|
||||||
|
| resources: | | spec: | | spec: |
|
||||||
|
| - ../../base | | replicas: 80 | | template: |
|
||||||
|
| patches: | +-------------------------------+ | spec: |
|
||||||
|
| - path: replica_count.yaml | | containers: |
|
||||||
|
| - path: cpu_count.yaml | | - name: myapp |
|
||||||
|
+-----------------------------------------------+ | resources: |
|
||||||
|
| limits: |
|
||||||
|
| memory: "128Mi" |
|
||||||
|
| cpu: "7000m" |
|
||||||
|
+------------------------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
File structure:
|
File structure:
|
||||||
> ```
|
> ```
|
||||||
> ~/someApp
|
> ~/someApp
|
||||||
> ├── base
|
> ├── base
|
||||||
> │ ├── deployment.yaml
|
> │ ├── deployment.yaml
|
||||||
> │ ├── kustomization.yaml
|
> │ ├── kustomization.yaml
|
||||||
> │ └── service.yaml
|
> │ └── service.yaml
|
||||||
> └── overlays
|
> └── overlays
|
||||||
> ├── development
|
> ├── development
|
||||||
> │ ├── cpu_count.yaml
|
> │ ├── cpu_count.yaml
|
||||||
> │ ├── kustomization.yaml
|
> │ ├── kustomization.yaml
|
||||||
> │ └── replica_count.yaml
|
> │ └── replica_count.yaml
|
||||||
> └── production
|
> └── production
|
||||||
> ├── cpu_count.yaml
|
> ├── cpu_count.yaml
|
||||||
> ├── kustomization.yaml
|
> ├── kustomization.yaml
|
||||||
@@ -166,8 +222,6 @@ is governed by the [Kubernetes Code of Conduct].
|
|||||||
[applied]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#apply
|
[applied]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#apply
|
||||||
[base]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#base
|
[base]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#base
|
||||||
[declarative configuration]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#declarative-application-management
|
[declarative configuration]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#declarative-application-management
|
||||||
[imageBase]: images/base.jpg
|
|
||||||
[imageOverlay]: images/overlay.jpg
|
|
||||||
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
|
[kubectl announcement]: https://kubernetes.io/blog/2019/03/25/kubernetes-1-14-release-announcement
|
||||||
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
|
[kubernetes documentation]: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/
|
||||||
[kubernetes style]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#kubernetes-style-object
|
[kubernetes style]: https://kubectl.docs.kubernetes.io/references/kustomize/glossary/#kubernetes-style-object
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ package imagetag
|
|||||||
import (
|
import (
|
||||||
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
"sigs.k8s.io/kustomize/api/filters/filtersutil"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/image"
|
"sigs.k8s.io/kustomize/api/internal/image"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ package patchjson6902
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "gopkg.in/evanphx/json-patch.v5"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
"sigs.k8s.io/kustomize/kyaml/kio"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
k8syaml "sigs.k8s.io/yaml"
|
k8syaml "sigs.k8s.io/yaml"
|
||||||
|
|||||||
@@ -776,6 +776,133 @@ spec:
|
|||||||
autoscaling: true
|
autoscaling: true
|
||||||
deepgram-api:
|
deepgram-api:
|
||||||
some: value
|
some: value
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Issue #4928
|
||||||
|
"support numeric keys": {
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "foobar"
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "barfoo"
|
||||||
|
"9110": "foo-foo"
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "barfoo"
|
||||||
|
"9110": "foo-foo"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
"honor different key style one": {
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
'6443': "foobar"
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "barfoo"
|
||||||
|
9110: "foo-foo"
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
'6443': "barfoo"
|
||||||
|
9110: "foo-foo"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
"honor different key style two": {
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "foobar"
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "barfoo"
|
||||||
|
'9110': "foo-foo"
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "barfoo"
|
||||||
|
'9110': "foo-foo"
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
|
||||||
|
"different key types": {
|
||||||
|
input: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "key-string-double-quoted"
|
||||||
|
`,
|
||||||
|
patch: yaml.MustParse(`
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
6443: "key-int"
|
||||||
|
`),
|
||||||
|
expected: `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: blabla
|
||||||
|
namespace: blabla-ns
|
||||||
|
data:
|
||||||
|
"6443": "key-int"
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,8 +126,8 @@ func applyReplacement(nodes []*yaml.RNode, value *yaml.RNode, targetSelectors []
|
|||||||
}
|
}
|
||||||
|
|
||||||
// filter targets by matching resource IDs
|
// filter targets by matching resource IDs
|
||||||
for i, id := range ids {
|
for _, id := range ids {
|
||||||
if id.IsSelectedBy(selector.Select.ResId) && !rejectId(selector.Reject, &ids[i]) {
|
if id.IsSelectedBy(selector.Select.ResId) && !containsRejectId(selector.Reject, ids) {
|
||||||
err := copyValueToTarget(possibleTarget, value, selector)
|
err := copyValueToTarget(possibleTarget, value, selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -168,10 +168,15 @@ func matchesAnnoAndLabelSelector(n *yaml.RNode, selector *types.Selector) (bool,
|
|||||||
return annoMatch && labelMatch, nil
|
return annoMatch && labelMatch, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rejectId(rejects []*types.Selector, id *resid.ResId) bool {
|
func containsRejectId(rejects []*types.Selector, ids []resid.ResId) bool {
|
||||||
for _, r := range rejects {
|
for _, r := range rejects {
|
||||||
if !r.ResId.IsEmpty() && id.IsSelectedBy(r.ResId) {
|
if r.ResId.IsEmpty() {
|
||||||
return true
|
continue
|
||||||
|
}
|
||||||
|
for _, id := range ids {
|
||||||
|
if id.IsSelectedBy(r.ResId) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ module sigs.k8s.io/kustomize/api
|
|||||||
go 1.20
|
go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible
|
|
||||||
github.com/go-errors/errors v1.4.2
|
github.com/go-errors/errors v1.4.2
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
|
||||||
github.com/imdario/mergo v0.3.6
|
github.com/imdario/mergo v0.3.6
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.1
|
||||||
|
gopkg.in/evanphx/json-patch.v5 v5.6.0
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961
|
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3
|
sigs.k8s.io/kustomize/kyaml v0.14.3
|
||||||
@@ -35,3 +35,5 @@ require (
|
|||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace sigs.k8s.io/kustomize/kyaml => ../kyaml
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
@@ -75,6 +73,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/evanphx/json-patch.v5 v5.6.0 h1:BMT6KIwBD9CaU91PJCZIe46bDmBWa9ynTQgJIOpfQBk=
|
||||||
|
gopkg.in/evanphx/json-patch.v5 v5.6.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
@@ -85,7 +85,5 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|||||||
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961 h1:pqRVJGQJz6oeZby8qmPKXYIBjyrcv7EHCe/33UkZMYA=
|
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961 h1:pqRVJGQJz6oeZby8qmPKXYIBjyrcv7EHCe/33UkZMYA=
|
||||||
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961/go.mod h1:l8HTwL5fqnlns4jOveW1L75eo7R9KFHxiE0bsPGy428=
|
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961/go.mod h1:l8HTwL5fqnlns4jOveW1L75eo7R9KFHxiE0bsPGy428=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3 h1:WpabVAKZe2YEp/irTSHwD6bfjwZnTtSDewd2BVJGMZs=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3/go.mod h1:npvh9epWysfQ689Rtt/U+dpOJDTBn8kUnF1O6VzvmZA=
|
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
. "sigs.k8s.io/kustomize/api/internal/accumulator"
|
. "sigs.k8s.io/kustomize/api/internal/accumulator"
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
"sigs.k8s.io/kustomize/kyaml/resid"
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ package builtins
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "gopkg.in/evanphx/json-patch.v5"
|
||||||
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
|||||||
@@ -7,104 +7,123 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
jsonpatch "github.com/evanphx/json-patch"
|
jsonpatch "gopkg.in/evanphx/json-patch.v5"
|
||||||
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
"sigs.k8s.io/kustomize/api/filters/patchjson6902"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
"sigs.k8s.io/kustomize/kyaml/kio/kioutil"
|
||||||
"sigs.k8s.io/yaml"
|
"sigs.k8s.io/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
type PatchTransformerPlugin struct {
|
type PatchTransformerPlugin struct {
|
||||||
loadedPatch *resource.Resource
|
smPatches []*resource.Resource // strategic-merge patches
|
||||||
decodedPatch jsonpatch.Patch
|
jsonPatches jsonpatch.Patch // json6902 patch
|
||||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
// patchText is pure patch text created by Path or Patch
|
||||||
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
patchText string
|
||||||
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
// patchSource is patch source message
|
||||||
Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"`
|
patchSource string
|
||||||
|
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||||
|
Patch string `json:"patch,omitempty" yaml:"patch,omitempty"`
|
||||||
|
Target *types.Selector `json:"target,omitempty" yaml:"target,omitempty"`
|
||||||
|
Options map[string]bool `json:"options,omitempty" yaml:"options,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PatchTransformerPlugin) Config(
|
func (p *PatchTransformerPlugin) Config(h *resmap.PluginHelpers, c []byte) error {
|
||||||
h *resmap.PluginHelpers, c []byte) error {
|
if err := yaml.Unmarshal(c, p); err != nil {
|
||||||
err := yaml.Unmarshal(c, p)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
p.Patch = strings.TrimSpace(p.Patch)
|
p.Patch = strings.TrimSpace(p.Patch)
|
||||||
if p.Patch == "" && p.Path == "" {
|
switch {
|
||||||
return fmt.Errorf(
|
case p.Patch == "" && p.Path == "":
|
||||||
"must specify one of patch and path in\n%s", string(c))
|
return fmt.Errorf("must specify one of patch and path in\n%s", string(c))
|
||||||
}
|
case p.Patch != "" && p.Path != "":
|
||||||
if p.Patch != "" && p.Path != "" {
|
return fmt.Errorf("patch and path can't be set at the same time\n%s", string(c))
|
||||||
return fmt.Errorf(
|
case p.Patch != "":
|
||||||
"patch and path can't be set at the same time\n%s", string(c))
|
p.patchText = p.Patch
|
||||||
}
|
p.patchSource = fmt.Sprintf("[patch: %q]", p.patchText)
|
||||||
if p.Path != "" {
|
case p.Path != "":
|
||||||
loaded, loadErr := h.Loader().Load(p.Path)
|
loaded, err := h.Loader().Load(p.Path)
|
||||||
if loadErr != nil {
|
if err != nil {
|
||||||
return loadErr
|
return fmt.Errorf("failed to get the patch file from path(%s): %w", p.Path, err)
|
||||||
}
|
}
|
||||||
p.Patch = string(loaded)
|
p.patchText = string(loaded)
|
||||||
|
p.patchSource = fmt.Sprintf("[path: %q]", p.Path)
|
||||||
}
|
}
|
||||||
|
|
||||||
patchSM, errSM := h.ResmapFactory().RF().FromBytes([]byte(p.Patch))
|
patchesSM, errSM := h.ResmapFactory().RF().SliceFromBytes([]byte(p.patchText))
|
||||||
patchJson, errJson := jsonPatchFromBytes([]byte(p.Patch))
|
patchesJson, errJson := jsonPatchFromBytes([]byte(p.patchText))
|
||||||
|
|
||||||
if (errSM == nil && errJson == nil) ||
|
if (errSM == nil && errJson == nil) ||
|
||||||
(patchSM != nil && patchJson != nil) {
|
(patchesSM != nil && patchesJson != nil) {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"illegally qualifies as both an SM and JSON patch: [%v]",
|
"illegally qualifies as both an SM and JSON patch: %s",
|
||||||
p.Patch)
|
p.patchSource)
|
||||||
}
|
}
|
||||||
if errSM != nil && errJson != nil {
|
if errSM != nil && errJson != nil {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
"unable to parse SM or JSON patch from [%v]", p.Patch)
|
"unable to parse SM or JSON patch from %s", p.patchSource)
|
||||||
}
|
}
|
||||||
if errSM == nil {
|
if errSM == nil {
|
||||||
p.loadedPatch = patchSM
|
p.smPatches = patchesSM
|
||||||
if p.Options["allowNameChange"] {
|
for _, loadedPatch := range p.smPatches {
|
||||||
p.loadedPatch.AllowNameChange()
|
if p.Options["allowNameChange"] {
|
||||||
}
|
loadedPatch.AllowNameChange()
|
||||||
if p.Options["allowKindChange"] {
|
}
|
||||||
p.loadedPatch.AllowKindChange()
|
if p.Options["allowKindChange"] {
|
||||||
|
loadedPatch.AllowKindChange()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p.decodedPatch = patchJson
|
p.jsonPatches = patchesJson
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
|
func (p *PatchTransformerPlugin) Transform(m resmap.ResMap) error {
|
||||||
if p.loadedPatch == nil {
|
if p.smPatches != nil {
|
||||||
return p.transformJson6902(m, p.decodedPatch)
|
return p.transformStrategicMerge(m)
|
||||||
}
|
}
|
||||||
// The patch was a strategic merge patch
|
return p.transformJson6902(m)
|
||||||
return p.transformStrategicMerge(m, p.loadedPatch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// transformStrategicMerge applies the provided strategic merge patch
|
// transformStrategicMerge applies each loaded strategic merge patch
|
||||||
// to all the resources in the ResMap that match either the Target or
|
// to the resource in the ResMap that matches the identifier of the patch.
|
||||||
// the identifier of the patch.
|
// If only one patch is specified, the Target can be used instead.
|
||||||
func (p *PatchTransformerPlugin) transformStrategicMerge(m resmap.ResMap, patch *resource.Resource) error {
|
func (p *PatchTransformerPlugin) transformStrategicMerge(m resmap.ResMap) error {
|
||||||
if p.Target == nil {
|
if p.Target != nil {
|
||||||
|
if len(p.smPatches) > 1 {
|
||||||
|
// detail: https://github.com/kubernetes-sigs/kustomize/issues/5049#issuecomment-1440604403
|
||||||
|
return fmt.Errorf("Multiple Strategic-Merge Patches in one `patches` entry is not allowed to set `patches.target` field: %s", p.patchSource)
|
||||||
|
}
|
||||||
|
|
||||||
|
// single patch
|
||||||
|
patch := p.smPatches[0]
|
||||||
|
selected, err := m.Select(*p.Target)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to find patch target %q in `resources`: %w", p.Target, err)
|
||||||
|
}
|
||||||
|
return errors.Wrap(m.ApplySmPatch(resource.MakeIdSet(selected), patch))
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, patch := range p.smPatches {
|
||||||
target, err := m.GetById(patch.OrgId())
|
target, err := m.GetById(patch.OrgId())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return fmt.Errorf("no resource matches strategic merge patch %q: %w", patch.OrgId(), err)
|
||||||
|
}
|
||||||
|
if err := target.ApplySmPatch(patch); err != nil {
|
||||||
|
return errors.Wrap(err)
|
||||||
}
|
}
|
||||||
return target.ApplySmPatch(patch)
|
|
||||||
}
|
}
|
||||||
selected, err := m.Select(*p.Target)
|
return nil
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return m.ApplySmPatch(resource.MakeIdSet(selected), patch)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// transformJson6902 applies the provided json6902 patch
|
// transformJson6902 applies json6902 Patch to all the resources in the ResMap that match Target.
|
||||||
// to all the resources in the ResMap that match the Target.
|
func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap) error {
|
||||||
func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpatch.Patch) error {
|
|
||||||
if p.Target == nil {
|
if p.Target == nil {
|
||||||
return fmt.Errorf("must specify a target for patch %s", p.Patch)
|
return fmt.Errorf("must specify a target for JSON patch %s", p.patchSource)
|
||||||
}
|
}
|
||||||
resources, err := m.Select(*p.Target)
|
resources, err := m.Select(*p.Target)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -114,7 +133,7 @@ func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpa
|
|||||||
res.StorePreviousId()
|
res.StorePreviousId()
|
||||||
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
|
internalAnnotations := kioutil.GetInternalAnnotations(&res.RNode)
|
||||||
err = res.ApplyFilter(patchjson6902.Filter{
|
err = res.ApplyFilter(patchjson6902.Filter{
|
||||||
Patch: p.Patch,
|
Patch: p.patchText,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -129,16 +148,17 @@ func (p *PatchTransformerPlugin) transformJson6902(m resmap.ResMap, patch jsonpa
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// jsonPatchFromBytes loads a Json 6902 patch from
|
// jsonPatchFromBytes loads a Json 6902 patch from a bytes input
|
||||||
// a bytes input
|
func jsonPatchFromBytes(in []byte) (jsonpatch.Patch, error) {
|
||||||
func jsonPatchFromBytes(
|
|
||||||
in []byte) (jsonpatch.Patch, error) {
|
|
||||||
ops := string(in)
|
ops := string(in)
|
||||||
if ops == "" {
|
if ops == "" {
|
||||||
return nil, fmt.Errorf("empty json patch operations")
|
return nil, fmt.Errorf("empty json patch operations")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ops[0] != '[' {
|
if ops[0] != '[' {
|
||||||
|
// TODO(5049):
|
||||||
|
// In the case of multiple yaml documents, return error instead of ignoring all but first.
|
||||||
|
// Details: https://github.com/kubernetes-sigs/kustomize/pull/5194#discussion_r1256686728
|
||||||
jsonOps, err := yaml.YAMLToJSON(in)
|
jsonOps, err := yaml.YAMLToJSON(in)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
. "sigs.k8s.io/kustomize/api/internal/generators"
|
. "sigs.k8s.io/kustomize/api/internal/generators"
|
||||||
"sigs.k8s.io/kustomize/api/kv"
|
"sigs.k8s.io/kustomize/api/kv"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
"sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
. "sigs.k8s.io/kustomize/api/internal/generators"
|
. "sigs.k8s.io/kustomize/api/internal/generators"
|
||||||
"sigs.k8s.io/kustomize/api/kv"
|
"sigs.k8s.io/kustomize/api/kv"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
"sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
// Copyright 2020 The Kubernetes Authors.
|
// Copyright 2020 The Kubernetes Authors.
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
package image
|
package image_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/image"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIsImageMatched(t *testing.T) {
|
func TestIsImageMatched(t *testing.T) {
|
||||||
@@ -50,7 +51,7 @@ func TestIsImageMatched(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.testName, func(t *testing.T) {
|
t.Run(tc.testName, func(t *testing.T) {
|
||||||
assert.Equal(t, tc.isMatched, IsImageMatched(tc.value, tc.name))
|
assert.Equal(t, tc.isMatched, image.IsImageMatched(tc.value, tc.name))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,7 +117,7 @@ func TestSplit(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.testName, func(t *testing.T) {
|
t.Run(tc.testName, func(t *testing.T) {
|
||||||
name, tag, digest := Split(tc.value)
|
name, tag, digest := image.Split(tc.value)
|
||||||
assert.Equal(t, tc.name, name)
|
assert.Equal(t, tc.name, name)
|
||||||
assert.Equal(t, tc.tag, tag)
|
assert.Equal(t, tc.tag, tag)
|
||||||
assert.Equal(t, tc.digest, digest)
|
assert.Equal(t, tc.digest, digest)
|
||||||
@@ -25,7 +25,7 @@ func IsRemoteFile(path string) bool {
|
|||||||
return err == nil && (u.Scheme == "http" || u.Scheme == "https")
|
return err == nil && (u.Scheme == "http" || u.Scheme == "https")
|
||||||
}
|
}
|
||||||
|
|
||||||
// fileLoader is a kustomization's interface to files.
|
// FileLoader is a kustomization's interface to files.
|
||||||
//
|
//
|
||||||
// The directory in which a kustomization file sits
|
// The directory in which a kustomization file sits
|
||||||
// is referred to below as the kustomization's _root_.
|
// is referred to below as the kustomization's _root_.
|
||||||
@@ -38,49 +38,48 @@ func IsRemoteFile(path string) bool {
|
|||||||
//
|
//
|
||||||
// * supplemental data paths
|
// * supplemental data paths
|
||||||
//
|
//
|
||||||
// `Load` is used to visit these paths.
|
// `Load` is used to visit these paths.
|
||||||
//
|
//
|
||||||
// These paths refer to resources, patches,
|
// These paths refer to resources, patches,
|
||||||
// data for ConfigMaps and Secrets, etc.
|
// data for ConfigMaps and Secrets, etc.
|
||||||
//
|
//
|
||||||
// The loadRestrictor may disallow certain paths
|
// The loadRestrictor may disallow certain paths
|
||||||
// or classes of paths.
|
// or classes of paths.
|
||||||
//
|
//
|
||||||
// * bases (other kustomizations)
|
// * bases (other kustomizations)
|
||||||
//
|
//
|
||||||
// `New` is used to load bases.
|
// `New` is used to load bases.
|
||||||
//
|
//
|
||||||
// A base can be either a remote git repo URL, or
|
// A base can be either a remote git repo URL, or
|
||||||
// a directory specified relative to the current
|
// a directory specified relative to the current
|
||||||
// root. In the former case, the repo is locally
|
// root. In the former case, the repo is locally
|
||||||
// cloned, and the new loader is rooted on a path
|
// cloned, and the new loader is rooted on a path
|
||||||
// in that clone.
|
// in that clone.
|
||||||
//
|
//
|
||||||
// As loaders create new loaders, a root history
|
// As loaders create new loaders, a root history
|
||||||
// is established, and used to disallow:
|
// is established, and used to disallow:
|
||||||
//
|
//
|
||||||
// - A base that is a repository that, in turn,
|
// - A base that is a repository that, in turn,
|
||||||
// specifies a base repository seen previously
|
// specifies a base repository seen previously
|
||||||
// in the loading stack (a cycle).
|
// in the loading stack (a cycle).
|
||||||
//
|
//
|
||||||
// - An overlay depending on a base positioned at
|
// - An overlay depending on a base positioned at
|
||||||
// or above it. I.e. '../foo' is OK, but '.',
|
// or above it. I.e. '../foo' is OK, but '.',
|
||||||
// '..', '../..', etc. are disallowed. Allowing
|
// '..', '../..', etc. are disallowed. Allowing
|
||||||
// such a base has no advantages and encourages
|
// such a base has no advantages and encourages
|
||||||
// cycles, particularly if some future change
|
// cycles, particularly if some future change
|
||||||
// were to introduce globbing to file
|
// were to introduce globbing to file
|
||||||
// specifications in the kustomization file.
|
// specifications in the kustomization file.
|
||||||
//
|
//
|
||||||
// These restrictions assure that kustomizations
|
// These restrictions assure that kustomizations
|
||||||
// are self-contained and relocatable, and impose
|
// are self-contained and relocatable, and impose
|
||||||
// some safety when relying on remote kustomizations,
|
// some safety when relying on remote kustomizations,
|
||||||
// e.g. a remotely loaded ConfigMap generator specified
|
// e.g. a remotely loaded ConfigMap generator specified
|
||||||
// to read from /etc/passwd will fail.
|
// to read from /etc/passwd will fail.
|
||||||
//
|
type FileLoader struct {
|
||||||
type fileLoader struct {
|
|
||||||
// Loader that spawned this loader.
|
// Loader that spawned this loader.
|
||||||
// Used to avoid cycles.
|
// Used to avoid cycles.
|
||||||
referrer *fileLoader
|
referrer *FileLoader
|
||||||
|
|
||||||
// An absolute, cleaned path to a directory.
|
// An absolute, cleaned path to a directory.
|
||||||
// The Load function will read non-absolute
|
// The Load function will read non-absolute
|
||||||
@@ -107,23 +106,9 @@ type fileLoader struct {
|
|||||||
cleaner func() error
|
cleaner func() error
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewFileLoaderAtCwd returns a loader that loads from PWD.
|
|
||||||
// A convenience for kustomize edit commands.
|
|
||||||
func NewFileLoaderAtCwd(fSys filesys.FileSystem) *fileLoader {
|
|
||||||
return newLoaderOrDie(
|
|
||||||
RestrictionRootOnly, fSys, filesys.SelfDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFileLoaderAtRoot returns a loader that loads from "/".
|
|
||||||
// A convenience for tests.
|
|
||||||
func NewFileLoaderAtRoot(fSys filesys.FileSystem) *fileLoader {
|
|
||||||
return newLoaderOrDie(
|
|
||||||
RestrictionRootOnly, fSys, filesys.Separator)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Repo returns the absolute path to the repo that contains Root if this fileLoader was created from a url
|
// Repo returns the absolute path to the repo that contains Root if this fileLoader was created from a url
|
||||||
// or the empty string otherwise.
|
// or the empty string otherwise.
|
||||||
func (fl *fileLoader) Repo() string {
|
func (fl *FileLoader) Repo() string {
|
||||||
if fl.repoSpec != nil {
|
if fl.repoSpec != nil {
|
||||||
return fl.repoSpec.Dir.String()
|
return fl.repoSpec.Dir.String()
|
||||||
}
|
}
|
||||||
@@ -132,13 +117,13 @@ func (fl *fileLoader) Repo() string {
|
|||||||
|
|
||||||
// Root returns the absolute path that is prepended to any
|
// Root returns the absolute path that is prepended to any
|
||||||
// relative paths used in Load.
|
// relative paths used in Load.
|
||||||
func (fl *fileLoader) Root() string {
|
func (fl *FileLoader) Root() string {
|
||||||
return fl.root.String()
|
return fl.root.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func newLoaderOrDie(
|
func NewLoaderOrDie(
|
||||||
lr LoadRestrictorFunc,
|
lr LoadRestrictorFunc,
|
||||||
fSys filesys.FileSystem, path string) *fileLoader {
|
fSys filesys.FileSystem, path string) *FileLoader {
|
||||||
root, err := filesys.ConfirmDir(fSys, path)
|
root, err := filesys.ConfirmDir(fSys, path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("unable to make loader at '%s'; %v", path, err)
|
log.Fatalf("unable to make loader at '%s'; %v", path, err)
|
||||||
@@ -147,12 +132,12 @@ func newLoaderOrDie(
|
|||||||
lr, root, fSys, nil, git.ClonerUsingGitExec)
|
lr, root, fSys, nil, git.ClonerUsingGitExec)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newLoaderAtConfirmedDir returns a new fileLoader with given root.
|
// newLoaderAtConfirmedDir returns a new FileLoader with given root.
|
||||||
func newLoaderAtConfirmedDir(
|
func newLoaderAtConfirmedDir(
|
||||||
lr LoadRestrictorFunc,
|
lr LoadRestrictorFunc,
|
||||||
root filesys.ConfirmedDir, fSys filesys.FileSystem,
|
root filesys.ConfirmedDir, fSys filesys.FileSystem,
|
||||||
referrer *fileLoader, cloner git.Cloner) *fileLoader {
|
referrer *FileLoader, cloner git.Cloner) *FileLoader {
|
||||||
return &fileLoader{
|
return &FileLoader{
|
||||||
loadRestrictor: lr,
|
loadRestrictor: lr,
|
||||||
root: root,
|
root: root,
|
||||||
referrer: referrer,
|
referrer: referrer,
|
||||||
@@ -164,7 +149,7 @@ func newLoaderAtConfirmedDir(
|
|||||||
|
|
||||||
// New returns a new Loader, rooted relative to current loader,
|
// New returns a new Loader, rooted relative to current loader,
|
||||||
// or rooted in a temp directory holding a git repo clone.
|
// or rooted in a temp directory holding a git repo clone.
|
||||||
func (fl *fileLoader) New(path string) (ifc.Loader, error) {
|
func (fl *FileLoader) New(path string) (ifc.Loader, error) {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
return nil, errors.Errorf("new root cannot be empty")
|
return nil, errors.Errorf("new root cannot be empty")
|
||||||
}
|
}
|
||||||
@@ -200,7 +185,7 @@ func (fl *fileLoader) New(path string) (ifc.Loader, error) {
|
|||||||
// directory holding a cloned git repo.
|
// directory holding a cloned git repo.
|
||||||
func newLoaderAtGitClone(
|
func newLoaderAtGitClone(
|
||||||
repoSpec *git.RepoSpec, fSys filesys.FileSystem,
|
repoSpec *git.RepoSpec, fSys filesys.FileSystem,
|
||||||
referrer *fileLoader, cloner git.Cloner) (ifc.Loader, error) {
|
referrer *FileLoader, cloner git.Cloner) (ifc.Loader, error) {
|
||||||
cleaner := repoSpec.Cleaner(fSys)
|
cleaner := repoSpec.Cleaner(fSys)
|
||||||
err := cloner(repoSpec)
|
err := cloner(repoSpec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -229,7 +214,7 @@ func newLoaderAtGitClone(
|
|||||||
return nil, fmt.Errorf("%q refers to directory outside of repo %q", repoSpec.AbsPath(),
|
return nil, fmt.Errorf("%q refers to directory outside of repo %q", repoSpec.AbsPath(),
|
||||||
repoSpec.CloneDir())
|
repoSpec.CloneDir())
|
||||||
}
|
}
|
||||||
return &fileLoader{
|
return &FileLoader{
|
||||||
// Clones never allowed to escape root.
|
// Clones never allowed to escape root.
|
||||||
loadRestrictor: RestrictionRootOnly,
|
loadRestrictor: RestrictionRootOnly,
|
||||||
root: root,
|
root: root,
|
||||||
@@ -241,7 +226,7 @@ func newLoaderAtGitClone(
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fl *fileLoader) errIfGitContainmentViolation(
|
func (fl *FileLoader) errIfGitContainmentViolation(
|
||||||
base filesys.ConfirmedDir) error {
|
base filesys.ConfirmedDir) error {
|
||||||
containingRepo := fl.containingRepo()
|
containingRepo := fl.containingRepo()
|
||||||
if containingRepo == nil {
|
if containingRepo == nil {
|
||||||
@@ -259,7 +244,7 @@ func (fl *fileLoader) errIfGitContainmentViolation(
|
|||||||
|
|
||||||
// Looks back through referrers for a git repo, returning nil
|
// Looks back through referrers for a git repo, returning nil
|
||||||
// if none found.
|
// if none found.
|
||||||
func (fl *fileLoader) containingRepo() *git.RepoSpec {
|
func (fl *FileLoader) containingRepo() *git.RepoSpec {
|
||||||
if fl.repoSpec != nil {
|
if fl.repoSpec != nil {
|
||||||
return fl.repoSpec
|
return fl.repoSpec
|
||||||
}
|
}
|
||||||
@@ -271,7 +256,7 @@ func (fl *fileLoader) containingRepo() *git.RepoSpec {
|
|||||||
|
|
||||||
// errIfArgEqualOrHigher tests whether the argument,
|
// errIfArgEqualOrHigher tests whether the argument,
|
||||||
// is equal to or above the root of any ancestor.
|
// is equal to or above the root of any ancestor.
|
||||||
func (fl *fileLoader) errIfArgEqualOrHigher(
|
func (fl *FileLoader) errIfArgEqualOrHigher(
|
||||||
candidateRoot filesys.ConfirmedDir) error {
|
candidateRoot filesys.ConfirmedDir) error {
|
||||||
if fl.root.HasPrefix(candidateRoot) {
|
if fl.root.HasPrefix(candidateRoot) {
|
||||||
return fmt.Errorf(
|
return fmt.Errorf(
|
||||||
@@ -288,7 +273,7 @@ func (fl *fileLoader) errIfArgEqualOrHigher(
|
|||||||
// I.e. Allow a distinction between git URI with
|
// I.e. Allow a distinction between git URI with
|
||||||
// path foo and tag bar and a git URI with the same
|
// path foo and tag bar and a git URI with the same
|
||||||
// path but a different tag?
|
// path but a different tag?
|
||||||
func (fl *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error {
|
func (fl *FileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error {
|
||||||
// TODO(monopole): Use parsed data instead of Raw().
|
// TODO(monopole): Use parsed data instead of Raw().
|
||||||
if fl.repoSpec != nil &&
|
if fl.repoSpec != nil &&
|
||||||
strings.HasPrefix(fl.repoSpec.Raw(), newRepoSpec.Raw()) {
|
strings.HasPrefix(fl.repoSpec.Raw(), newRepoSpec.Raw()) {
|
||||||
@@ -305,7 +290,7 @@ func (fl *fileLoader) errIfRepoCycle(newRepoSpec *git.RepoSpec) error {
|
|||||||
// Load returns the content of file at the given path,
|
// Load returns the content of file at the given path,
|
||||||
// else an error. Relative paths are taken relative
|
// else an error. Relative paths are taken relative
|
||||||
// to the root.
|
// to the root.
|
||||||
func (fl *fileLoader) Load(path string) ([]byte, error) {
|
func (fl *FileLoader) Load(path string) ([]byte, error) {
|
||||||
if IsRemoteFile(path) {
|
if IsRemoteFile(path) {
|
||||||
return fl.httpClientGetContent(path)
|
return fl.httpClientGetContent(path)
|
||||||
}
|
}
|
||||||
@@ -319,7 +304,7 @@ func (fl *fileLoader) Load(path string) ([]byte, error) {
|
|||||||
return fl.fSys.ReadFile(path)
|
return fl.fSys.ReadFile(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fl *fileLoader) httpClientGetContent(path string) ([]byte, error) {
|
func (fl *FileLoader) httpClientGetContent(path string) ([]byte, error) {
|
||||||
var hc *http.Client
|
var hc *http.Client
|
||||||
if fl.http != nil {
|
if fl.http != nil {
|
||||||
hc = fl.http
|
hc = fl.http
|
||||||
@@ -344,6 +329,6 @@ func (fl *fileLoader) httpClientGetContent(path string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cleanup runs the cleaner.
|
// Cleanup runs the cleaner.
|
||||||
func (fl *fileLoader) Cleanup() error {
|
func (fl *FileLoader) Cleanup() error {
|
||||||
return fl.cleaner()
|
return fl.cleaner()
|
||||||
}
|
}
|
||||||
@@ -31,6 +31,11 @@ func TestIsRemoteFile(t *testing.T) {
|
|||||||
"https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml",
|
"https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml",
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
"malformed https": {
|
||||||
|
// TODO(annasong): Maybe we want to fix this. Needs more research.
|
||||||
|
"https:/raw.githubusercontent.com/kubernetes-sigs/kustomize/master/examples/helloWorld/configMap.yaml",
|
||||||
|
true,
|
||||||
|
},
|
||||||
"https dir": {
|
"https dir": {
|
||||||
"https://github.com/kubernetes-sigs/kustomize//examples/helloWorld/",
|
"https://github.com/kubernetes-sigs/kustomize//examples/helloWorld/",
|
||||||
true,
|
true,
|
||||||
@@ -88,8 +93,9 @@ func MakeFakeFs(td []testData) filesys.FileSystem {
|
|||||||
return fSys
|
return fSys
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeLoader() *fileLoader {
|
func makeLoader() *FileLoader {
|
||||||
return NewFileLoaderAtRoot(MakeFakeFs(testCases))
|
return NewLoaderOrDie(
|
||||||
|
RestrictionRootOnly, MakeFakeFs(testCases), filesys.Separator)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLoaderLoad(t *testing.T) {
|
func TestLoaderLoad(t *testing.T) {
|
||||||
@@ -201,23 +207,44 @@ func TestNewEmptyLoader(t *testing.T) {
|
|||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewLoaderHTTP(t *testing.T) {
|
func TestNewRemoteLoaderDoesNotExist(t *testing.T) {
|
||||||
t.Run("doesn't exist", func(t *testing.T) {
|
_, err := makeLoader().New("https://example.com/org/repo")
|
||||||
_, err := makeLoader().New("https://google.com/project")
|
require.ErrorContains(t, err, "fetch")
|
||||||
require.Error(t, err)
|
}
|
||||||
})
|
|
||||||
// Though it is unlikely and we do not weigh this use case in our designs,
|
func TestLoaderLocalScheme(t *testing.T) {
|
||||||
// it is possible for a reference that is considered a remote file to
|
// It is unlikely but possible for a reference with a url scheme to
|
||||||
// actually be a directory
|
// actually refer to a local file or directory.
|
||||||
t.Run("exists", func(t *testing.T) {
|
t.Run("file", func(t *testing.T) {
|
||||||
const remoteFileLikeRoot = "https://domain"
|
|
||||||
require.True(t, IsRemoteFile(remoteFileLikeRoot))
|
|
||||||
fSys, dir := setupOnDisk(t)
|
fSys, dir := setupOnDisk(t)
|
||||||
require.NoError(t, fSys.MkdirAll(dir.Join("https:/domain")))
|
parts := []string{
|
||||||
ldr, err := newLoaderOrDie(RestrictionRootOnly,
|
"ssh:",
|
||||||
|
"resource.yaml",
|
||||||
|
}
|
||||||
|
require.NoError(t, fSys.Mkdir(dir.Join(parts[0])))
|
||||||
|
const content = "resource config"
|
||||||
|
require.NoError(t, fSys.WriteFile(
|
||||||
|
dir.Join(filepath.Join(parts...)),
|
||||||
|
[]byte(content),
|
||||||
|
))
|
||||||
|
actualContent, err := NewLoaderOrDie(RestrictionRootOnly,
|
||||||
fSys,
|
fSys,
|
||||||
dir.String(),
|
dir.String(),
|
||||||
).New(remoteFileLikeRoot)
|
).Load(strings.Join(parts, "//"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, content, string(actualContent))
|
||||||
|
})
|
||||||
|
t.Run("directory", func(t *testing.T) {
|
||||||
|
fSys, dir := setupOnDisk(t)
|
||||||
|
parts := []string{
|
||||||
|
"https:",
|
||||||
|
"root",
|
||||||
|
}
|
||||||
|
require.NoError(t, fSys.MkdirAll(dir.Join(filepath.Join(parts...))))
|
||||||
|
ldr, err := NewLoaderOrDie(RestrictionRootOnly,
|
||||||
|
fSys,
|
||||||
|
dir.String(),
|
||||||
|
).New(strings.Join(parts, "//"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Empty(t, ldr.Repo())
|
require.Empty(t, ldr.Repo())
|
||||||
})
|
})
|
||||||
@@ -296,7 +323,7 @@ func TestRestrictionRootOnlyInRealLoader(t *testing.T) {
|
|||||||
|
|
||||||
var l ifc.Loader
|
var l ifc.Loader
|
||||||
|
|
||||||
l = newLoaderOrDie(RestrictionRootOnly, fSys, dir)
|
l = NewLoaderOrDie(RestrictionRootOnly, fSys, dir)
|
||||||
|
|
||||||
l = doSanityChecksAndDropIntoBase(t, l)
|
l = doSanityChecksAndDropIntoBase(t, l)
|
||||||
|
|
||||||
@@ -317,7 +344,7 @@ func TestRestrictionNoneInRealLoader(t *testing.T) {
|
|||||||
|
|
||||||
var l ifc.Loader
|
var l ifc.Loader
|
||||||
|
|
||||||
l = newLoaderOrDie(RestrictionNone, fSys, dir)
|
l = NewLoaderOrDie(RestrictionNone, fSys, dir)
|
||||||
|
|
||||||
l = doSanityChecksAndDropIntoBase(t, l)
|
l = doSanityChecksAndDropIntoBase(t, l)
|
||||||
|
|
||||||
@@ -416,7 +443,7 @@ func TestLoaderDisallowsLocalBaseFromRemoteOverlay(t *testing.T) {
|
|||||||
|
|
||||||
// Establish that a local overlay can navigate
|
// Establish that a local overlay can navigate
|
||||||
// to the local bases.
|
// to the local bases.
|
||||||
l1 = newLoaderOrDie(
|
l1 = NewLoaderOrDie(
|
||||||
RestrictionRootOnly, fSys, cloneRoot+"/foo/overlay")
|
RestrictionRootOnly, fSys, cloneRoot+"/foo/overlay")
|
||||||
require.Equal(cloneRoot+"/foo/overlay", l1.Root())
|
require.Equal(cloneRoot+"/foo/overlay", l1.Root())
|
||||||
|
|
||||||
@@ -574,7 +601,8 @@ func TestLoaderHTTP(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
l1 := NewFileLoaderAtRoot(MakeFakeFs(testCasesFile))
|
l1 := NewLoaderOrDie(
|
||||||
|
RestrictionRootOnly, MakeFakeFs(testCasesFile), filesys.Separator)
|
||||||
require.Equal("/", l1.Root())
|
require.Equal("/", l1.Root())
|
||||||
|
|
||||||
for _, x := range testCasesFile {
|
for _, x := range testCasesFile {
|
||||||
@@ -635,6 +663,8 @@ func TestLoaderHTTP(t *testing.T) {
|
|||||||
|
|
||||||
// setupOnDisk sets up a file system on disk and directory that is cleaned after
|
// setupOnDisk sets up a file system on disk and directory that is cleaned after
|
||||||
// test completion.
|
// test completion.
|
||||||
|
// TODO(annasong): Move all loader tests that require real file system into
|
||||||
|
// api/krusty.
|
||||||
func setupOnDisk(t *testing.T) (filesys.FileSystem, filesys.ConfirmedDir) {
|
func setupOnDisk(t *testing.T) (filesys.FileSystem, filesys.ConfirmedDir) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
"sigs.k8s.io/kustomize/api/internal/generators"
|
"sigs.k8s.io/kustomize/api/internal/generators"
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
"sigs.k8s.io/kustomize/api/internal/target"
|
"sigs.k8s.io/kustomize/api/internal/target"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/provider"
|
"sigs.k8s.io/kustomize/api/provider"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
"sigs.k8s.io/kustomize/api/internal/git"
|
"sigs.k8s.io/kustomize/api/internal/git"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
"sigs.k8s.io/kustomize/kyaml/resid"
|
"sigs.k8s.io/kustomize/kyaml/resid"
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
|
"sigs.k8s.io/kustomize/api/internal/konfig/builtinpluginconsts"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
"sigs.k8s.io/kustomize/kyaml/errors"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
fLdr "sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
. "sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
|
. "sigs.k8s.io/kustomize/api/internal/plugins/execplugin"
|
||||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
|
"sigs.k8s.io/kustomize/api/internal/plugins/utils"
|
||||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/provider"
|
"sigs.k8s.io/kustomize/api/provider"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
. "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
. "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/provider"
|
"sigs.k8s.io/kustomize/api/provider"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||||
|
|||||||
@@ -13,12 +13,12 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/api/internal/accumulator"
|
"sigs.k8s.io/kustomize/api/internal/accumulator"
|
||||||
"sigs.k8s.io/kustomize/api/internal/builtins"
|
"sigs.k8s.io/kustomize/api/internal/builtins"
|
||||||
"sigs.k8s.io/kustomize/api/internal/kusterr"
|
"sigs.k8s.io/kustomize/api/internal/kusterr"
|
||||||
|
load "sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
"sigs.k8s.io/kustomize/api/internal/plugins/builtinconfig"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
|
"sigs.k8s.io/kustomize/api/internal/plugins/builtinhelpers"
|
||||||
"sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
"sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||||
"sigs.k8s.io/kustomize/api/internal/utils"
|
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||||
"sigs.k8s.io/kustomize/api/konfig"
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
load "sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
. "sigs.k8s.io/kustomize/api/internal/target"
|
. "sigs.k8s.io/kustomize/api/internal/target"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
"sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
"sigs.k8s.io/kustomize/api/provider"
|
"sigs.k8s.io/kustomize/api/provider"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ package target_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
fLdr "sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||||
"sigs.k8s.io/kustomize/api/internal/target"
|
"sigs.k8s.io/kustomize/api/internal/target"
|
||||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/provider"
|
"sigs.k8s.io/kustomize/api/provider"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||||
|
|||||||
@@ -17,6 +17,18 @@ import (
|
|||||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const validResource = `
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Service
|
||||||
|
metadata:
|
||||||
|
name: myService
|
||||||
|
spec:
|
||||||
|
selector:
|
||||||
|
backend: bungie
|
||||||
|
ports:
|
||||||
|
- port: 7002
|
||||||
|
`
|
||||||
|
|
||||||
func TestTargetMustHaveKustomizationFile(t *testing.T) {
|
func TestTargetMustHaveKustomizationFile(t *testing.T) {
|
||||||
th := kusttest_test.MakeHarness(t)
|
th := kusttest_test.MakeHarness(t)
|
||||||
th.WriteF("service.yaml", `
|
th.WriteF("service.yaml", `
|
||||||
@@ -63,17 +75,7 @@ func TestBaseMustHaveKustomizationFile(t *testing.T) {
|
|||||||
resources:
|
resources:
|
||||||
- base
|
- base
|
||||||
`)
|
`)
|
||||||
th.WriteF("base/service.yaml", `
|
th.WriteF("base/service.yaml", validResource)
|
||||||
apiVersion: v1
|
|
||||||
kind: Service
|
|
||||||
metadata:
|
|
||||||
name: myService
|
|
||||||
spec:
|
|
||||||
selector:
|
|
||||||
backend: bungie
|
|
||||||
ports:
|
|
||||||
- port: 7002
|
|
||||||
`)
|
|
||||||
err := th.RunWithErr(".", th.MakeDefaultOptions())
|
err := th.RunWithErr(".", th.MakeDefaultOptions())
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Fatalf("expected an error")
|
t.Fatalf("expected an error")
|
||||||
@@ -167,12 +169,35 @@ spec:
|
|||||||
|
|
||||||
func TestAccumulateResourcesErrors(t *testing.T) {
|
func TestAccumulateResourcesErrors(t *testing.T) {
|
||||||
type testcase struct {
|
type testcase struct {
|
||||||
name string
|
name string
|
||||||
resource string
|
resource string
|
||||||
// regex error message that is output when kustomize tries to
|
isAbsolute bool
|
||||||
// accumulate resource as file and dir, respectively
|
files map[string]string
|
||||||
|
// errFile, errDir are regex for the expected error message output
|
||||||
|
// when kustomize tries to accumulate resource as file and dir,
|
||||||
|
// respectively. The test substitutes occurrences of "%s" in the
|
||||||
|
// error strings with the absolute path where kustomize looks for it.
|
||||||
errFile, errDir string
|
errFile, errDir string
|
||||||
}
|
}
|
||||||
|
populateAbsolutePaths := func(tc testcase, dir string) testcase {
|
||||||
|
filePaths := make(map[string]string, len(tc.files)+1)
|
||||||
|
for file, content := range tc.files {
|
||||||
|
filePaths[filepath.Join(dir, file)] = content
|
||||||
|
}
|
||||||
|
resourcePath := filepath.Join(dir, tc.resource)
|
||||||
|
if tc.isAbsolute {
|
||||||
|
tc.resource = resourcePath
|
||||||
|
}
|
||||||
|
filePaths[filepath.Join(dir, "kustomization.yaml")] = fmt.Sprintf(`
|
||||||
|
resources:
|
||||||
|
- %s
|
||||||
|
`, tc.resource)
|
||||||
|
tc.files = filePaths
|
||||||
|
regPath := regexp.QuoteMeta(resourcePath)
|
||||||
|
tc.errFile = strings.ReplaceAll(tc.errFile, "%s", regPath)
|
||||||
|
tc.errDir = strings.ReplaceAll(tc.errDir, "%s", regPath)
|
||||||
|
return tc
|
||||||
|
}
|
||||||
buildError := func(tc testcase) string {
|
buildError := func(tc testcase) string {
|
||||||
const (
|
const (
|
||||||
prefix = "accumulating resources"
|
prefix = "accumulating resources"
|
||||||
@@ -196,39 +221,89 @@ func TestAccumulateResourcesErrors(t *testing.T) {
|
|||||||
for _, test := range []testcase{
|
for _, test := range []testcase{
|
||||||
{
|
{
|
||||||
name: "remote file not considered repo",
|
name: "remote file not considered repo",
|
||||||
// This url is too short to be considered a remote repo.
|
// The example.com second-level domain is reserved and
|
||||||
resource: "https://raw.githubusercontent.com/kustomize",
|
// safe to access, see RFC 2606.
|
||||||
// It is acceptable that the error for a remote file-like reference
|
resource: "https://example.com/segments-too-few-to-be-repo",
|
||||||
// (that is not long enough to be considered a repo) does not
|
// It's acceptable for the error output of a remote file-like
|
||||||
// indicate said reference is not a local directory.
|
// resource to not indicate the resource's status as a
|
||||||
// Though it is possible for the remote file-like reference to be
|
// local directory. Though it is possible for a remote file-like
|
||||||
// a local directory, it is very unlikely.
|
// resource to be a local directory, it is very unlikely.
|
||||||
errFile: `HTTP Error: status code 400 \(Bad Request\)\z`,
|
errFile: `HTTP Error: status code 404 \(Not Found\)\z`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "remote file qualifies as repo",
|
name: "remote file qualifies as repo",
|
||||||
resource: "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/kustomize/v5.0.0/examples/helloWorld/configMap",
|
resource: "https://example.com/long/enough/to/have/org/and/repo",
|
||||||
// TODO(4788): This error message is technically wrong. Just
|
// TODO(4788): This error message is technically wrong. Just
|
||||||
// because we fail to GET a reference does not mean the reference is
|
// because we fail to GET a resource does not mean the resource is
|
||||||
// not a remote file. We should return the GET status code instead.
|
// not a remote file. We should return the GET status code as well.
|
||||||
errFile: "URL is a git repository",
|
errFile: "URL is a git repository",
|
||||||
errDir: `failed to run \S+/git fetch --depth=1 .+`,
|
errDir: `failed to run \S+/git fetch --depth=1 .+`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "local file qualifies as repo",
|
||||||
|
// The .example top level domain is reserved for example purposes,
|
||||||
|
// see RFC 2606.
|
||||||
|
resource: "package@v1.28.0.example/configs/base",
|
||||||
|
errFile: `evalsymlink failure on '%s' .+`,
|
||||||
|
errDir: `failed to run \S+/git fetch --depth=1 .+`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "relative path does not exist",
|
||||||
|
resource: "file-or-directory",
|
||||||
|
errFile: `evalsymlink failure on '%s' .+`,
|
||||||
|
errDir: `must build at directory: not a valid directory: evalsymlink failure .+`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "absolute path does not exist",
|
||||||
|
resource: "file-or-directory",
|
||||||
|
isAbsolute: true,
|
||||||
|
errFile: `evalsymlink failure on '%s' .+`,
|
||||||
|
errDir: `new root '%s' cannot be absolute`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "relative file violates restrictions",
|
||||||
|
resource: "../base/resource.yaml",
|
||||||
|
files: map[string]string{
|
||||||
|
"../base/resource.yaml": validResource,
|
||||||
|
},
|
||||||
|
errFile: "security; file '%s' is not in or below .+",
|
||||||
|
// TODO(4348): Over-inclusion of directory error message when we
|
||||||
|
// know resource is file.
|
||||||
|
errDir: "must build at directory: '%s': file is not directory",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "absolute file violates restrictions",
|
||||||
|
resource: "../base/resource.yaml",
|
||||||
|
isAbsolute: true,
|
||||||
|
files: map[string]string{
|
||||||
|
"../base/resource.yaml": validResource,
|
||||||
|
},
|
||||||
|
errFile: "security; file '%s' is not in or below .+",
|
||||||
|
// TODO(4348): Over-inclusion of directory error message when we
|
||||||
|
// know resource is file.
|
||||||
|
errDir: `new root '%s' cannot be absolute`,
|
||||||
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
// should use real file system to indicate that we are creating
|
// Should use real file system to indicate that we are creating
|
||||||
// new temporary directories on disk when we attempt to fetch repos
|
// new temporary directories on disk when we attempt to fetch repos.
|
||||||
fSys, tmpDir := kusttest_test.CreateKustDir(t, fmt.Sprintf(`
|
fs, tmpDir := kusttest_test.Setup(t)
|
||||||
resources:
|
root := tmpDir.Join("root")
|
||||||
- %s
|
require.NoError(t, fs.Mkdir(root))
|
||||||
`, test.resource))
|
|
||||||
|
test = populateAbsolutePaths(test, root)
|
||||||
|
for file, content := range test.files {
|
||||||
|
dir := filepath.Dir(file)
|
||||||
|
require.NoError(t, fs.MkdirAll(dir))
|
||||||
|
require.NoError(t, fs.WriteFile(file, []byte(content)))
|
||||||
|
}
|
||||||
|
|
||||||
b := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
|
b := krusty.MakeKustomizer(krusty.MakeDefaultOptions())
|
||||||
_, err := b.Run(fSys, tmpDir.String())
|
_, err := b.Run(fs, root)
|
||||||
require.Regexp(t, buildError(test), err.Error())
|
require.Regexp(t, buildError(test), err.Error())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// TODO(annasong): add tests that check accumulateResources errors for
|
// TODO(annasong): add tests that check accumulateResources errors for
|
||||||
// - local files
|
|
||||||
// - repos
|
// - repos
|
||||||
// - local directories
|
// - local directories
|
||||||
// - files that yield malformed yaml errors
|
// - files that yield malformed yaml errors
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
"sigs.k8s.io/kustomize/api/konfig"
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
|
||||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -8,11 +8,11 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/internal/builtins"
|
"sigs.k8s.io/kustomize/api/internal/builtins"
|
||||||
|
fLdr "sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||||
"sigs.k8s.io/kustomize/api/internal/target"
|
"sigs.k8s.io/kustomize/api/internal/target"
|
||||||
"sigs.k8s.io/kustomize/api/internal/utils"
|
"sigs.k8s.io/kustomize/api/internal/utils"
|
||||||
"sigs.k8s.io/kustomize/api/konfig"
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/provenance"
|
"sigs.k8s.io/kustomize/api/provenance"
|
||||||
"sigs.k8s.io/kustomize/api/provider"
|
"sigs.k8s.io/kustomize/api/provider"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ package krusty_test
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
|
|
||||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -303,20 +301,15 @@ patchesStrategicMerge:
|
|||||||
m = th.Run("overlay", th.MakeDefaultOptions())
|
m = th.Run("overlay", th.MakeDefaultOptions())
|
||||||
th.AssertActualEqualsExpected(m, expected)
|
th.AssertActualEqualsExpected(m, expected)
|
||||||
|
|
||||||
// Technique 4: "patches:" field, one patch file. Fails.
|
// Technique 4: "patches:" field, one patch file.
|
||||||
th.WriteK("overlay", `
|
th.WriteK("overlay", `
|
||||||
resources:
|
resources:
|
||||||
- ../base
|
- ../base
|
||||||
patches:
|
patches:
|
||||||
- path: twoPatchesInOneFile.yaml
|
- path: twoPatchesInOneFile.yaml
|
||||||
`)
|
`)
|
||||||
err := th.RunWithErr("overlay", th.MakeDefaultOptions())
|
m = th.Run("overlay", th.MakeDefaultOptions())
|
||||||
assert.Error(t, err)
|
th.AssertActualEqualsExpected(m, expected)
|
||||||
// This should fail, because the semantics of the `patches` field.
|
|
||||||
// That field allows specific patch targeting to a list of targets,
|
|
||||||
// while the `patchesStrategicMerge` field accepts patches that
|
|
||||||
// implicitly identify their targets via GVKN.
|
|
||||||
assert.Contains(t, err.Error(), "unable to parse SM or JSON patch from ")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRemoveEmptyDirWithNullFieldInSmp(t *testing.T) {
|
func TestRemoveEmptyDirWithNullFieldInSmp(t *testing.T) {
|
||||||
@@ -1670,7 +1663,7 @@ spec:
|
|||||||
template:
|
template:
|
||||||
spec:
|
spec:
|
||||||
containers:
|
containers:
|
||||||
- image: fluentd:latest
|
- image: fluentd:latest
|
||||||
name: fluentd
|
name: fluentd
|
||||||
serviceAccountName: fluentd-sa
|
serviceAccountName: fluentd-sa
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
"sigs.k8s.io/kustomize/api/krusty"
|
"sigs.k8s.io/kustomize/api/krusty"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
kusttest_test "sigs.k8s.io/kustomize/api/testutils/kusttest"
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
@@ -27,6 +28,7 @@ func TestRemoteLoad_LocalProtocol(t *testing.T) {
|
|||||||
root string
|
root string
|
||||||
simple string
|
simple string
|
||||||
noSuffix string
|
noSuffix string
|
||||||
|
hash string
|
||||||
multiBaseDev string
|
multiBaseDev string
|
||||||
withSubmodule string
|
withSubmodule string
|
||||||
}
|
}
|
||||||
@@ -35,9 +37,10 @@ func TestRemoteLoad_LocalProtocol(t *testing.T) {
|
|||||||
// root/
|
// root/
|
||||||
// simple.git/ - base with just a pod
|
// simple.git/ - base with just a pod
|
||||||
// nosuffix/ - same as simple.git/ without the .git suffix
|
// nosuffix/ - same as simple.git/ without the .git suffix
|
||||||
|
// hash-xx/ - same as simple.git/ with random hash at xx
|
||||||
// multibase.git/ - base with a dev overlay
|
// multibase.git/ - base with a dev overlay
|
||||||
// with-submodule.git/ - includes `simple` as a submodule
|
// with-submodule.git/ - includes `simple` as a submodule
|
||||||
// submodule/ - the submodule referencing `simple
|
// submodule/ - the submodule referencing `simple`
|
||||||
createGitRepos := func(t *testing.T) testRepos {
|
createGitRepos := func(t *testing.T) testRepos {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
@@ -49,10 +52,16 @@ func TestRemoteLoad_LocalProtocol(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
|
|
||||||
|
hashPath, err := os.MkdirTemp(root, "hash-")
|
||||||
|
require.NoError(t, err)
|
||||||
|
hashDir := filepath.Base(hashPath)
|
||||||
|
|
||||||
bash(fmt.Sprintf(`
|
bash(fmt.Sprintf(`
|
||||||
set -eux
|
set -eux
|
||||||
|
|
||||||
export ROOT="%s"
|
export ROOT="%s"
|
||||||
|
export HASH_DIR="%s"
|
||||||
export GIT_AUTHOR_EMAIL=nobody@kustomize.io
|
export GIT_AUTHOR_EMAIL=nobody@kustomize.io
|
||||||
export GIT_AUTHOR_NAME=Nobody
|
export GIT_AUTHOR_NAME=Nobody
|
||||||
export GIT_COMMITTER_EMAIL=nobody@kustomize.io
|
export GIT_COMMITTER_EMAIL=nobody@kustomize.io
|
||||||
@@ -84,19 +93,27 @@ cp -r testdata/remoteload/multibase $ROOT/multibase.git
|
|||||||
git add .
|
git add .
|
||||||
git commit -m "import"
|
git commit -m "import"
|
||||||
)
|
)
|
||||||
|
cp -r testdata/remoteload/with-submodule $ROOT/with-submodule.git # see README
|
||||||
|
cp -r $ROOT/simple.git/. $ROOT/$HASH_DIR
|
||||||
(
|
(
|
||||||
mkdir $ROOT/with-submodule.git
|
|
||||||
cd $ROOT/with-submodule.git
|
cd $ROOT/with-submodule.git
|
||||||
git init --initial-branch=main
|
git init --initial-branch=main
|
||||||
git submodule add $ROOT/simple.git submodule
|
git add .
|
||||||
git commit -m "import"
|
git commit -m "import"
|
||||||
|
git checkout -b relative-submodule
|
||||||
|
git submodule add ../$HASH_DIR submodule
|
||||||
|
git commit -m "relative submodule"
|
||||||
|
git checkout main
|
||||||
|
git submodule add $ROOT/simple.git submodule
|
||||||
|
git commit -m "submodule"
|
||||||
)
|
)
|
||||||
`, root))
|
`, root, hashDir))
|
||||||
return testRepos{
|
return testRepos{
|
||||||
root: root,
|
root: root,
|
||||||
// The strings below aren't currently used, and more serve as documentation.
|
// The strings below aren't currently used, and more serve as documentation.
|
||||||
simple: "simple.git",
|
simple: "simple.git",
|
||||||
noSuffix: "nosuffix",
|
noSuffix: "nosuffix",
|
||||||
|
hash: hashDir,
|
||||||
multiBaseDev: "multibase.git",
|
multiBaseDev: "multibase.git",
|
||||||
withSubmodule: "with-submodule.git",
|
withSubmodule: "with-submodule.git",
|
||||||
}
|
}
|
||||||
@@ -182,6 +199,15 @@ resources:
|
|||||||
`,
|
`,
|
||||||
expected: simpleBuild,
|
expected: simpleBuild,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "has relative submodule",
|
||||||
|
kustomization: `
|
||||||
|
resources:
|
||||||
|
- file://$ROOT/with-submodule.git/submodule?ref=relative-submodule
|
||||||
|
`,
|
||||||
|
// TODO(annasong): Replace with simpleBuild once #5131 is fixed.
|
||||||
|
err: `failed to run '\S+/git submodule update --init --recursive'`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "has timeout",
|
name: "has timeout",
|
||||||
kustomization: `
|
kustomization: `
|
||||||
@@ -272,7 +298,7 @@ resources:
|
|||||||
|
|
||||||
if test.err != "" {
|
if test.err != "" {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
require.Contains(t, err.Error(), test.err)
|
require.Regexp(t, test.err, err.Error())
|
||||||
} else {
|
} else {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
checkYaml(t, m, strings.ReplaceAll(test.expected, "$ROOT", repos.root))
|
checkYaml(t, m, strings.ReplaceAll(test.expected, "$ROOT", repos.root))
|
||||||
|
|||||||
@@ -546,3 +546,71 @@ metadata:
|
|||||||
name: red-dc6gc5btkc
|
name: red-dc6gc5btkc
|
||||||
`)
|
`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReplacementTransformerWithSuffixTransformerAndReject(t *testing.T) {
|
||||||
|
th := kusttest_test.MakeEnhancedHarness(t)
|
||||||
|
defer th.Reset()
|
||||||
|
|
||||||
|
th.WriteF("base/app.yaml", `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: original-name
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: app1:1.0
|
||||||
|
name: app
|
||||||
|
`)
|
||||||
|
th.WriteK("base", `
|
||||||
|
resources:
|
||||||
|
- app.yaml
|
||||||
|
`)
|
||||||
|
th.WriteK("overlay", `
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
|
||||||
|
nameSuffix: -dev
|
||||||
|
resources:
|
||||||
|
- ../base
|
||||||
|
|
||||||
|
configMapGenerator:
|
||||||
|
- name: app-config
|
||||||
|
literals:
|
||||||
|
- name=something-else
|
||||||
|
|
||||||
|
replacements:
|
||||||
|
- source:
|
||||||
|
kind: ConfigMap
|
||||||
|
name: app-config
|
||||||
|
fieldPath: data.name
|
||||||
|
targets:
|
||||||
|
- fieldPaths:
|
||||||
|
- spec.template.spec.containers.0.name
|
||||||
|
select:
|
||||||
|
kind: Deployment
|
||||||
|
reject:
|
||||||
|
- name: original-name
|
||||||
|
`)
|
||||||
|
m := th.Run("overlay", th.MakeDefaultOptions())
|
||||||
|
th.AssertActualEqualsExpected(m, `
|
||||||
|
apiVersion: apps/v1
|
||||||
|
kind: Deployment
|
||||||
|
metadata:
|
||||||
|
name: original-name-dev
|
||||||
|
spec:
|
||||||
|
template:
|
||||||
|
spec:
|
||||||
|
containers:
|
||||||
|
- image: app1:1.0
|
||||||
|
name: app
|
||||||
|
---
|
||||||
|
apiVersion: v1
|
||||||
|
data:
|
||||||
|
name: something-else
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: app-config-dev-97544dk6t8
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
|||||||
10
api/krusty/testdata/remoteload/with-submodule/README.md
vendored
Normal file
10
api/krusty/testdata/remoteload/with-submodule/README.md
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# submodule
|
||||||
|
|
||||||
|
This repo demonstrates kustomize's ability to download git repos
|
||||||
|
with submodules. The following branches contain
|
||||||
|
* main: submodule via absolute path
|
||||||
|
* relative-submodule: submodule via relative path
|
||||||
|
|
||||||
|
For the submodule accessed via a relative path, we include a random hash in the
|
||||||
|
submodule name to avoid accessing an unintended directory in the case kustomize
|
||||||
|
contains loader bugs (issue #5131).
|
||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
ldr "sigs.k8s.io/kustomize/api/loader"
|
ldr "sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
|||||||
24
api/pkg/loader/loader.go
Normal file
24
api/pkg/loader/loader.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright 2023 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
// Package pkg has all the helpers to interact with the api.
|
||||||
|
package loader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewFileLoaderAtCwd returns a loader that loads from PWD.
|
||||||
|
// A convenience for kustomize edit commands.
|
||||||
|
func NewFileLoaderAtCwd(fSys filesys.FileSystem) *loader.FileLoader {
|
||||||
|
return loader.NewLoaderOrDie(
|
||||||
|
loader.RestrictionRootOnly, fSys, filesys.SelfDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFileLoaderAtRoot returns a loader that loads from "/".
|
||||||
|
// A convenience for tests.
|
||||||
|
func NewFileLoaderAtRoot(fSys filesys.FileSystem) *loader.FileLoader {
|
||||||
|
return loader.NewLoaderOrDie(
|
||||||
|
loader.RestrictionRootOnly, fSys, filesys.Separator)
|
||||||
|
}
|
||||||
@@ -9,8 +9,9 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
|
loader "sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
"sigs.k8s.io/kustomize/api/kv"
|
"sigs.k8s.io/kustomize/api/kv"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
ldrpkg "sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
. "sigs.k8s.io/kustomize/api/resmap"
|
. "sigs.k8s.io/kustomize/api/resmap"
|
||||||
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
|
resmaptest_test "sigs.k8s.io/kustomize/api/testutils/resmaptest"
|
||||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||||
@@ -249,7 +250,7 @@ func TestNewResMapFromSecretArgs(t *testing.T) {
|
|||||||
|
|
||||||
actual, err := rmF.NewResMapFromSecretArgs(
|
actual, err := rmF.NewResMapFromSecretArgs(
|
||||||
kv.NewLoader(
|
kv.NewLoader(
|
||||||
loader.NewFileLoaderAtRoot(fSys),
|
ldrpkg.NewFileLoaderAtRoot(fSys),
|
||||||
valtest_test.MakeFakeValidator()), secrets)
|
valtest_test.MakeFakeValidator()), secrets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("unexpected error: %v", err)
|
t.Fatalf("unexpected error: %v", err)
|
||||||
|
|||||||
@@ -696,8 +696,7 @@ func (m *resWrangler) DeAnchor() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ApplySmPatch applies the patch, and errors on Id collisions.
|
// ApplySmPatch applies the patch, and errors on Id collisions.
|
||||||
func (m *resWrangler) ApplySmPatch(
|
func (m *resWrangler) ApplySmPatch(selectedSet *resource.IdSet, patch *resource.Resource) error {
|
||||||
selectedSet *resource.IdSet, patch *resource.Resource) error {
|
|
||||||
var list []*resource.Resource
|
var list []*resource.Resource
|
||||||
for _, res := range m.rList {
|
for _, res := range m.rList {
|
||||||
if selectedSet.Contains(res.CurId()) {
|
if selectedSet.Contains(res.CurId()) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
"sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
. "sigs.k8s.io/kustomize/api/resource"
|
. "sigs.k8s.io/kustomize/api/resource"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"sigs.k8s.io/kustomize/api/internal/konfig/builtinpluginconsts"
|
||||||
"sigs.k8s.io/kustomize/api/konfig"
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
"sigs.k8s.io/kustomize/api/konfig/builtinpluginconsts"
|
|
||||||
"sigs.k8s.io/kustomize/api/krusty"
|
"sigs.k8s.io/kustomize/api/krusty"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
|
fLdr "sigs.k8s.io/kustomize/api/internal/loader"
|
||||||
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
pLdr "sigs.k8s.io/kustomize/api/internal/plugins/loader"
|
||||||
"sigs.k8s.io/kustomize/api/konfig"
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
fLdr "sigs.k8s.io/kustomize/api/loader"
|
|
||||||
"sigs.k8s.io/kustomize/api/provider"
|
"sigs.k8s.io/kustomize/api/provider"
|
||||||
"sigs.k8s.io/kustomize/api/resmap"
|
"sigs.k8s.io/kustomize/api/resmap"
|
||||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||||
|
|||||||
@@ -11,19 +11,27 @@ import (
|
|||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Setup sets up a file system on disk and directory that is cleaned after
|
||||||
|
// test completion.
|
||||||
|
func Setup(t *testing.T) (filesys.FileSystem, filesys.ConfirmedDir) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
fSys := filesys.MakeFsOnDisk()
|
||||||
|
dir, err := filesys.NewTmpConfirmedDir()
|
||||||
|
require.NoError(t, err)
|
||||||
|
t.Cleanup(func() {
|
||||||
|
_ = fSys.RemoveAll(dir.String())
|
||||||
|
})
|
||||||
|
return fSys, dir
|
||||||
|
}
|
||||||
|
|
||||||
// CreateKustDir creates a file system on disk and a new directory
|
// CreateKustDir creates a file system on disk and a new directory
|
||||||
// that holds a kustomization file with content. The directory is removed on
|
// that holds a kustomization file with content. The directory is removed on
|
||||||
// test completion.
|
// test completion.
|
||||||
func CreateKustDir(t *testing.T, content string) (filesys.FileSystem, filesys.ConfirmedDir) {
|
func CreateKustDir(t *testing.T, content string) (filesys.FileSystem, filesys.ConfirmedDir) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
fSys := filesys.MakeFsOnDisk()
|
fSys, tmpDir := Setup(t)
|
||||||
tmpDir, err := filesys.NewTmpConfirmedDir()
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(content)))
|
require.NoError(t, fSys.WriteFile(filepath.Join(tmpDir.String(), "kustomization.yaml"), []byte(content)))
|
||||||
|
|
||||||
t.Cleanup(func() {
|
|
||||||
require.NoError(t, fSys.RemoveAll(tmpDir.String()))
|
|
||||||
})
|
|
||||||
return fSys, tmpDir
|
return fSys, tmpDir
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,3 +35,5 @@ require (
|
|||||||
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961 // indirect
|
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961 // indirect
|
||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
replace sigs.k8s.io/kustomize/kyaml => ../../kyaml
|
||||||
|
|||||||
@@ -87,7 +87,5 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|||||||
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961 h1:pqRVJGQJz6oeZby8qmPKXYIBjyrcv7EHCe/33UkZMYA=
|
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961 h1:pqRVJGQJz6oeZby8qmPKXYIBjyrcv7EHCe/33UkZMYA=
|
||||||
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961/go.mod h1:l8HTwL5fqnlns4jOveW1L75eo7R9KFHxiE0bsPGy428=
|
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961/go.mod h1:l8HTwL5fqnlns4jOveW1L75eo7R9KFHxiE0bsPGy428=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3 h1:WpabVAKZe2YEp/irTSHwD6bfjwZnTtSDewd2BVJGMZs=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3/go.mod h1:npvh9epWysfQ689Rtt/U+dpOJDTBn8kUnF1O6VzvmZA=
|
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ go 1.20
|
|||||||
require (
|
require (
|
||||||
github.com/spf13/cobra v1.7.0
|
github.com/spf13/cobra v1.7.0
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.1
|
||||||
sigs.k8s.io/kustomize/api v0.13.4
|
sigs.k8s.io/kustomize/api v0.14.0
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3
|
sigs.k8s.io/kustomize/kyaml v0.14.3
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -37,3 +37,5 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
replace sigs.k8s.io/kustomize/api => ../../api
|
replace sigs.k8s.io/kustomize/api => ../../api
|
||||||
|
|
||||||
|
replace sigs.k8s.io/kustomize/kyaml => ../../kyaml
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
@@ -73,6 +72,7 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/evanphx/json-patch.v5 v5.6.0 h1:BMT6KIwBD9CaU91PJCZIe46bDmBWa9ynTQgJIOpfQBk=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
@@ -83,7 +83,5 @@ k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961/go.mod h1:l8HTwL5fqnlns4j
|
|||||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
|
k8s.io/utils v0.0.0-20230505201702-9f6742963106 h1:EObNQ3TW2D+WptiYXlApGNLVy0zm/JIBVY9i+M4wpAU=
|
||||||
k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20230505201702-9f6742963106/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3 h1:WpabVAKZe2YEp/irTSHwD6bfjwZnTtSDewd2BVJGMZs=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3/go.mod h1:npvh9epWysfQ689Rtt/U+dpOJDTBn8kUnF1O6VzvmZA=
|
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
|
|||||||
32
go.work.sum
32
go.work.sum
@@ -5,43 +5,57 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
|
|||||||
github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk=
|
github.com/dustmop/soup v1.1.2-0.20190516214245-38228baa104e/go.mod h1:CgNC6SGbT+Xb8wGGvzilttZL1mc5sQ/5KkcxsZttMIk=
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
github.com/evanphx/json-patch v5.6.0+incompatible h1:jBYDEEiFBPxA0v50tFdvOzQQTCvpL6mnFh5mB2/l16U=
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
||||||
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
|
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||||
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
|
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
||||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||||
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU=
|
||||||
github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
|
github.com/onsi/ginkgo/v2 v2.9.1/go.mod h1:FEcmzVcCHl+4o9bQZVab+4dC9+j+91t2FHSzmGAPfuo=
|
||||||
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
|
||||||
github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
|
github.com/onsi/gomega v1.27.3/go.mod h1:5vG284IBtfDAmDyrK+eGyZmUgUlmi+Wngqo557cZ6Gw=
|
||||||
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
|
github.com/onsi/gomega v1.27.4/go.mod h1:riYq/GJKh8hhoM01HN6Vmuy93AarCXCBGpvFDK3q3fQ=
|
||||||
|
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
|
||||||
|
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
||||||
|
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
|
||||||
|
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
|
||||||
|
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
|
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY=
|
go.starlark.net v0.0.0-20190528202925-30ae18b8564f/go.mod h1:c1/X6cHgvdXj6pUlmWKMkuqRnW4K8x2vwt6JAaaircg=
|
||||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0 h1:hb9wdF1z5waM+dSIICn1l0DkLVDT3hqhhQsDNUmHPRE=
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
|
||||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
|
||||||
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
|
||||||
k8s.io/klog/v2 v2.80.1/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20230501164219-8b0f38b5fd1f/go.mod h1:byini6yhqGC14c3ebc/QwanvYwhuMWF6yz2F8uwW8eg=
|
|
||||||
k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
|
||||||
sigs.k8s.io/kustomize/cmd/config v0.11.3/go.mod h1:ENTZ8Ds12gewUpdxF5PJq/9qPVQFd5VPvMIL11wrBIU=
|
|
||||||
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=
|
sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
KUSTOMIZE_EXEC=kustomize
|
KUSTOMIZE_EXEC=kustomize
|
||||||
KUSTOMIZE_FLAGS="build --enable_alpha_plugins --enable-exec"
|
KUSTOMIZE_FLAGS="build --enable-exec --enable-alpha-plugins"
|
||||||
|
|
||||||
function build_label_namespace_exec {
|
function build_label_namespace_exec {
|
||||||
cd label_namespace/execfn
|
cd label_namespace/execfn
|
||||||
|
|||||||
@@ -5,7 +5,8 @@ FROM alpine:latest
|
|||||||
|
|
||||||
ENV BUILD_HOME=/usr/local/build
|
ENV BUILD_HOME=/usr/local/build
|
||||||
RUN apk update && apk add --no-cache git nodejs npm
|
RUN apk update && apk add --no-cache git nodejs npm
|
||||||
RUN npm install -g typescript
|
COPY ["./package.json", "./package-lock.json", "./"]
|
||||||
|
RUN npm install -g
|
||||||
|
|
||||||
RUN mkdir -p $BUILD_HOME
|
RUN mkdir -p $BUILD_HOME
|
||||||
|
|
||||||
|
|||||||
16
hack/krmFunctionBenchmark/label_namespace/execfn/package-lock.json
generated
Normal file
16
hack/krmFunctionBenchmark/label_namespace/execfn/package-lock.json
generated
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"requires": true,
|
||||||
|
"lockfileVersion": 1,
|
||||||
|
"dependencies": {
|
||||||
|
"help": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/help/-/help-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-jDd0MU+9xzvOQRC6CIzdjvb+agCvpzQY/Fp11quDnugDO4QQzh134EsLkRQMvFIJBleFkvnXagHFm4MTefkkpA=="
|
||||||
|
},
|
||||||
|
"typescript": {
|
||||||
|
"version": "5.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz",
|
||||||
|
"integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "execfn",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC"
|
||||||
|
}
|
||||||
BIN
images/base.jpg
BIN
images/base.jpg
Binary file not shown.
|
Before Width: | Height: | Size: 40 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 73 KiB |
@@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"sigs.k8s.io/kustomize/api/konfig"
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
ldrhelper "sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
||||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
|
||||||
@@ -61,7 +61,7 @@ func NewCmdCreate(fSys filesys.FileSystem, rf *resource.Factory) *cobra.Command
|
|||||||
&opts.namespace,
|
&opts.namespace,
|
||||||
"namespace",
|
"namespace",
|
||||||
"",
|
"",
|
||||||
"Set the value of the namespace field in the customization file.")
|
"Set the value of the namespace field in the kustomization file.")
|
||||||
c.Flags().StringVar(
|
c.Flags().StringVar(
|
||||||
&opts.annotations,
|
&opts.annotations,
|
||||||
"annotations",
|
"annotations",
|
||||||
@@ -99,7 +99,7 @@ func runCreate(opts createFlags, fSys filesys.FileSystem, rf *resource.Factory)
|
|||||||
var resources []string
|
var resources []string
|
||||||
var err error
|
var err error
|
||||||
if opts.resources != "" {
|
if opts.resources != "" {
|
||||||
resources, err = util.GlobPatternsWithLoader(fSys, loader.NewFileLoaderAtCwd(fSys), strings.Split(opts.resources, ","))
|
resources, err = util.GlobPatternsWithLoader(fSys, ldrhelper.NewFileLoaderAtCwd(fSys), strings.Split(opts.resources, ","))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
"sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
||||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
|||||||
@@ -34,10 +34,11 @@ func (k kindOfAdd) String() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type addMetadataOptions struct {
|
type addMetadataOptions struct {
|
||||||
force bool
|
force bool
|
||||||
metadata map[string]string
|
metadata map[string]string
|
||||||
mapValidator func(map[string]string) error
|
mapValidator func(map[string]string) error
|
||||||
kind kindOfAdd
|
kind kindOfAdd
|
||||||
|
labelsWithoutSelector bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// newCmdAddAnnotation adds one or more commonAnnotations to the kustomization file.
|
// newCmdAddAnnotation adds one or more commonAnnotations to the kustomization file.
|
||||||
@@ -79,6 +80,9 @@ func newCmdAddLabel(fSys filesys.FileSystem, v func(map[string]string) error) *c
|
|||||||
cmd.Flags().BoolVarP(&o.force, "force", "f", false,
|
cmd.Flags().BoolVarP(&o.force, "force", "f", false,
|
||||||
"overwrite commonLabel if it already exists",
|
"overwrite commonLabel if it already exists",
|
||||||
)
|
)
|
||||||
|
cmd.Flags().BoolVar(&o.labelsWithoutSelector, "without-selector", false,
|
||||||
|
"using add labels without selector option",
|
||||||
|
)
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,6 +131,10 @@ func (o *addMetadataOptions) addAnnotations(m *types.Kustomization) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *addMetadataOptions) addLabels(m *types.Kustomization) error {
|
func (o *addMetadataOptions) addLabels(m *types.Kustomization) error {
|
||||||
|
if o.labelsWithoutSelector {
|
||||||
|
m.Labels = append(m.Labels, types.Label{Pairs: make(map[string]string), IncludeSelectors: false})
|
||||||
|
return o.writeToMap(m.Labels[len(m.Labels)-1].Pairs, label)
|
||||||
|
}
|
||||||
if m.CommonLabels == nil {
|
if m.CommonLabels == nil {
|
||||||
m.CommonLabels = make(map[string]string)
|
m.CommonLabels = make(map[string]string)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -274,3 +274,27 @@ func TestAddLabelForce(t *testing.T) {
|
|||||||
assert.NoError(t, cmd.RunE(cmd, args))
|
assert.NoError(t, cmd.RunE(cmd, args))
|
||||||
v.VerifyCall()
|
v.VerifyCall()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestAddLabelWithoutSelector(t *testing.T) {
|
||||||
|
var o addMetadataOptions
|
||||||
|
o.labelsWithoutSelector = true
|
||||||
|
m := makeKustomization(t)
|
||||||
|
o.metadata = map[string]string{"new": "label"}
|
||||||
|
assert.NoError(t, o.addLabels(m))
|
||||||
|
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"new": "label"}})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddLabelWithoutSelectorAddLabel(t *testing.T) {
|
||||||
|
var o addMetadataOptions
|
||||||
|
o.metadata = map[string]string{"owls": "cute", "otters": "adorable"}
|
||||||
|
o.labelsWithoutSelector = true
|
||||||
|
|
||||||
|
m := makeKustomization(t)
|
||||||
|
assert.NoError(t, o.addLabels(m))
|
||||||
|
// adding new labels should work
|
||||||
|
o.metadata = map[string]string{"new": "label"}
|
||||||
|
assert.NoError(t, o.addLabels(m))
|
||||||
|
|
||||||
|
assert.Equal(t, m.Labels[0], types.Label{Pairs: map[string]string{"owls": "cute", "otters": "adorable"}})
|
||||||
|
assert.Equal(t, m.Labels[1], types.Label{Pairs: map[string]string{"new": "label"}})
|
||||||
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
ldrhelper "sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
||||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/util"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
@@ -49,7 +49,7 @@ func (o *addResourceOptions) Validate(args []string) error {
|
|||||||
|
|
||||||
// RunAddResource runs addResource command (do real work).
|
// RunAddResource runs addResource command (do real work).
|
||||||
func (o *addResourceOptions) RunAddResource(fSys filesys.FileSystem) error {
|
func (o *addResourceOptions) RunAddResource(fSys filesys.FileSystem) error {
|
||||||
resources, err := util.GlobPatternsWithLoader(fSys, loader.NewFileLoaderAtCwd(fSys), o.resourceFilePaths)
|
resources, err := util.GlobPatternsWithLoader(fSys, ldrhelper.NewFileLoaderAtCwd(fSys), o.resourceFilePaths)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/api/kv"
|
"sigs.k8s.io/kustomize/api/kv"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
ldrhelper "sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
@@ -19,7 +19,7 @@ func TestNewAddConfigMapIsNotNil(t *testing.T) {
|
|||||||
assert.NotNil(t, newCmdAddConfigMap(
|
assert.NotNil(t, newCmdAddConfigMap(
|
||||||
fSys,
|
fSys,
|
||||||
kv.NewLoader(
|
kv.NewLoader(
|
||||||
loader.NewFileLoaderAtCwd(fSys),
|
ldrhelper.NewFileLoaderAtCwd(fSys),
|
||||||
valtest_test.MakeFakeValidator()),
|
valtest_test.MakeFakeValidator()),
|
||||||
nil))
|
nil))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"sigs.k8s.io/kustomize/api/kv"
|
"sigs.k8s.io/kustomize/api/kv"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
ldrhelper "sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
valtest_test "sigs.k8s.io/kustomize/api/testutils/valtest"
|
||||||
"sigs.k8s.io/kustomize/api/types"
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
"sigs.k8s.io/kustomize/kyaml/filesys"
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
@@ -19,7 +19,7 @@ func TestNewCmdAddSecretIsNotNil(t *testing.T) {
|
|||||||
assert.NotNil(t, newCmdAddSecret(
|
assert.NotNil(t, newCmdAddSecret(
|
||||||
fSys,
|
fSys,
|
||||||
kv.NewLoader(
|
kv.NewLoader(
|
||||||
loader.NewFileLoaderAtCwd(fSys),
|
ldrhelper.NewFileLoaderAtCwd(fSys),
|
||||||
valtest_test.MakeFakeValidator()),
|
valtest_test.MakeFakeValidator()),
|
||||||
nil))
|
nil))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"sigs.k8s.io/kustomize/api/ifc"
|
"sigs.k8s.io/kustomize/api/ifc"
|
||||||
"sigs.k8s.io/kustomize/api/kv"
|
"sigs.k8s.io/kustomize/api/kv"
|
||||||
"sigs.k8s.io/kustomize/api/loader"
|
ldrhelper "sigs.k8s.io/kustomize/api/pkg/loader"
|
||||||
"sigs.k8s.io/kustomize/api/resource"
|
"sigs.k8s.io/kustomize/api/resource"
|
||||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/edit/add"
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/edit/add"
|
||||||
"sigs.k8s.io/kustomize/kustomize/v5/commands/edit/fix"
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/edit/fix"
|
||||||
@@ -43,11 +43,11 @@ func NewCmdEdit(
|
|||||||
c.AddCommand(
|
c.AddCommand(
|
||||||
add.NewCmdAdd(
|
add.NewCmdAdd(
|
||||||
fSys,
|
fSys,
|
||||||
kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), v),
|
kv.NewLoader(ldrhelper.NewFileLoaderAtCwd(fSys), v),
|
||||||
rf),
|
rf),
|
||||||
set.NewCmdSet(
|
set.NewCmdSet(
|
||||||
fSys,
|
fSys,
|
||||||
kv.NewLoader(loader.NewFileLoaderAtCwd(fSys), v),
|
kv.NewLoader(ldrhelper.NewFileLoaderAtCwd(fSys), v),
|
||||||
v),
|
v),
|
||||||
fix.NewCmdFix(fSys, w),
|
fix.NewCmdFix(fSys, w),
|
||||||
remove.NewCmdRemove(fSys, v),
|
remove.NewCmdRemove(fSys, v),
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ func NewCmdRemove(
|
|||||||
kustomize edit remove resource {filepath} {filepath}
|
kustomize edit remove resource {filepath} {filepath}
|
||||||
kustomize edit remove resource {pattern}
|
kustomize edit remove resource {pattern}
|
||||||
|
|
||||||
|
# Removes one or more configmap from the kustomization file
|
||||||
|
kustomize edit remove configmap {name1},{name2}
|
||||||
|
|
||||||
# Removes one or more patches from the kustomization file
|
# Removes one or more patches from the kustomization file
|
||||||
kustomize edit remove patch --path {filepath} --group {target group name} --version {target version}
|
kustomize edit remove patch --path {filepath} --group {target group name} --version {target version}
|
||||||
|
|
||||||
@@ -37,6 +40,7 @@ func NewCmdRemove(
|
|||||||
Args: cobra.MinimumNArgs(1),
|
Args: cobra.MinimumNArgs(1),
|
||||||
}
|
}
|
||||||
c.AddCommand(
|
c.AddCommand(
|
||||||
|
newCmdRemoveConfigMap(fSys),
|
||||||
newCmdRemoveResource(fSys),
|
newCmdRemoveResource(fSys),
|
||||||
newCmdRemoveLabel(fSys, v.MakeLabelNameValidator()),
|
newCmdRemoveLabel(fSys, v.MakeLabelNameValidator()),
|
||||||
newCmdRemoveAnnotation(fSys, v.MakeAnnotationNameValidator()),
|
newCmdRemoveAnnotation(fSys, v.MakeAnnotationNameValidator()),
|
||||||
|
|||||||
99
kustomize/commands/edit/remove/removeconfigmap.go
Normal file
99
kustomize/commands/edit/remove/removeconfigmap.go
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
// Copyright 2023 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package remove
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"sigs.k8s.io/kustomize/api/konfig"
|
||||||
|
"sigs.k8s.io/kustomize/api/types"
|
||||||
|
"sigs.k8s.io/kustomize/kustomize/v5/commands/internal/kustfile"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
)
|
||||||
|
|
||||||
|
type removeConfigMapOptions struct {
|
||||||
|
configMapNamesToRemove []string
|
||||||
|
}
|
||||||
|
|
||||||
|
// newCmdRemoveResource remove the name of a file containing a resource to the kustomization file.
|
||||||
|
func newCmdRemoveConfigMap(fSys filesys.FileSystem) *cobra.Command {
|
||||||
|
var o removeConfigMapOptions
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "configmap",
|
||||||
|
Short: "Removes the specified configmap(s) from " +
|
||||||
|
konfig.DefaultKustomizationFileName(),
|
||||||
|
Long: "",
|
||||||
|
Example: `
|
||||||
|
remove configmap my-configmap
|
||||||
|
`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
err := o.Validate(args)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return o.RunRemoveConfigMap(fSys)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate validates removeConfigMap command.
|
||||||
|
func (o *removeConfigMapOptions) Validate(args []string) error {
|
||||||
|
switch {
|
||||||
|
case len(args) == 0:
|
||||||
|
return errors.New("at least one configmap name must be specified")
|
||||||
|
case len(args) > 1:
|
||||||
|
return fmt.Errorf("too many arguments: %s; to provide multiple configmaps to remove, please separate configmap names by commas", args)
|
||||||
|
}
|
||||||
|
|
||||||
|
o.configMapNamesToRemove = strings.Split(args[0], ",")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RunRemoveConfigMap runs ConfigMap command (do real work).
|
||||||
|
func (o *removeConfigMapOptions) RunRemoveConfigMap(fSys filesys.FileSystem) error {
|
||||||
|
mf, err := kustfile.NewKustomizationFile(fSys)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not read kustomization file: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
m, err := mf.Read()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("could not read kustomization file contents: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
foundConfigMaps := make(map[string]struct{})
|
||||||
|
|
||||||
|
newConfigMaps := make([]types.ConfigMapArgs, 0, len(m.ConfigMapGenerator))
|
||||||
|
for _, currentConfigMap := range m.ConfigMapGenerator {
|
||||||
|
if kustfile.StringInSlice(currentConfigMap.Name, o.configMapNamesToRemove) {
|
||||||
|
foundConfigMaps[currentConfigMap.Name] = struct{}{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newConfigMaps = append(newConfigMaps, currentConfigMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(foundConfigMaps) == 0 {
|
||||||
|
return fmt.Errorf("no specified configmap(s) were found in the %s file",
|
||||||
|
konfig.DefaultKustomizationFileName())
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range o.configMapNamesToRemove {
|
||||||
|
if _, found := foundConfigMaps[name]; !found {
|
||||||
|
log.Printf("configmap %s doesn't exist in kustomization file", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m.ConfigMapGenerator = newConfigMaps
|
||||||
|
err = mf.Write(m)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write kustomization file: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
116
kustomize/commands/edit/remove/removeconfigmap_test.go
Normal file
116
kustomize/commands/edit/remove/removeconfigmap_test.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// Copyright 2023 The Kubernetes Authors.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package remove //nolint:testpackage
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
testutils_test "sigs.k8s.io/kustomize/kustomize/v5/commands/internal/testutils"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/filesys"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRemoveConfigMap(t *testing.T) {
|
||||||
|
const configMapName01 = "example-configmap-01"
|
||||||
|
const configMapName02 = "example-configmap-02"
|
||||||
|
|
||||||
|
tests := map[string]struct {
|
||||||
|
input string
|
||||||
|
args []string
|
||||||
|
expectedOutput string
|
||||||
|
expectedErr string
|
||||||
|
}{
|
||||||
|
"happy path": {
|
||||||
|
input: fmt.Sprintf(`
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
configMapGenerator:
|
||||||
|
- name: %s
|
||||||
|
files:
|
||||||
|
- application.properties
|
||||||
|
`, configMapName01),
|
||||||
|
args: []string{configMapName01},
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"multiple": {
|
||||||
|
input: fmt.Sprintf(`
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
configMapGenerator:
|
||||||
|
- name: %s
|
||||||
|
files:
|
||||||
|
- application.properties
|
||||||
|
- name: %s
|
||||||
|
files:
|
||||||
|
- application.properties
|
||||||
|
`, configMapName01, configMapName02),
|
||||||
|
args: []string{
|
||||||
|
fmt.Sprintf("%s,%s", configMapName01, configMapName02),
|
||||||
|
},
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
"miss": {
|
||||||
|
input: fmt.Sprintf(`
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
configMapGenerator:
|
||||||
|
- name: %s
|
||||||
|
files:
|
||||||
|
- application.properties
|
||||||
|
`, configMapName01),
|
||||||
|
args: []string{"foo"},
|
||||||
|
expectedErr: "no specified configmap(s) were found",
|
||||||
|
},
|
||||||
|
"no configmap name specified": {
|
||||||
|
args: []string{},
|
||||||
|
expectedErr: "at least one configmap name must be specified",
|
||||||
|
},
|
||||||
|
"too many configmap names specified": {
|
||||||
|
args: []string{"test1", "test2"},
|
||||||
|
expectedErr: "too many arguments",
|
||||||
|
},
|
||||||
|
"one existing and one non-existing": {
|
||||||
|
input: fmt.Sprintf(`
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
configMapGenerator:
|
||||||
|
- name: %s
|
||||||
|
files:
|
||||||
|
- application.properties
|
||||||
|
`, configMapName01),
|
||||||
|
args: []string{fmt.Sprintf("%s,%s", configMapName01, "foo")},
|
||||||
|
expectedOutput: `
|
||||||
|
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||||
|
kind: Kustomization
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, tc := range tests {
|
||||||
|
t.Run(name, func(t *testing.T) {
|
||||||
|
fSys := filesys.MakeFsInMemory()
|
||||||
|
testutils_test.WriteTestKustomizationWith(fSys, []byte(tc.input))
|
||||||
|
cmd := newCmdRemoveConfigMap(fSys)
|
||||||
|
err := cmd.RunE(cmd, tc.args)
|
||||||
|
|
||||||
|
if tc.expectedErr != "" {
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Contains(t, err.Error(), tc.expectedErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NoError(t, err)
|
||||||
|
content, err := testutils_test.ReadTestKustomization(fSys)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, tc.expectedOutput, string(content))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ require (
|
|||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.8.1
|
github.com/stretchr/testify v1.8.1
|
||||||
golang.org/x/text v0.8.0
|
golang.org/x/text v0.8.0
|
||||||
sigs.k8s.io/kustomize/api v0.13.4
|
sigs.k8s.io/kustomize/api v0.14.0
|
||||||
sigs.k8s.io/kustomize/cmd/config v0.11.3
|
sigs.k8s.io/kustomize/cmd/config v0.11.3
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3
|
sigs.k8s.io/kustomize/kyaml v0.14.3
|
||||||
sigs.k8s.io/yaml v1.3.0
|
sigs.k8s.io/yaml v1.3.0
|
||||||
@@ -16,7 +16,6 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
|
|
||||||
github.com/go-errors/errors v1.4.2 // indirect
|
github.com/go-errors/errors v1.4.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
github.com/go-openapi/jsonreference v0.20.2 // indirect
|
||||||
@@ -34,8 +33,9 @@ require (
|
|||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/xlab/treeprint v1.2.0 // indirect
|
github.com/xlab/treeprint v1.2.0 // indirect
|
||||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
|
||||||
golang.org/x/sys v0.8.0 // indirect
|
golang.org/x/sys v0.12.0 // indirect
|
||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
|
gopkg.in/evanphx/json-patch.v5 v5.6.0 // indirect
|
||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
@@ -43,3 +43,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
replace sigs.k8s.io/kustomize/api => ../api
|
replace sigs.k8s.io/kustomize/api => ../api
|
||||||
|
|
||||||
|
replace sigs.k8s.io/kustomize/cmd/config => ../cmd/config
|
||||||
|
|
||||||
|
replace sigs.k8s.io/kustomize/kyaml => ../kyaml
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible h1:4onqiflcdA9EOZ4RxV643DvftH5pOlLGNtQ5lPWQu84=
|
|
||||||
github.com/evanphx/json-patch v4.12.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
@@ -69,8 +67,8 @@ github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd
|
|||||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
|
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 h1:+FNtrFTmVw0YZGpBGX56XDee331t6JAXeK2bcyhLOOc=
|
||||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
||||||
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
|
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@@ -81,6 +79,8 @@ google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
gopkg.in/evanphx/json-patch.v5 v5.6.0 h1:BMT6KIwBD9CaU91PJCZIe46bDmBWa9ynTQgJIOpfQBk=
|
||||||
|
gopkg.in/evanphx/json-patch.v5 v5.6.0/go.mod h1:/kvTRh1TVm5wuM6OkHxqXtE/1nUZZpihg29RtuIyfvk=
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
@@ -91,9 +91,5 @@ gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|||||||
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961 h1:pqRVJGQJz6oeZby8qmPKXYIBjyrcv7EHCe/33UkZMYA=
|
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961 h1:pqRVJGQJz6oeZby8qmPKXYIBjyrcv7EHCe/33UkZMYA=
|
||||||
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961/go.mod h1:l8HTwL5fqnlns4jOveW1L75eo7R9KFHxiE0bsPGy428=
|
k8s.io/kube-openapi v0.0.0-20230601164746-7562a1006961/go.mod h1:l8HTwL5fqnlns4jOveW1L75eo7R9KFHxiE0bsPGy428=
|
||||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||||
sigs.k8s.io/kustomize/cmd/config v0.11.3 h1:QLukJoe/0sjhUrtylmBS1MXhvkdLtbpHJvAClXDra54=
|
|
||||||
sigs.k8s.io/kustomize/cmd/config v0.11.3/go.mod h1:ENTZ8Ds12gewUpdxF5PJq/9qPVQFd5VPvMIL11wrBIU=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3 h1:WpabVAKZe2YEp/irTSHwD6bfjwZnTtSDewd2BVJGMZs=
|
|
||||||
sigs.k8s.io/kustomize/kyaml v0.14.3/go.mod h1:npvh9epWysfQ689Rtt/U+dpOJDTBn8kUnF1O6VzvmZA=
|
|
||||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package fixsetters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// FieldMeta contains metadata that may be attached to fields as comments
|
|
||||||
type FieldMetaV1 struct {
|
|
||||||
Schema spec.Schema
|
|
||||||
|
|
||||||
Extensions XKustomize
|
|
||||||
}
|
|
||||||
|
|
||||||
type XKustomize struct {
|
|
||||||
SetBy string `yaml:"setBy,omitempty" json:"setBy,omitempty"`
|
|
||||||
PartialFieldSetters []PartialFieldSetter `yaml:"partialSetters,omitempty" json:"partialSetters,omitempty"`
|
|
||||||
FieldSetter *PartialFieldSetter `yaml:"setter,omitempty" json:"setter,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PartialFieldSetter defines how to set part of a field rather than the full field
|
|
||||||
// value. e.g. the tag part of an image field
|
|
||||||
type PartialFieldSetter struct {
|
|
||||||
// Name is the name of this setter.
|
|
||||||
Name string `yaml:"name" json:"name"`
|
|
||||||
|
|
||||||
// Value is the current value that has been set.
|
|
||||||
Value string `yaml:"value" json:"value"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpgradeV1SetterComment reads the FieldMeta from a node and upgrade the
|
|
||||||
// setters comment to latest
|
|
||||||
func (fm *FieldMetaV1) UpgradeV1SetterComment(n *yaml.RNode) error {
|
|
||||||
// check for metadata on head and line comments
|
|
||||||
comments := []string{n.YNode().LineComment, n.YNode().HeadComment}
|
|
||||||
for _, c := range comments {
|
|
||||||
if c == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
c := strings.TrimLeft(c, "#")
|
|
||||||
|
|
||||||
if err := fm.Schema.UnmarshalJSON([]byte(c)); err != nil {
|
|
||||||
// note: don't return an error if the comment isn't a fieldmeta struct
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
fe := fm.Schema.VendorExtensible.Extensions["x-kustomize"]
|
|
||||||
if fe == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
b, err := json.Marshal(fe)
|
|
||||||
if err != nil {
|
|
||||||
return errors.Wrap(err)
|
|
||||||
}
|
|
||||||
// delete line comment after parsing info into fieldmeta
|
|
||||||
n.YNode().HeadComment = ""
|
|
||||||
n.YNode().LineComment = ""
|
|
||||||
err = json.Unmarshal(b, &fm.Extensions)
|
|
||||||
if fm.Extensions.FieldSetter != nil {
|
|
||||||
n.YNode().LineComment = fmt.Sprintf(`{"%s":"%s"}`, fieldmeta.ShortHandRef(), fm.Extensions.FieldSetter.Name)
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package fixsetters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters2"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/setters2/settersutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// SetterFixer fixes setters in the input package
|
|
||||||
type SetterFixer struct {
|
|
||||||
// PkgPath is path to the resource package
|
|
||||||
PkgPath string
|
|
||||||
|
|
||||||
// OpenAPIPath is path to the openAPI file in the package
|
|
||||||
OpenAPIPath string
|
|
||||||
|
|
||||||
// DryRun only displays the actions without performing
|
|
||||||
DryRun bool
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetterFixerV1Result holds the results of V1 setters fix
|
|
||||||
type SetterFixerV1Result struct {
|
|
||||||
// NeedFix indicates if the resource in pkgPath are on V1 version of setters
|
|
||||||
// and need to be fixed
|
|
||||||
NeedFix bool
|
|
||||||
|
|
||||||
// CreatedSetters are setters created as part of this fix
|
|
||||||
CreatedSetters []string
|
|
||||||
|
|
||||||
// CreatedSubst are substitutions created as part of this fix
|
|
||||||
CreatedSubst []string
|
|
||||||
|
|
||||||
// FailedSetters are setters failed to create from current V1 setters
|
|
||||||
FailedSetters map[string]error
|
|
||||||
|
|
||||||
// FailedSubst are substitutions failed to be created from V1 partial setters
|
|
||||||
FailedSubst map[string]error
|
|
||||||
}
|
|
||||||
|
|
||||||
// FixSettersV1 reads the package and upgrades v1 version of setters
|
|
||||||
// to latest
|
|
||||||
func (f *SetterFixer) FixV1Setters() (SetterFixerV1Result, error) {
|
|
||||||
sfr := SetterFixerV1Result{
|
|
||||||
FailedSetters: make(map[string]error),
|
|
||||||
FailedSubst: make(map[string]error),
|
|
||||||
}
|
|
||||||
// KrmFile need not exist for dryRun
|
|
||||||
if !f.DryRun {
|
|
||||||
_, err := os.Stat(f.OpenAPIPath)
|
|
||||||
if err != nil {
|
|
||||||
return sfr, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
// lookup for all setters and partial setters in v1 format
|
|
||||||
// delete the v1 format comments after lookup
|
|
||||||
l := UpgradeV1Setters{}
|
|
||||||
if f.DryRun {
|
|
||||||
err = applyReadFilter(&l, f.PkgPath)
|
|
||||||
} else {
|
|
||||||
err = applyWriteFilter(&l, f.PkgPath)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return sfr, err
|
|
||||||
}
|
|
||||||
if len(l.SetterCounts) > 0 {
|
|
||||||
sfr.NeedFix = true
|
|
||||||
} else {
|
|
||||||
return sfr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each v1 setter create the equivalent in v2,
|
|
||||||
for _, setter := range l.SetterCounts {
|
|
||||||
sd := setters2.SetterDefinition{
|
|
||||||
Name: setter.Name,
|
|
||||||
Value: setter.Value,
|
|
||||||
Description: setter.Description,
|
|
||||||
SetBy: setter.SetBy,
|
|
||||||
Type: setter.Type,
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
if !f.DryRun {
|
|
||||||
err = sd.AddToFile(f.OpenAPIPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
sfr.FailedSetters[setter.Name] = err
|
|
||||||
} else {
|
|
||||||
sfr.CreatedSetters = append(sfr.CreatedSetters, setter.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each group of partial setters, create equivalent substitution
|
|
||||||
for _, subst := range l.Substitutions {
|
|
||||||
sc := settersutil.SubstitutionCreator{
|
|
||||||
Name: subst.Name,
|
|
||||||
FieldValue: subst.FieldVale,
|
|
||||||
Pattern: subst.Pattern,
|
|
||||||
ResourcesPath: f.PkgPath,
|
|
||||||
OpenAPIPath: f.OpenAPIPath,
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
if !f.DryRun {
|
|
||||||
err = applyWriteFilter(&sc, f.PkgPath)
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
sfr.FailedSubst[subst.Name] = err
|
|
||||||
} else {
|
|
||||||
sfr.CreatedSubst = append(sfr.CreatedSubst, subst.Name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sfr, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyWriteFilter(f kio.Filter, pkgPath string) error {
|
|
||||||
rw := &kio.LocalPackageReadWriter{
|
|
||||||
PackagePath: pkgPath,
|
|
||||||
}
|
|
||||||
return kio.Pipeline{
|
|
||||||
Inputs: []kio.Reader{rw},
|
|
||||||
Filters: []kio.Filter{f},
|
|
||||||
Outputs: []kio.Writer{rw},
|
|
||||||
}.Execute()
|
|
||||||
}
|
|
||||||
|
|
||||||
func applyReadFilter(f kio.Filter, pkgPath string) error {
|
|
||||||
rw := &kio.LocalPackageReader{
|
|
||||||
PackagePath: pkgPath,
|
|
||||||
}
|
|
||||||
return kio.Pipeline{
|
|
||||||
Inputs: []kio.Reader{rw},
|
|
||||||
Filters: []kio.Filter{f},
|
|
||||||
}.Execute()
|
|
||||||
}
|
|
||||||
@@ -1,460 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package fixsetters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFixSettersV1(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
name string
|
|
||||||
input string
|
|
||||||
err string
|
|
||||||
dryRun bool
|
|
||||||
openAPIFile string
|
|
||||||
expectedOutput string
|
|
||||||
expectedOpenAPI string
|
|
||||||
needFix bool
|
|
||||||
createdSetters []string
|
|
||||||
createdSubst []string
|
|
||||||
failedSetters map[string]error
|
|
||||||
failedSubst map[string]error
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "upgrade-delete-partial-setters",
|
|
||||||
input: `
|
|
||||||
apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
cluster: "someproj/someclus" # {"type":"string","x-kustomize":{"partialSetters":[{"name":"project","value":"someproj"},{"name":"cluster","value":"someclus"}]}}
|
|
||||||
spec:
|
|
||||||
profile: asm # {"type":"string","x-kustomize":{"setter":{"name":"profile","value":"asm"}}}
|
|
||||||
cluster: "someproj/someclus" # {"type":"string","x-kustomize":{"partialSetters":[{"name":"project","value":"someproj"},{"name":"cluster","value":"someclus"}]}}
|
|
||||||
`,
|
|
||||||
|
|
||||||
openAPIFile: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization`,
|
|
||||||
|
|
||||||
needFix: true,
|
|
||||||
createdSetters: []string{"cluster", "profile", "project"},
|
|
||||||
createdSubst: []string{"project-cluster-54235872"},
|
|
||||||
failedSetters: map[string]error{},
|
|
||||||
failedSubst: map[string]error{},
|
|
||||||
|
|
||||||
expectedOutput: `apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
cluster: "someproj/someclus" # {"$openapi":"project-cluster-54235872"}
|
|
||||||
spec:
|
|
||||||
profile: asm # {"$openapi":"profile"}
|
|
||||||
cluster: "someproj/someclus" # {"$openapi":"project-cluster-54235872"}
|
|
||||||
`,
|
|
||||||
|
|
||||||
expectedOpenAPI: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.cluster:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: cluster
|
|
||||||
value: someclus
|
|
||||||
io.k8s.cli.setters.profile:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: profile
|
|
||||||
value: asm
|
|
||||||
io.k8s.cli.setters.project:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: project
|
|
||||||
value: someproj
|
|
||||||
io.k8s.cli.substitutions.project-cluster-54235872:
|
|
||||||
x-k8s-cli:
|
|
||||||
substitution:
|
|
||||||
name: project-cluster-54235872
|
|
||||||
pattern: ${project}/${cluster}
|
|
||||||
values:
|
|
||||||
- marker: ${project}
|
|
||||||
ref: '#/definitions/io.k8s.cli.setters.project'
|
|
||||||
- marker: ${cluster}
|
|
||||||
ref: '#/definitions/io.k8s.cli.setters.cluster'
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "upgrade-delete-partial-setters-dryRun",
|
|
||||||
dryRun: true,
|
|
||||||
input: `apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
cluster: "someproj/someclus" # {"type":"string","x-kustomize":{"partialSetters":[{"name":"project","value":"someproj"},{"name":"cluster","value":"someclus"}]}}
|
|
||||||
spec:
|
|
||||||
profile: asm # {"type":"string","x-kustomize":{"setter":{"name":"profile","value":"asm"}}}
|
|
||||||
cluster: "someproj/someclus" # {"type":"string","x-kustomize":{"partialSetters":[{"name":"project","value":"someproj"},{"name":"cluster","value":"someclus"}]}}
|
|
||||||
`,
|
|
||||||
needFix: true,
|
|
||||||
createdSetters: []string{"cluster", "profile", "project"},
|
|
||||||
createdSubst: []string{"project-cluster-54235872"},
|
|
||||||
failedSetters: map[string]error{},
|
|
||||||
failedSubst: map[string]error{},
|
|
||||||
|
|
||||||
expectedOutput: `apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
cluster: "someproj/someclus" # {"type":"string","x-kustomize":{"partialSetters":[{"name":"project","value":"someproj"},{"name":"cluster","value":"someclus"}]}}
|
|
||||||
spec:
|
|
||||||
profile: asm # {"type":"string","x-kustomize":{"setter":{"name":"profile","value":"asm"}}}
|
|
||||||
cluster: "someproj/someclus" # {"type":"string","x-kustomize":{"partialSetters":[{"name":"project","value":"someproj"},{"name":"cluster","value":"someclus"}]}}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "partial-setters-same-value",
|
|
||||||
input: `
|
|
||||||
apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
spec:
|
|
||||||
profile: asm # {"type":"string","x-kustomize":{"setter":{"name":"profile","value":"asm"}}}
|
|
||||||
team: asm # {"type":"string","x-kustomize":{"setter":{"name":"team","value":"asm"}}}
|
|
||||||
profile-team: asm/asm # {"type":"string","x-kustomize":{"partialSetters":[{"name":"profile","value":"asm"},{"name":"team","value":"asm"}]}}
|
|
||||||
`,
|
|
||||||
|
|
||||||
openAPIFile: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization`,
|
|
||||||
|
|
||||||
needFix: true,
|
|
||||||
createdSetters: []string{"profile", "team"},
|
|
||||||
createdSubst: []string{"profile-team-1851878264"},
|
|
||||||
failedSetters: map[string]error{},
|
|
||||||
failedSubst: map[string]error{},
|
|
||||||
|
|
||||||
expectedOutput: `apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
spec:
|
|
||||||
profile: asm # {"$openapi":"profile"}
|
|
||||||
team: asm # {"$openapi":"team"}
|
|
||||||
profile-team: asm/asm # {"$openapi":"profile-team-1851878264"}
|
|
||||||
`,
|
|
||||||
|
|
||||||
expectedOpenAPI: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.profile:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: profile
|
|
||||||
value: asm
|
|
||||||
io.k8s.cli.setters.team:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: team
|
|
||||||
value: asm
|
|
||||||
io.k8s.cli.substitutions.profile-team-1851878264:
|
|
||||||
x-k8s-cli:
|
|
||||||
substitution:
|
|
||||||
name: profile-team-1851878264
|
|
||||||
pattern: ${profile}/${team}
|
|
||||||
values:
|
|
||||||
- marker: ${profile}
|
|
||||||
ref: '#/definitions/io.k8s.cli.setters.profile'
|
|
||||||
- marker: ${team}
|
|
||||||
ref: '#/definitions/io.k8s.cli.setters.team'
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "partial-setters-suffix-subst",
|
|
||||||
input: `
|
|
||||||
apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
spec:
|
|
||||||
profile: asm-profile # {"type":"string","x-kustomize":{"partialSetters":[{"name":"asm","value":"asm"}]}}
|
|
||||||
team: asm-team # {"type":"string","x-kustomize":{"partialSetters":[{"name":"asm","value":"asm"}]}}
|
|
||||||
`,
|
|
||||||
|
|
||||||
openAPIFile: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization`,
|
|
||||||
|
|
||||||
needFix: true,
|
|
||||||
createdSetters: []string{"asm"},
|
|
||||||
createdSubst: []string{"asm-3472570278", "asm-3647054792"},
|
|
||||||
failedSetters: map[string]error{},
|
|
||||||
failedSubst: map[string]error{},
|
|
||||||
|
|
||||||
expectedOutput: `apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
spec:
|
|
||||||
profile: asm-profile # {"$openapi":"asm-3647054792"}
|
|
||||||
team: asm-team # {"$openapi":"asm-3472570278"}
|
|
||||||
`,
|
|
||||||
|
|
||||||
expectedOpenAPI: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.asm:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: asm
|
|
||||||
value: asm
|
|
||||||
io.k8s.cli.substitutions.asm-3472570278:
|
|
||||||
x-k8s-cli:
|
|
||||||
substitution:
|
|
||||||
name: asm-3472570278
|
|
||||||
pattern: ${asm}-team
|
|
||||||
values:
|
|
||||||
- marker: ${asm}
|
|
||||||
ref: '#/definitions/io.k8s.cli.setters.asm'
|
|
||||||
io.k8s.cli.substitutions.asm-3647054792:
|
|
||||||
x-k8s-cli:
|
|
||||||
substitution:
|
|
||||||
name: asm-3647054792
|
|
||||||
pattern: ${asm}-profile
|
|
||||||
values:
|
|
||||||
- marker: ${asm}
|
|
||||||
ref: '#/definitions/io.k8s.cli.setters.asm'
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "upgrade-with-both-versions",
|
|
||||||
|
|
||||||
input: `
|
|
||||||
apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
clusterName: "project-id/us-east1-d/cluster-name"
|
|
||||||
spec:
|
|
||||||
profile: asm # {"type":"string","x-kustomize":{"setter":{"name":"profilesetter","value":"asm"}}}
|
|
||||||
hub: gcr.io/asm-testing # {"$openapi":"hubsetter"}
|
|
||||||
`,
|
|
||||||
|
|
||||||
openAPIFile: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.hubsetter:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: hubsetter
|
|
||||||
value: gcr.io/asm-testing`,
|
|
||||||
|
|
||||||
needFix: true,
|
|
||||||
createdSetters: []string{"profilesetter"},
|
|
||||||
failedSetters: map[string]error{},
|
|
||||||
failedSubst: map[string]error{},
|
|
||||||
|
|
||||||
expectedOutput: `apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
clusterName: "project-id/us-east1-d/cluster-name"
|
|
||||||
spec:
|
|
||||||
profile: asm # {"$openapi":"profilesetter"}
|
|
||||||
hub: gcr.io/asm-testing # {"$openapi":"hubsetter"}
|
|
||||||
`,
|
|
||||||
|
|
||||||
expectedOpenAPI: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.hubsetter:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: hubsetter
|
|
||||||
value: gcr.io/asm-testing
|
|
||||||
io.k8s.cli.setters.profilesetter:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: profilesetter
|
|
||||||
value: asm
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "setter-already-exists",
|
|
||||||
|
|
||||||
input: `
|
|
||||||
apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
clusterName: "project-id/us-east1-d/cluster-name"
|
|
||||||
spec:
|
|
||||||
profile: asm # {"type":"string","x-kustomize":{"setter":{"name":"profilesetter","value":"asm"}}}
|
|
||||||
hub: asm # {"$openapi":"profilesetter"}
|
|
||||||
`,
|
|
||||||
|
|
||||||
openAPIFile: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.profilesetter:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: profilesetter
|
|
||||||
value: asm
|
|
||||||
`,
|
|
||||||
|
|
||||||
needFix: true,
|
|
||||||
createdSetters: []string{"profilesetter"},
|
|
||||||
failedSetters: map[string]error{},
|
|
||||||
failedSubst: map[string]error{},
|
|
||||||
expectedOutput: `apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
clusterName: "project-id/us-east1-d/cluster-name"
|
|
||||||
spec:
|
|
||||||
profile: asm # {"$openapi":"profilesetter"}
|
|
||||||
hub: asm # {"$openapi":"profilesetter"}
|
|
||||||
`,
|
|
||||||
|
|
||||||
expectedOpenAPI: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.profilesetter:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: profilesetter
|
|
||||||
value: asm
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "do-not-delete-latest setters",
|
|
||||||
|
|
||||||
input: `
|
|
||||||
apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
clusterName: "project-id/us-east1-d/cluster-name"
|
|
||||||
spec:
|
|
||||||
profile: asm # {"$openapi":"profilesetter"}
|
|
||||||
hub: gcr.io/asm-testing
|
|
||||||
`,
|
|
||||||
failedSetters: map[string]error{},
|
|
||||||
failedSubst: map[string]error{},
|
|
||||||
|
|
||||||
openAPIFile: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.profilesetter:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: profilesetter
|
|
||||||
value: asm
|
|
||||||
`,
|
|
||||||
|
|
||||||
expectedOutput: `apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
clusterName: "project-id/us-east1-d/cluster-name"
|
|
||||||
spec:
|
|
||||||
profile: asm # {"$openapi":"profilesetter"}
|
|
||||||
hub: gcr.io/asm-testing
|
|
||||||
`,
|
|
||||||
|
|
||||||
expectedOpenAPI: `apiVersion: kustomization.dev/v1alpha1
|
|
||||||
kind: Kustomization
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.profilesetter:
|
|
||||||
type: string
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: profilesetter
|
|
||||||
value: asm
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "no-openAPI-file-error",
|
|
||||||
input: `
|
|
||||||
apiVersion: install.istio.io/v1alpha2
|
|
||||||
kind: IstioControlPlane
|
|
||||||
metadata:
|
|
||||||
clusterName: "project-id/us-east1-d/cluster-name"
|
|
||||||
spec:
|
|
||||||
profile: asm # {"type":"string","x-kustomize":{"setter":{"name":"profilesetter","value":"asm"}}}
|
|
||||||
hub: gcr.io/asm-testing
|
|
||||||
`,
|
|
||||||
|
|
||||||
err: "Krmfile:",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i := range tests {
|
|
||||||
test := tests[i]
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
|
||||||
openAPIFileName := "Krmfile"
|
|
||||||
|
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
err := os.WriteFile(filepath.Join(dir, "deploy.yaml"), []byte(test.input), 0600)
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
if test.openAPIFile != "" {
|
|
||||||
err = os.WriteFile(filepath.Join(dir, openAPIFileName), []byte(test.openAPIFile), 0600)
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sf := SetterFixer{
|
|
||||||
PkgPath: dir,
|
|
||||||
DryRun: test.dryRun,
|
|
||||||
OpenAPIPath: filepath.Join(dir, "Krmfile"),
|
|
||||||
}
|
|
||||||
|
|
||||||
sfr, err := sf.FixV1Setters()
|
|
||||||
if test.err == "" {
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if !assert.Contains(t, err.Error(), test.err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
actualOutput, err := os.ReadFile(filepath.Join(dir, "deploy.yaml"))
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedOutput, string(actualOutput))
|
|
||||||
|
|
||||||
if test.expectedOpenAPI != "" {
|
|
||||||
actualOpenAPI, err := os.ReadFile(filepath.Join(dir, openAPIFileName))
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.expectedOpenAPI, string(actualOpenAPI))
|
|
||||||
}
|
|
||||||
assert.Equal(t, test.needFix, sfr.NeedFix)
|
|
||||||
assert.Equal(t, test.createdSetters, sfr.CreatedSetters)
|
|
||||||
assert.Equal(t, test.createdSubst, sfr.CreatedSubst)
|
|
||||||
assert.Equal(t, test.failedSubst, sfr.FailedSubst)
|
|
||||||
assert.Equal(t, test.failedSetters, sfr.FailedSetters)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package fixsetters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"hash/fnv"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ yaml.Filter = &upgradeV1Setters{}
|
|
||||||
|
|
||||||
// upgradeV1Setters looks up v1 setters in a Resource and upgrades
|
|
||||||
// all the setters related comments
|
|
||||||
type upgradeV1Setters struct {
|
|
||||||
// Name of the setter to lookup. Optional
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// Setters is a list of setters that were found
|
|
||||||
Setters []setter
|
|
||||||
|
|
||||||
// Substitutions is a list of substitutions that were found
|
|
||||||
Substitutions []substitution
|
|
||||||
}
|
|
||||||
|
|
||||||
type substitution struct {
|
|
||||||
Name string
|
|
||||||
FieldVale string
|
|
||||||
Pattern string
|
|
||||||
}
|
|
||||||
|
|
||||||
type setter struct {
|
|
||||||
PartialFieldSetter
|
|
||||||
Description string
|
|
||||||
Type string
|
|
||||||
SetBy string
|
|
||||||
SubstName string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ls *upgradeV1Setters) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|
||||||
switch object.YNode().Kind {
|
|
||||||
case yaml.DocumentNode:
|
|
||||||
// skip the document node
|
|
||||||
return ls.Filter(yaml.NewRNode(object.YNode().Content[0]))
|
|
||||||
case yaml.MappingNode:
|
|
||||||
return object, object.VisitFields(func(node *yaml.MapNode) error {
|
|
||||||
return node.Value.PipeE(ls)
|
|
||||||
})
|
|
||||||
case yaml.SequenceNode:
|
|
||||||
return object, object.VisitElements(func(node *yaml.RNode) error {
|
|
||||||
return node.PipeE(ls)
|
|
||||||
})
|
|
||||||
case yaml.ScalarNode:
|
|
||||||
return object, ls.lookupAndUpgrade(object)
|
|
||||||
default:
|
|
||||||
return object, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookupAndUpgrade finds any setters for a field and upgrades the setters comment
|
|
||||||
func (ls *upgradeV1Setters) lookupAndUpgrade(field *yaml.RNode) error {
|
|
||||||
// check if there is a substitution for this field
|
|
||||||
var fm = FieldMetaV1{}
|
|
||||||
if err := fm.UpgradeV1SetterComment(field); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if fm.Extensions.FieldSetter != nil {
|
|
||||||
if ls.Name != "" && ls.Name != fm.Extensions.FieldSetter.Name {
|
|
||||||
// skip this setter, it doesn't match the specified setter
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// full setter
|
|
||||||
ls.Setters = append(ls.Setters, setter{
|
|
||||||
PartialFieldSetter: *fm.Extensions.FieldSetter,
|
|
||||||
Description: fm.Schema.Description,
|
|
||||||
Type: fm.Schema.Type[0],
|
|
||||||
SetBy: fm.Extensions.SetBy,
|
|
||||||
})
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(fm.Extensions.PartialFieldSetters) > 0 {
|
|
||||||
fieldValue := field.YNode().Value
|
|
||||||
pattern := fieldValue
|
|
||||||
|
|
||||||
var substName string
|
|
||||||
// derive substitution pattern from partial setters
|
|
||||||
for i := range fm.Extensions.PartialFieldSetters {
|
|
||||||
substName += fm.Extensions.PartialFieldSetters[i].Name + "-"
|
|
||||||
pattern = strings.Replace(pattern, fm.Extensions.PartialFieldSetters[i].Value, `${`+fm.Extensions.PartialFieldSetters[i].Name+"}", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
fvHash, err := FNV32aHash(fieldValue)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
substName += fvHash
|
|
||||||
ls.Substitutions = append(ls.Substitutions, substitution{
|
|
||||||
Name: substName,
|
|
||||||
FieldVale: fieldValue,
|
|
||||||
Pattern: pattern,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range fm.Extensions.PartialFieldSetters {
|
|
||||||
if ls.Name != "" && ls.Name != fm.Extensions.PartialFieldSetters[i].Name {
|
|
||||||
// skip this setter
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ls.Setters = append(ls.Setters, setter{
|
|
||||||
PartialFieldSetter: fm.Extensions.PartialFieldSetters[i],
|
|
||||||
Description: fm.Schema.Description,
|
|
||||||
Type: fm.Schema.Type[0],
|
|
||||||
SetBy: fm.Extensions.SetBy,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FNV32aHash generates 32-bit FNV-1a hash for input string
|
|
||||||
func FNV32aHash(text string) (string, error) {
|
|
||||||
algorithm := fnv.New32a()
|
|
||||||
_, err := algorithm.Write([]byte(text))
|
|
||||||
if err != nil {
|
|
||||||
return "", errors.Wrap(err)
|
|
||||||
}
|
|
||||||
return fmt.Sprint(algorithm.Sum32()), nil
|
|
||||||
}
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package fixsetters
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ kio.Filter = &UpgradeV1Setters{}
|
|
||||||
|
|
||||||
// UpgradeV1Setters identifies setters for a collection of Resources to upgrade
|
|
||||||
type UpgradeV1Setters struct {
|
|
||||||
// Name is the name of the setter to match. Optional.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// SetterCounts is populated by Filter and contains the count of fields matching each setter.
|
|
||||||
SetterCounts []setterCount
|
|
||||||
|
|
||||||
// Substitutions are groups of partial setters
|
|
||||||
Substitutions []substitution
|
|
||||||
}
|
|
||||||
|
|
||||||
// setterCount records the identified setters and number of fields matching those setters
|
|
||||||
type setterCount struct {
|
|
||||||
// Count is the number of substitutions possible to perform
|
|
||||||
Count int
|
|
||||||
|
|
||||||
// setter is the substitution found
|
|
||||||
setter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter implements kio.Filter
|
|
||||||
func (l *UpgradeV1Setters) Filter(input []*yaml.RNode) ([]*yaml.RNode, error) {
|
|
||||||
setters := map[string]*setterCount{}
|
|
||||||
substitutions := map[string]*substitution{}
|
|
||||||
|
|
||||||
for i := range input {
|
|
||||||
// lookup substitutions for this object
|
|
||||||
ls := &upgradeV1Setters{Name: l.Name}
|
|
||||||
if err := input[i].PipeE(ls); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// aggregate counts for each setter by name. takes the description and value from
|
|
||||||
// the first setter for each name encountered.
|
|
||||||
for j := range ls.Setters {
|
|
||||||
setter := ls.Setters[j]
|
|
||||||
curr, found := setters[setter.Name]
|
|
||||||
if !found {
|
|
||||||
curr = &setterCount{setter: setter}
|
|
||||||
setters[setter.Name] = curr
|
|
||||||
}
|
|
||||||
curr.Count++
|
|
||||||
}
|
|
||||||
|
|
||||||
for j := range ls.Substitutions {
|
|
||||||
subst := ls.Substitutions[j]
|
|
||||||
_, found := substitutions[subst.Name]
|
|
||||||
if !found {
|
|
||||||
substitutions[subst.Name] = &subst
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pull out and sort the results by setter name
|
|
||||||
for _, v := range setters {
|
|
||||||
l.SetterCounts = append(l.SetterCounts, *v)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, subst := range substitutions {
|
|
||||||
l.Substitutions = append(l.Substitutions, *subst)
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(l.Substitutions, func(i, j int) bool {
|
|
||||||
return l.Substitutions[i].Name < l.Substitutions[j].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
sort.Slice(l.SetterCounts, func(i, j int) bool {
|
|
||||||
return l.SetterCounts[i].Name < l.SetterCounts[j].Name
|
|
||||||
})
|
|
||||||
return input, nil
|
|
||||||
}
|
|
||||||
@@ -44,6 +44,16 @@ var (
|
|||||||
customSchema []byte //nolint:gochecknoglobals
|
customSchema []byte //nolint:gochecknoglobals
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// schemaParseStatus is used in cases when a schema should be parsed, but the
|
||||||
|
// parsing may be delayed to a later time.
|
||||||
|
type schemaParseStatus uint32
|
||||||
|
|
||||||
|
const (
|
||||||
|
schemaNotParsed schemaParseStatus = iota
|
||||||
|
schemaParseDelayed
|
||||||
|
schemaParsed
|
||||||
|
)
|
||||||
|
|
||||||
// openapiData contains the parsed openapi state. this is in a struct rather than
|
// openapiData contains the parsed openapi state. this is in a struct rather than
|
||||||
// a list of vars so that it can be reset from tests.
|
// a list of vars so that it can be reset from tests.
|
||||||
type openapiData struct {
|
type openapiData struct {
|
||||||
@@ -57,13 +67,17 @@ type openapiData struct {
|
|||||||
// is namespaceable or not
|
// is namespaceable or not
|
||||||
namespaceabilityByResourceType map[yaml.TypeMeta]bool
|
namespaceabilityByResourceType map[yaml.TypeMeta]bool
|
||||||
|
|
||||||
// noUseBuiltInSchema stores whether we want to prevent using the built-n
|
// noUseBuiltInSchema stores whether we want to prevent using the built-in
|
||||||
// Kubernetes schema as part of the global schema
|
// Kubernetes schema as part of the global schema
|
||||||
noUseBuiltInSchema bool
|
noUseBuiltInSchema bool
|
||||||
|
|
||||||
// schemaInit stores whether or not we've parsed the schema already,
|
// schemaInit stores whether or not we've parsed the schema already,
|
||||||
// so that we only reparse the when necessary (to speed up performance)
|
// so that we only reparse the when necessary (to speed up performance)
|
||||||
schemaInit bool
|
schemaInit bool
|
||||||
|
|
||||||
|
// defaultBuiltInSchemaParseStatus stores the parse status of the default
|
||||||
|
// built-in schema.
|
||||||
|
defaultBuiltInSchemaParseStatus schemaParseStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
type format string
|
type format string
|
||||||
@@ -387,18 +401,45 @@ func GetSchema(s string, schema *spec.Schema) (*ResourceSchema, error) {
|
|||||||
// be true if the resource is namespace-scoped, and false if the type is
|
// be true if the resource is namespace-scoped, and false if the type is
|
||||||
// cluster-scoped.
|
// cluster-scoped.
|
||||||
func IsNamespaceScoped(typeMeta yaml.TypeMeta) (bool, bool) {
|
func IsNamespaceScoped(typeMeta yaml.TypeMeta) (bool, bool) {
|
||||||
if res, f := precomputedIsNamespaceScoped[typeMeta]; f {
|
if isNamespaceScoped, found := precomputedIsNamespaceScoped[typeMeta]; found {
|
||||||
return res, true
|
return isNamespaceScoped, found
|
||||||
|
}
|
||||||
|
if isInitSchemaNeededForNamespaceScopeCheck() {
|
||||||
|
initSchema()
|
||||||
}
|
}
|
||||||
return isNamespaceScopedFromSchema(typeMeta)
|
|
||||||
}
|
|
||||||
|
|
||||||
func isNamespaceScopedFromSchema(typeMeta yaml.TypeMeta) (bool, bool) {
|
|
||||||
initSchema()
|
|
||||||
isNamespaceScoped, found := globalSchema.namespaceabilityByResourceType[typeMeta]
|
isNamespaceScoped, found := globalSchema.namespaceabilityByResourceType[typeMeta]
|
||||||
return isNamespaceScoped, found
|
return isNamespaceScoped, found
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isInitSchemaNeededForNamespaceScopeCheck returns true if initSchema is needed
|
||||||
|
// to ensure globalSchema.namespaceabilityByResourceType is fully populated for
|
||||||
|
// cases where a custom or non-default built-in schema is in use.
|
||||||
|
func isInitSchemaNeededForNamespaceScopeCheck() bool {
|
||||||
|
schemaLock.Lock()
|
||||||
|
defer schemaLock.Unlock()
|
||||||
|
|
||||||
|
if globalSchema.schemaInit {
|
||||||
|
return false // globalSchema already is initialized.
|
||||||
|
}
|
||||||
|
if customSchema != nil {
|
||||||
|
return true // initSchema is needed.
|
||||||
|
}
|
||||||
|
if kubernetesOpenAPIVersion == "" || kubernetesOpenAPIVersion == kubernetesOpenAPIDefaultVersion {
|
||||||
|
// The default built-in schema is in use. Since
|
||||||
|
// precomputedIsNamespaceScoped aligns with the default built-in schema
|
||||||
|
// (verified by TestIsNamespaceScopedPrecompute), there is no need to
|
||||||
|
// call initSchema.
|
||||||
|
if globalSchema.defaultBuiltInSchemaParseStatus == schemaNotParsed {
|
||||||
|
// The schema may be needed for purposes other than namespace scope
|
||||||
|
// checks. Flag it to be parsed when that need arises.
|
||||||
|
globalSchema.defaultBuiltInSchemaParseStatus = schemaParseDelayed
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// A non-default built-in schema is in use. initSchema is needed.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// IsCertainlyClusterScoped returns true for Node, Namespace, etc. and
|
// IsCertainlyClusterScoped returns true for Node, Namespace, etc. and
|
||||||
// false for Pod, Deployment, etc. and kinds that aren't recognized in the
|
// false for Pod, Deployment, etc. and kinds that aren't recognized in the
|
||||||
// openapi data. See:
|
// openapi data. See:
|
||||||
@@ -638,13 +679,19 @@ func initSchema() {
|
|||||||
panic(fmt.Errorf("invalid schema file: %w", err))
|
panic(fmt.Errorf("invalid schema file: %w", err))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if kubernetesOpenAPIVersion == "" {
|
if kubernetesOpenAPIVersion == "" || kubernetesOpenAPIVersion == kubernetesOpenAPIDefaultVersion {
|
||||||
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
|
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
|
||||||
|
globalSchema.defaultBuiltInSchemaParseStatus = schemaParsed
|
||||||
} else {
|
} else {
|
||||||
parseBuiltinSchema(kubernetesOpenAPIVersion)
|
parseBuiltinSchema(kubernetesOpenAPIVersion)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if globalSchema.defaultBuiltInSchemaParseStatus == schemaParseDelayed {
|
||||||
|
parseBuiltinSchema(kubernetesOpenAPIDefaultVersion)
|
||||||
|
globalSchema.defaultBuiltInSchemaParseStatus = schemaParsed
|
||||||
|
}
|
||||||
|
|
||||||
if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName), JsonOrYaml); err != nil {
|
if err := parse(kustomizationapi.MustAsset(kustomizationAPIAssetName), JsonOrYaml); err != nil {
|
||||||
// this should never happen
|
// this should never happen
|
||||||
panic(err)
|
panic(err)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
openapi_v2 "github.com/google/gnostic-models/openapiv2"
|
openapi_v2 "github.com/google/gnostic-models/openapiv2"
|
||||||
"google.golang.org/protobuf/proto"
|
"google.golang.org/protobuf/proto"
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi"
|
"sigs.k8s.io/kustomize/kyaml/openapi/kubernetesapi"
|
||||||
|
"sigs.k8s.io/kustomize/kyaml/yaml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkProtoUnmarshal(t *testing.B) {
|
func BenchmarkProtoUnmarshal(t *testing.B) {
|
||||||
@@ -31,3 +32,19 @@ func BenchmarkProtoUnmarshal(t *testing.B) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkPrecomputedIsNamespaceScoped(b *testing.B) {
|
||||||
|
testcases := map[string]yaml.TypeMeta{
|
||||||
|
"namespace scoped": {APIVersion: "apps/v1", Kind: "ControllerRevision"},
|
||||||
|
"cluster scoped": {APIVersion: "rbac.authorization.k8s.io/v1", Kind: "ClusterRole"},
|
||||||
|
"unknown resource": {APIVersion: "custom.io/v1", Kind: "Custom"},
|
||||||
|
}
|
||||||
|
for name, testcase := range testcases {
|
||||||
|
b.Run(name, func(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
ResetOpenAPI()
|
||||||
|
_, _ = IsNamespaceScoped(testcase)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,302 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package setters2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"reflect"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Add creates or updates setter or substitution references from resource fields.
|
|
||||||
// Requires that at least one of FieldValue and FieldName have been set.
|
|
||||||
type Add struct {
|
|
||||||
// FieldValue if set will add the OpenAPI reference to fields if they have this value.
|
|
||||||
// Optional. If unspecified match all field values.
|
|
||||||
FieldValue string
|
|
||||||
|
|
||||||
// FieldName if set will add the OpenAPI reference to fields with this name or path
|
|
||||||
// FieldName may be the full name of the field, full path to the field, or the path suffix.
|
|
||||||
// e.g. all of the following would match spec.template.spec.containers.image --
|
|
||||||
// [image, containers.image, spec.containers.image, template.spec.containers.image,
|
|
||||||
// spec.template.spec.containers.image]
|
|
||||||
// Optional. If unspecified match all field names.
|
|
||||||
FieldName string
|
|
||||||
|
|
||||||
// Ref is the OpenAPI reference to set on the matching fields as a comment.
|
|
||||||
Ref string
|
|
||||||
|
|
||||||
// ListValues are the value of a list setter.
|
|
||||||
ListValues []string
|
|
||||||
|
|
||||||
// Type is the type of the setter value
|
|
||||||
Type string
|
|
||||||
|
|
||||||
// Count is the number of fields the setter applies to
|
|
||||||
Count int
|
|
||||||
|
|
||||||
SettersSchema *spec.Schema
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter implements yaml.Filter
|
|
||||||
func (a *Add) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|
||||||
if a.FieldName == "" && a.FieldValue == "" {
|
|
||||||
return nil, errors.Errorf("must specify either fieldName or fieldValue")
|
|
||||||
}
|
|
||||||
if a.Ref == "" {
|
|
||||||
return nil, errors.Errorf("must specify ref")
|
|
||||||
}
|
|
||||||
return object, accept(a, object, a.SettersSchema)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *Add) visitSequence(_ *yaml.RNode, _ string, _ *openapi.ResourceSchema) error {
|
|
||||||
// no-op
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// visitMapping implements visitor
|
|
||||||
// visitMapping visits the fields in input MappingNode and adds setter/subst ref
|
|
||||||
// if the path path spec matches with input FiledName
|
|
||||||
func (a *Add) visitMapping(object *yaml.RNode, p string, _ *openapi.ResourceSchema) error {
|
|
||||||
return object.VisitFields(func(node *yaml.MapNode) error {
|
|
||||||
if node.Value.YNode().Kind != yaml.SequenceNode {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
key, err := node.Key.String()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// derive the list values for the sequence node to write it to openAPI definitions
|
|
||||||
var values []string
|
|
||||||
for _, sc := range node.Value.Content() {
|
|
||||||
values = append(values, sc.Value)
|
|
||||||
}
|
|
||||||
|
|
||||||
// pathToKey refers to the path address of the key node ex: metadata.annotations
|
|
||||||
// p is the path till parent node, pathToKey is obtained by appending child key
|
|
||||||
pathToKey := p + "." + strings.Trim(key, "\n")
|
|
||||||
if a.FieldName != "" && strings.HasSuffix(pathToKey, a.FieldName) {
|
|
||||||
// check if there are different values for field path before adding ref to the field
|
|
||||||
if len(a.ListValues) > 0 && !reflect.DeepEqual(values, a.ListValues) {
|
|
||||||
return errors.Errorf("setters can only be created for fields with same values, "+
|
|
||||||
"encountered different array values for specified field path: %s, %s", values, a.ListValues)
|
|
||||||
}
|
|
||||||
a.ListValues = values
|
|
||||||
a.Count++
|
|
||||||
return a.addRef(node.Key)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// visitScalar implements visitor
|
|
||||||
// visitScalar will set the field metadata on each scalar field whose name + value match
|
|
||||||
func (a *Add) visitScalar(object *yaml.RNode, p string, _, _ *openapi.ResourceSchema) error {
|
|
||||||
// check if the field matches
|
|
||||||
if a.Type == "array" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if a.FieldName != "" && !strings.HasSuffix(p, a.FieldName) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if a.FieldValue != "" && a.FieldValue != object.YNode().Value {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
a.Count++
|
|
||||||
return a.addRef(object)
|
|
||||||
}
|
|
||||||
|
|
||||||
// addRef adds the setter/subst ref to the object node as a line comment
|
|
||||||
func (a *Add) addRef(object *yaml.RNode) error {
|
|
||||||
// read the field metadata
|
|
||||||
fm := fieldmeta.FieldMeta{SettersSchema: a.SettersSchema}
|
|
||||||
if err := fm.Read(object); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the ref on the field metadata
|
|
||||||
r, err := spec.NewRef(a.Ref)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fm.Schema.Ref = r
|
|
||||||
|
|
||||||
// write the field metadata
|
|
||||||
if err := fm.Write(object); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetterDefinition may be used to update a files OpenAPI definitions with a new setter.
|
|
||||||
type SetterDefinition struct {
|
|
||||||
// Name is the name of the setter to create or update.
|
|
||||||
Name string `yaml:"name"`
|
|
||||||
|
|
||||||
// Value is the value of the setter.
|
|
||||||
Value string `yaml:"value"`
|
|
||||||
|
|
||||||
// ListValues are the value of a list setter.
|
|
||||||
ListValues []string `yaml:"listValues,omitempty"`
|
|
||||||
|
|
||||||
// SetBy is the person or role that last set the value.
|
|
||||||
SetBy string `yaml:"setBy,omitempty"`
|
|
||||||
|
|
||||||
// Description is a description of the value.
|
|
||||||
Description string `yaml:"description,omitempty"`
|
|
||||||
|
|
||||||
// Count is the number of fields set by this setter.
|
|
||||||
Count int `yaml:"count,omitempty"`
|
|
||||||
|
|
||||||
// Type is the type of the setter value.
|
|
||||||
Type string `yaml:"type,omitempty"`
|
|
||||||
|
|
||||||
// Schema is the openAPI schema for setter constraints.
|
|
||||||
Schema string `yaml:"schema,omitempty"`
|
|
||||||
|
|
||||||
// EnumValues is a map of possible setter values to actual field values.
|
|
||||||
// If EnumValues is specified, then the value set the by user 1) MUST
|
|
||||||
// be present in the enumValues map as a key, and 2) the map entry value
|
|
||||||
// MUST be used as the value to set in the configuration (rather than the key)
|
|
||||||
// Example -- may be used for t-shirt sizing values by allowing cpu to be
|
|
||||||
// set to small, medium or large, and then mapping these values to cpu values -- 0.5, 2, 8
|
|
||||||
EnumValues map[string]string `yaml:"enumValues,omitempty"`
|
|
||||||
|
|
||||||
// Required indicates that the setter must be set by package consumer before
|
|
||||||
// live apply/preview. This field is added to the setter definition to record
|
|
||||||
// the package publisher's intent to make the setter required to be set.
|
|
||||||
Required bool `yaml:"required,omitempty"`
|
|
||||||
|
|
||||||
// IsSet indicates the specified field has been explicitly assigned.
|
|
||||||
IsSet bool `yaml:"isSet,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sd SetterDefinition) AddToFile(path string) error {
|
|
||||||
return yaml.UpdateFile(sd, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sd SetterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|
||||||
key := fieldmeta.SetterDefinitionPrefix + sd.Name
|
|
||||||
|
|
||||||
definitions, err := object.Pipe(yaml.LookupCreate(
|
|
||||||
yaml.MappingNode, openapi.SupplementaryOpenAPIFieldName, "definitions"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
setterDef, err := definitions.Pipe(yaml.LookupCreate(yaml.MappingNode, key))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if sd.Schema != "" {
|
|
||||||
schNode, err := yaml.ConvertJSONToYamlNode(sd.Schema)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = definitions.PipeE(yaml.SetField(key, schNode))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// don't write the schema to the extension
|
|
||||||
sd.Schema = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if sd.Description != "" {
|
|
||||||
err = setterDef.PipeE(yaml.FieldSetter{Name: "description", StringValue: sd.Description})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// don't write the description to the extension
|
|
||||||
sd.Description = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
if sd.Type != "" {
|
|
||||||
err = setterDef.PipeE(yaml.FieldSetter{Name: "type", StringValue: sd.Type})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// don't write the type to the extension
|
|
||||||
sd.Type = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
ext, err := setterDef.Pipe(yaml.LookupCreate(yaml.MappingNode, K8sCliExtensionKey))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := yaml.Marshal(sd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
y, err := yaml.Parse(string(b))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := ext.PipeE(yaml.SetField("setter", y)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return object, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetterDefinition may be used to update a files OpenAPI definitions with a new substitution.
|
|
||||||
type SubstitutionDefinition struct {
|
|
||||||
// Name is the name of the substitution to create or update
|
|
||||||
Name string `yaml:"name"`
|
|
||||||
|
|
||||||
// Pattern is the substitution pattern into which setter values are substituted
|
|
||||||
Pattern string `yaml:"pattern"`
|
|
||||||
|
|
||||||
// Values are setters which are substituted into pattern to produce a field value
|
|
||||||
Values []Value `yaml:"values"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Value struct {
|
|
||||||
// Marker is the string marker in pattern that is replace by the referenced setter.
|
|
||||||
Marker string `yaml:"marker"`
|
|
||||||
|
|
||||||
// Ref is a reference to a setter to pull the replacement value from.
|
|
||||||
Ref string `yaml:"ref"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sd SubstitutionDefinition) AddToFile(path string) error {
|
|
||||||
return yaml.UpdateFile(sd, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sd SubstitutionDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|
||||||
// create the substitution extension value by marshalling the SubstitutionDefinition itself
|
|
||||||
b, err := yaml.Marshal(sd)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sub, err := yaml.Parse(string(b))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// lookup or create the definition for the substitution
|
|
||||||
defKey := fieldmeta.SubstitutionDefinitionPrefix + sd.Name
|
|
||||||
def, err := object.Pipe(yaml.LookupCreate(
|
|
||||||
yaml.MappingNode, openapi.SupplementaryOpenAPIFieldName, "definitions", defKey, "x-k8s-cli"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the substitution on the definition
|
|
||||||
if err := def.PipeE(yaml.SetField("substitution", sub)); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return object, nil
|
|
||||||
}
|
|
||||||
@@ -1,414 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package setters2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAdd_Filter(t *testing.T) {
|
|
||||||
var tests = []struct {
|
|
||||||
name string
|
|
||||||
add Add
|
|
||||||
input string
|
|
||||||
expected string
|
|
||||||
err string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
name: "add-replicas",
|
|
||||||
add: Add{
|
|
||||||
FieldValue: "3",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.replicas",
|
|
||||||
},
|
|
||||||
input: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
spec:
|
|
||||||
replicas: 3 # {"$openapi":"replicas"}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "add-replicas-annotations",
|
|
||||||
add: Add{
|
|
||||||
FieldValue: "3",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.replicas",
|
|
||||||
},
|
|
||||||
input: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
something: 3
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
something: 3 # {"$openapi":"replicas"}
|
|
||||||
spec:
|
|
||||||
replicas: 3 # {"$openapi":"replicas"}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "add-replicas-name",
|
|
||||||
add: Add{
|
|
||||||
FieldValue: "3",
|
|
||||||
FieldName: "replicas",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.replicas",
|
|
||||||
},
|
|
||||||
input: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
something: 3
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
something: 3
|
|
||||||
spec:
|
|
||||||
replicas: 3 # {"$openapi":"replicas"}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "add-replicas-2x",
|
|
||||||
add: Add{
|
|
||||||
FieldValue: "3",
|
|
||||||
FieldName: "replicas",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.replicas",
|
|
||||||
},
|
|
||||||
input: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
replicas: 3
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
replicas: 3 # {"$openapi":"replicas"}
|
|
||||||
spec:
|
|
||||||
replicas: 3 # {"$openapi":"replicas"}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "add-replicas-1x",
|
|
||||||
add: Add{
|
|
||||||
FieldValue: "3",
|
|
||||||
FieldName: "spec.replicas",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.replicas",
|
|
||||||
},
|
|
||||||
input: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
replicas: 3
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
replicas: 3
|
|
||||||
spec:
|
|
||||||
replicas: 3 # {"$openapi":"replicas"}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "add-field-inside-sequence",
|
|
||||||
add: Add{
|
|
||||||
FieldValue: "/usr/share/nginx",
|
|
||||||
FieldName: "spec.containers.volumeMounts.mountPath",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.mountPath",
|
|
||||||
},
|
|
||||||
input: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx
|
|
||||||
volumeMounts:
|
|
||||||
- name: nginx
|
|
||||||
mountPath: /usr/share/nginx
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: nginx
|
|
||||||
image: nginx
|
|
||||||
volumeMounts:
|
|
||||||
- name: nginx
|
|
||||||
mountPath: /usr/share/nginx # {"$openapi":"mountPath"}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "add-replicas-error",
|
|
||||||
add: Add{
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.replicas",
|
|
||||||
},
|
|
||||||
err: "must specify either fieldName or fieldValue",
|
|
||||||
input: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "ref has . in name of setter",
|
|
||||||
add: Add{
|
|
||||||
FieldValue: "3",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.foo.bar",
|
|
||||||
},
|
|
||||||
input: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`,
|
|
||||||
expected: `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
spec:
|
|
||||||
replicas: 3 # {"$openapi":"foo.bar"}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for i := range tests {
|
|
||||||
test := tests[i]
|
|
||||||
t.Run(test.name, func(t *testing.T) {
|
|
||||||
// parse the input to be modified
|
|
||||||
r, err := yaml.Parse(test.input)
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// invoke add
|
|
||||||
result, err := test.add.Filter(r)
|
|
||||||
if test.err != "" {
|
|
||||||
if !assert.Equal(t, test.err, err.Error()) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// compare the actual and expected output
|
|
||||||
actual, err := result.String()
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
actual = strings.TrimSpace(actual)
|
|
||||||
expected := strings.TrimSpace(test.expected)
|
|
||||||
if !assert.Equal(t, expected, actual) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var resourcefile = `apiVersion: resource.dev/v1alpha1
|
|
||||||
kind: resourcefile
|
|
||||||
metadata:
|
|
||||||
name: hello-world-set
|
|
||||||
upstream:
|
|
||||||
type: git
|
|
||||||
git:
|
|
||||||
commit: 5c1c019b59299a4f6c7edd1ff5ff54d720621bbe
|
|
||||||
directory: /package-examples/helloworld-set
|
|
||||||
ref: v0.1.0
|
|
||||||
packageMetadata:
|
|
||||||
shortDescription: example package using setters`
|
|
||||||
|
|
||||||
func TestAdd_Filter2(t *testing.T) {
|
|
||||||
path := filepath.Join(os.TempDir(), "resourcefile")
|
|
||||||
|
|
||||||
// write initial resourcefile to temp path
|
|
||||||
err := os.WriteFile(path, []byte(resourcefile), 0644)
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a setter definition
|
|
||||||
sd := SetterDefinition{
|
|
||||||
Name: "image",
|
|
||||||
Value: "1",
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sd.AddToFile(path)
|
|
||||||
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// update setter definition
|
|
||||||
sd2 := SetterDefinition{
|
|
||||||
Name: "image",
|
|
||||||
Value: "2",
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sd2.AddToFile(path)
|
|
||||||
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := `apiVersion: resource.dev/v1alpha1
|
|
||||||
kind: resourcefile
|
|
||||||
metadata:
|
|
||||||
name: hello-world-set
|
|
||||||
upstream:
|
|
||||||
type: git
|
|
||||||
git:
|
|
||||||
commit: 5c1c019b59299a4f6c7edd1ff5ff54d720621bbe
|
|
||||||
directory: /package-examples/helloworld-set
|
|
||||||
ref: v0.1.0
|
|
||||||
packageMetadata:
|
|
||||||
shortDescription: example package using setters
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.image:
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: image
|
|
||||||
value: "2"
|
|
||||||
`
|
|
||||||
assert.Equal(t, expected, string(b))
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAddUpdateSubstitution(t *testing.T) {
|
|
||||||
path := filepath.Join(os.TempDir(), "resourcefile")
|
|
||||||
|
|
||||||
// write initial resourcefile to temp path
|
|
||||||
err := os.WriteFile(path, []byte(resourcefile), 0644)
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
value1 := Value{
|
|
||||||
Marker: "IMAGE_NAME",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.image-name",
|
|
||||||
}
|
|
||||||
|
|
||||||
value2 := Value{
|
|
||||||
Marker: "IMAGE_TAG",
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.image-tag",
|
|
||||||
}
|
|
||||||
|
|
||||||
values := []Value{value1, value2}
|
|
||||||
|
|
||||||
// add a setter definition
|
|
||||||
subd := SubstitutionDefinition{
|
|
||||||
Name: "image",
|
|
||||||
Pattern: "IMAGE_NAME:IMAGE_TAG",
|
|
||||||
Values: values,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = subd.AddToFile(path)
|
|
||||||
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// update setter definition
|
|
||||||
subd2 := SubstitutionDefinition{
|
|
||||||
Name: "image",
|
|
||||||
Pattern: "IMAGE_NAME:IMAGE_TAG2",
|
|
||||||
}
|
|
||||||
|
|
||||||
err = subd2.AddToFile(path)
|
|
||||||
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := `apiVersion: resource.dev/v1alpha1
|
|
||||||
kind: resourcefile
|
|
||||||
metadata:
|
|
||||||
name: hello-world-set
|
|
||||||
upstream:
|
|
||||||
type: git
|
|
||||||
git:
|
|
||||||
commit: 5c1c019b59299a4f6c7edd1ff5ff54d720621bbe
|
|
||||||
directory: /package-examples/helloworld-set
|
|
||||||
ref: v0.1.0
|
|
||||||
packageMetadata:
|
|
||||||
shortDescription: example package using setters
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.substitutions.image:
|
|
||||||
x-k8s-cli:
|
|
||||||
substitution:
|
|
||||||
name: image
|
|
||||||
pattern: IMAGE_NAME:IMAGE_TAG2
|
|
||||||
values: []
|
|
||||||
`
|
|
||||||
assert.Equal(t, expected, string(b))
|
|
||||||
}
|
|
||||||
@@ -1,171 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package setters2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/openapi"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Delete delete openAPI definition references from resource fields.
|
|
||||||
type Delete struct {
|
|
||||||
// Name is the name of the openAPI definition to delete.
|
|
||||||
Name string
|
|
||||||
|
|
||||||
// DefinitionPrefix is the prefix of the OpenAPI definition type
|
|
||||||
DefinitionPrefix string
|
|
||||||
|
|
||||||
SettersSchema *spec.Schema
|
|
||||||
}
|
|
||||||
|
|
||||||
// Filter implements yaml.Filter
|
|
||||||
func (d *Delete) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|
||||||
return object, accept(d, object, d.SettersSchema)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Delete) visitSequence(_ *yaml.RNode, _ string, _ *openapi.ResourceSchema) error {
|
|
||||||
// no-op
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Delete) visitMapping(object *yaml.RNode, _ string, _ *openapi.ResourceSchema) error {
|
|
||||||
fieldRNodes, err := object.FieldRNodes()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// for each of the field node key visit it as scalar to delete the array setter comment
|
|
||||||
for _, fieldRNode := range fieldRNodes {
|
|
||||||
err := d.visitScalar(fieldRNode, "", nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// visitScalar implements visitor
|
|
||||||
// visitScalar will remove the reference on each scalar field whose name matches.
|
|
||||||
func (d *Delete) visitScalar(object *yaml.RNode, _ string, _, _ *openapi.ResourceSchema) error {
|
|
||||||
// read the field metadata
|
|
||||||
fm := fieldmeta.FieldMeta{SettersSchema: d.SettersSchema}
|
|
||||||
if err := fm.Read(object); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the reference iff the ref string matches with DefinitionPrefix
|
|
||||||
if strings.HasSuffix(fm.Schema.Ref.String(), d.DefinitionPrefix+d.Name) {
|
|
||||||
// remove the ref on the metadata
|
|
||||||
fm.Schema.Ref = spec.Ref{}
|
|
||||||
|
|
||||||
// write the field metadata
|
|
||||||
if err := fm.Write(object); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleterDefinition may be used to update a files OpenAPI definitions with a new setter.
|
|
||||||
type DeleterDefinition struct {
|
|
||||||
// Name is the name of the openAPI definition to delete.
|
|
||||||
Name string `yaml:"name"`
|
|
||||||
|
|
||||||
// DefinitionPrefix is the prefix of the OpenAPI definition type
|
|
||||||
DefinitionPrefix string `yaml:"definitionPrefix"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dd DeleterDefinition) DeleteFromFile(path string) error {
|
|
||||||
return yaml.UpdateFile(dd, path)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SubstReferringDefinition check if the definition used in substitution and return the substitution name if true
|
|
||||||
func SubstReferringDefinition(definitions *yaml.RNode, key string) string {
|
|
||||||
fieldNames, err := definitions.Fields()
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
for _, fieldName := range fieldNames {
|
|
||||||
// the definition key -- contains the substitution name
|
|
||||||
subkey := definitions.Field(fieldName).Key.YNode().Value
|
|
||||||
if strings.HasPrefix(subkey, fieldmeta.SubstitutionDefinitionPrefix) {
|
|
||||||
substNode, err := definitions.Field(fieldName).Value.Pipe(yaml.Lookup(K8sCliExtensionKey, "substitution"))
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := substNode.MarshalJSON()
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
subst := SubstitutionDefinition{}
|
|
||||||
if err := yaml.Unmarshal(b, &subst); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Check the ref in value to see if it contains the setter key
|
|
||||||
for _, v := range subst.Values {
|
|
||||||
if strings.HasSuffix(v.Ref, key) {
|
|
||||||
return subst.Name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (dd DeleterDefinition) Filter(object *yaml.RNode) (*yaml.RNode, error) {
|
|
||||||
key := dd.DefinitionPrefix + dd.Name
|
|
||||||
var defType string
|
|
||||||
|
|
||||||
switch dd.DefinitionPrefix {
|
|
||||||
case fieldmeta.SubstitutionDefinitionPrefix:
|
|
||||||
defType = "substitution"
|
|
||||||
case fieldmeta.SetterDefinitionPrefix:
|
|
||||||
defType = "setter"
|
|
||||||
default:
|
|
||||||
return nil, errors.Errorf("the input delete definitionPrefix does't match any of openAPI definitions, "+
|
|
||||||
"allowed values [%s, %s]", fieldmeta.SetterDefinitionPrefix, fieldmeta.SubstitutionDefinitionPrefix)
|
|
||||||
}
|
|
||||||
|
|
||||||
definitions, err := object.Pipe(yaml.Lookup(openapi.SupplementaryOpenAPIFieldName, "definitions"))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// return error if the setter to be deleted doesn't exist
|
|
||||||
if definitions == nil || definitions.Field(key) == nil {
|
|
||||||
return nil, errors.Errorf("%s %q does not exist", defType, dd.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
subst := SubstReferringDefinition(definitions, key)
|
|
||||||
|
|
||||||
if subst != "" {
|
|
||||||
return nil, errors.Errorf("%s %q is used in substitution %q, please delete the parent substitution first", defType, dd.Name, subst)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = definitions.Pipe(yaml.FieldClearer{Name: key})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// remove definitions if it's empty
|
|
||||||
_, err = object.Pipe(yaml.Lookup(openapi.SupplementaryOpenAPIFieldName), yaml.FieldClearer{Name: "definitions", IfEmpty: true})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// remove openApi if it's empty
|
|
||||||
_, err = object.Pipe(yaml.FieldClearer{Name: openapi.SupplementaryOpenAPIFieldName, IfEmpty: true})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return object, nil
|
|
||||||
}
|
|
||||||
@@ -1,87 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package setters2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
|
||||||
)
|
|
||||||
|
|
||||||
var resourcefile2 = `apiVersion: resource.dev/v1alpha1
|
|
||||||
kind: resourcefile
|
|
||||||
metadata:
|
|
||||||
name: hello-world-set
|
|
||||||
upstream:
|
|
||||||
type: git
|
|
||||||
git:
|
|
||||||
commit: 5c1c019b59299a4f6c7edd1ff5ff54d720621bbe
|
|
||||||
directory: /package-examples/helloworld-set
|
|
||||||
ref: v0.1.0
|
|
||||||
packageMetadata:
|
|
||||||
shortDescription: example package using setters
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.image:
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: image
|
|
||||||
value: "2"
|
|
||||||
io.k8s.cli.setters.tag:
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: tag
|
|
||||||
value: "sometag"
|
|
||||||
`
|
|
||||||
|
|
||||||
func TestDelete_Filter2(t *testing.T) {
|
|
||||||
path := filepath.Join(os.TempDir(), "resourcefile2")
|
|
||||||
|
|
||||||
// write initial resourcefile to temp path
|
|
||||||
err := os.WriteFile(path, []byte(resourcefile2), 0644)
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
// add a deleter definition
|
|
||||||
dd := DeleterDefinition{
|
|
||||||
Name: "image",
|
|
||||||
DefinitionPrefix: fieldmeta.SetterDefinitionPrefix,
|
|
||||||
}
|
|
||||||
|
|
||||||
err = dd.DeleteFromFile(path)
|
|
||||||
if !assert.NoError(t, err) {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
t.FailNow()
|
|
||||||
}
|
|
||||||
|
|
||||||
expected := `apiVersion: resource.dev/v1alpha1
|
|
||||||
kind: resourcefile
|
|
||||||
metadata:
|
|
||||||
name: hello-world-set
|
|
||||||
upstream:
|
|
||||||
type: git
|
|
||||||
git:
|
|
||||||
commit: 5c1c019b59299a4f6c7edd1ff5ff54d720621bbe
|
|
||||||
directory: /package-examples/helloworld-set
|
|
||||||
ref: v0.1.0
|
|
||||||
packageMetadata:
|
|
||||||
shortDescription: example package using setters
|
|
||||||
openAPI:
|
|
||||||
definitions:
|
|
||||||
io.k8s.cli.setters.tag:
|
|
||||||
x-k8s-cli:
|
|
||||||
setter:
|
|
||||||
name: tag
|
|
||||||
value: "sometag"
|
|
||||||
`
|
|
||||||
assert.Equal(t, expected, string(b))
|
|
||||||
}
|
|
||||||
@@ -1,163 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
//
|
|
||||||
// Package setters2 contains libraries for setting resource field values from OpenAPI setter
|
|
||||||
// extensions.
|
|
||||||
//
|
|
||||||
// Setters
|
|
||||||
//
|
|
||||||
// Setters are used to programmatically set configuration field values -- e.g. through a cli or ui.
|
|
||||||
//
|
|
||||||
// Setters are defined through OpenAPI definitions using the x-k8s-cli extension.
|
|
||||||
// Note: additional OpenAPI definitions may be registered through openapi.AddSchema([]byte)
|
|
||||||
//
|
|
||||||
// Example OpenAPI schema containing a setter:
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// "definitions": {
|
|
||||||
// "io.k8s.cli.setters.replicas": {
|
|
||||||
// "x-k8s-cli": {
|
|
||||||
// "setter": {
|
|
||||||
// "name": "replicas",
|
|
||||||
// "value": "4"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Setter fields:
|
|
||||||
//
|
|
||||||
// x-k8s-cli.setter.name: name of the setter
|
|
||||||
// x-k8s-cli.setter.value: value of the setter that should be applied to fields
|
|
||||||
//
|
|
||||||
// The setter definition key must be of the form "io.k8s.cli.setters.NAME", where NAME matches the
|
|
||||||
// value of "x-k8s-cli.setter.name".
|
|
||||||
//
|
|
||||||
// When Set.Filter is called, the named setter will have its value applied to all resource
|
|
||||||
// fields referencing it.
|
|
||||||
//
|
|
||||||
// Fields may reference setters through a yaml comment containing the serialized JSON OpenAPI.
|
|
||||||
//
|
|
||||||
// Example Deployment resource with a "spec.replicas" field set by the "replicas" setter:
|
|
||||||
//
|
|
||||||
// apiVersion: apps/v1
|
|
||||||
// kind: Deployment
|
|
||||||
// metadata:
|
|
||||||
// name: nginx-deployment
|
|
||||||
// spec:
|
|
||||||
// replicas: 4 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
|
|
||||||
//
|
|
||||||
// If the OpenAPI io.k8s.cli.setters.replicas x-k8s-cli.setter.value was changed from "4" to "5",
|
|
||||||
// then calling Set{Name: "replicas"}.Filter(deployment) would update the Deployment spec.replicas
|
|
||||||
// value from 4 to 5.
|
|
||||||
//
|
|
||||||
// Updated OpenAPI:
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// "definitions": {
|
|
||||||
// "io.k8s.cli.setters.replicas": {
|
|
||||||
// "x-k8s-cli": {
|
|
||||||
// "setter": {
|
|
||||||
// "name": "replicas",
|
|
||||||
// "value": "5"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Updated Deployment Configuration:
|
|
||||||
//
|
|
||||||
// apiVersion: apps/v1
|
|
||||||
// kind: Deployment
|
|
||||||
// metadata:
|
|
||||||
// name: nginx-deployment
|
|
||||||
// spec:
|
|
||||||
// replicas: 5 # {"$ref": "#/definitions/io.k8s.cli.setters.replicas"}
|
|
||||||
//
|
|
||||||
// Substitutions
|
|
||||||
//
|
|
||||||
// Substitutions are used to programmatically set configuration field values using multiple
|
|
||||||
// setters which are substituted into a pattern string.
|
|
||||||
//
|
|
||||||
// Substitutions may be used when a field value does not cleanly map to a single setter, but
|
|
||||||
// instead matches some string pattern where setters may be substituted in.
|
|
||||||
//
|
|
||||||
// Fields may reference substitutions the same way they do setters, however substitutions
|
|
||||||
// reference setters from which they are derived.
|
|
||||||
//
|
|
||||||
// Example OpenAPI schema containing a substitution derived from 2 setters:
|
|
||||||
//
|
|
||||||
// {
|
|
||||||
// "definitions": {
|
|
||||||
// "io.k8s.cli.setters.image-name": {
|
|
||||||
// "x-k8s-cli": {
|
|
||||||
// "setter": {
|
|
||||||
// "name": "image-name",
|
|
||||||
// "value": "nginx"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// "io.k8s.cli.setters.image-tag": {
|
|
||||||
// "x-k8s-cli": {
|
|
||||||
// "setter": {
|
|
||||||
// "name": "image-tag",
|
|
||||||
// "value": "1.8.1"
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// "io.k8s.cli.substitutions.image-name-tag": {
|
|
||||||
// "x-k8s-cli": {
|
|
||||||
// "substitution": {
|
|
||||||
// "name": "image-name-tag",
|
|
||||||
// "pattern": "IMAGE_NAME:IMAGE_TAG",
|
|
||||||
// "values": [
|
|
||||||
// {"marker": "IMAGE_NAME", "ref": "#/definitions/io.k8s.cli.setters.image-name"}
|
|
||||||
// {"marker": "IMAGE_TAG", "ref": "#/definitions/io.k8s.cli.setters.image-tag"}
|
|
||||||
// ]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// Substitution Fields.
|
|
||||||
//
|
|
||||||
// x-k8s-cli.substitution.name: name of the substitution
|
|
||||||
// x-k8s-cli.substitution.pattern: string pattern to substitute markers into
|
|
||||||
// x-k8s-cli.substitution.values.marker: the marker substring within pattern to replace
|
|
||||||
// x-k8s-cli.substitution.values.ref: the setter ref containing the value to replace the marker with
|
|
||||||
//
|
|
||||||
// The substitution is composed of a "pattern" containing markers, and a list of setter "values"
|
|
||||||
// which are substituted into the markers.
|
|
||||||
//
|
|
||||||
// Example Deployment with substitution:
|
|
||||||
//
|
|
||||||
// apiVersion: apps/v1
|
|
||||||
// kind: Deployment
|
|
||||||
// metadata:
|
|
||||||
// name: nginx-deployment
|
|
||||||
// spec:
|
|
||||||
// template:
|
|
||||||
// spec:
|
|
||||||
// containers:
|
|
||||||
// - name: nginx
|
|
||||||
// image: nginx:1.8.1 # {"$ref": "#/definitions/io.k8s.cli.substitutions.image-name-tag"}
|
|
||||||
//
|
|
||||||
// spec.template.spec.containers[name=nginx].image is set by the "image" substitution any time
|
|
||||||
// either "image-name" or "image-tag" is set. Whenever any setter referenced by a substitution
|
|
||||||
// is set, the substitution will be recalculated by substituting its values into its pattern.
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// If the OpenAPI io.k8s.cli.setters.image-name x-k8s-cli.setter.value was changed from "1.8.1"
|
|
||||||
// to "1.8.2", then calling either Set{Name: "image-name"}.Filter(deployment) or
|
|
||||||
// Set{Name: "image-tag"}.Filter(deployment) would update the Deployment field
|
|
||||||
// spec.template.spec.container[name=nginx].image from "nginx:1.8.1" to "nginx:1.8.2".
|
|
||||||
//
|
|
||||||
// Adding Field References
|
|
||||||
//
|
|
||||||
// References to setters and substitutions may be added to fields using the Add Filter.
|
|
||||||
// Add will write a JSON OpenAPI string as a comment to any fields matching the specified
|
|
||||||
// FieldName add FieldValue.
|
|
||||||
package setters2
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package setters2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ExampleAdd demonstrates adding a setter reference to fields.
|
|
||||||
func ExampleAdd_fieldName() {
|
|
||||||
deployment := `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
something: 3
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`
|
|
||||||
|
|
||||||
object := yaml.MustParse(deployment) // parse the configuration
|
|
||||||
err := object.PipeE(&Add{
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.replicas",
|
|
||||||
FieldName: "replicas",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the object with the update value
|
|
||||||
fmt.Println(object.MustString())
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// apiVersion: apps/v1
|
|
||||||
// kind: Deployment
|
|
||||||
// metadata:
|
|
||||||
// name: nginx-deployment
|
|
||||||
// annotations:
|
|
||||||
// something: 3
|
|
||||||
// spec:
|
|
||||||
// replicas: 3 # {"$openapi":"replicas"}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExampleAdd demonstrates adding a setter reference to fields.
|
|
||||||
func ExampleAdd_fieldValue() {
|
|
||||||
deployment := `
|
|
||||||
apiVersion: apps/v1
|
|
||||||
kind: Deployment
|
|
||||||
metadata:
|
|
||||||
name: nginx-deployment
|
|
||||||
annotations:
|
|
||||||
something: 3
|
|
||||||
spec:
|
|
||||||
replicas: 3
|
|
||||||
`
|
|
||||||
|
|
||||||
object := yaml.MustParse(deployment) // parse the configuration
|
|
||||||
err := object.PipeE(&Add{
|
|
||||||
Ref: "#/definitions/io.k8s.cli.setters.replicas",
|
|
||||||
FieldValue: "3",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print the object with the update value
|
|
||||||
fmt.Println(object.MustString())
|
|
||||||
|
|
||||||
// Output:
|
|
||||||
// apiVersion: apps/v1
|
|
||||||
// kind: Deployment
|
|
||||||
// metadata:
|
|
||||||
// name: nginx-deployment
|
|
||||||
// annotations:
|
|
||||||
// something: 3 # {"$openapi":"replicas"}
|
|
||||||
// spec:
|
|
||||||
// replicas: 3 # {"$openapi":"replicas"}
|
|
||||||
}
|
|
||||||
@@ -1,195 +0,0 @@
|
|||||||
// Copyright 2019 The Kubernetes Authors.
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package setters2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"k8s.io/kube-openapi/pkg/validation/spec"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/errors"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/kio"
|
|
||||||
"sigs.k8s.io/kustomize/kyaml/yaml"
|
|
||||||
)
|
|
||||||
|
|
||||||
// List lists the setters specified in the OpenAPI
|
|
||||||
// excludes the subpackages which contain file with
|
|
||||||
// name OpenAPIFileName in them
|
|
||||||
type List struct {
|
|
||||||
Name string
|
|
||||||
|
|
||||||
OpenAPIFileName string
|
|
||||||
|
|
||||||
Setters []SetterDefinition
|
|
||||||
|
|
||||||
Substitutions []SubstitutionDefinition
|
|
||||||
|
|
||||||
SettersSchema *spec.Schema
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListSetters initializes l.Setters with the setters from the OpenAPI definitions in the file
|
|
||||||
func (l *List) ListSetters(openAPIPath, resourcePath string) error {
|
|
||||||
y, err := yaml.ReadFile(openAPIPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return l.listSetters(y, resourcePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListSubst initializes l.Substitutions with the substitutions from the OpenAPI definitions in the file
|
|
||||||
func (l *List) ListSubst(openAPIPath string) error {
|
|
||||||
y, err := yaml.ReadFile(openAPIPath)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return l.listSubst(y)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *List) listSetters(object *yaml.RNode, resourcePath string) error {
|
|
||||||
// read the OpenAPI definitions
|
|
||||||
def, err := object.Pipe(yaml.LookupCreate(yaml.MappingNode, "openAPI", "definitions"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if yaml.IsMissingOrNull(def) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// iterate over definitions -- find those that are setters
|
|
||||||
err = def.VisitFields(func(node *yaml.MapNode) error {
|
|
||||||
setter := SetterDefinition{}
|
|
||||||
|
|
||||||
// the definition key -- contains the setter name
|
|
||||||
key := node.Key.YNode().Value
|
|
||||||
|
|
||||||
if !strings.HasPrefix(key, fieldmeta.SetterDefinitionPrefix) {
|
|
||||||
// not a setter -- doesn't have the right prefix
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
setterNode, err := node.Value.Pipe(yaml.Lookup(K8sCliExtensionKey, "setter"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if yaml.IsMissingOrNull(setterNode) {
|
|
||||||
// has the setter prefix, but missing the setter extension
|
|
||||||
return errors.Errorf("missing x-k8s-cli.setter for %s", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmarshal the yaml for the setter extension into the definition struct
|
|
||||||
b, err := setterNode.String()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := yaml.Unmarshal([]byte(b), &setter); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.Name != "" && l.Name != setter.Name {
|
|
||||||
// not the setter that was requested by list
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// the description is not part of the extension, and should be pulled out
|
|
||||||
// separately from the extension values.
|
|
||||||
description := node.Value.Field("description")
|
|
||||||
if description != nil {
|
|
||||||
setter.Description = description.Value.YNode().Value
|
|
||||||
}
|
|
||||||
|
|
||||||
// count the number of fields set by this setter
|
|
||||||
setter.Count, err = l.count(resourcePath, setter.Name)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Setters = append(l.Setters, setter)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort the setters by their name
|
|
||||||
sort.Slice(l.Setters, func(i, j int) bool {
|
|
||||||
return l.Setters[i].Name < l.Setters[j].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *List) listSubst(object *yaml.RNode) error {
|
|
||||||
// read the OpenAPI definitions
|
|
||||||
def, err := object.Pipe(yaml.LookupCreate(yaml.MappingNode, "openAPI", "definitions"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if yaml.IsMissingOrNull(def) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// iterate over definitions -- find those that are substitutions
|
|
||||||
err = def.VisitFields(func(node *yaml.MapNode) error {
|
|
||||||
subst := SubstitutionDefinition{}
|
|
||||||
|
|
||||||
// the definition key -- contains the substitution name
|
|
||||||
key := node.Key.YNode().Value
|
|
||||||
|
|
||||||
if !strings.HasPrefix(key, fieldmeta.SubstitutionDefinitionPrefix) {
|
|
||||||
// not a substitution -- doesn't have the right prefix
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
substNode, err := node.Value.Pipe(yaml.Lookup(K8sCliExtensionKey, "substitution"))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if yaml.IsMissingOrNull(substNode) {
|
|
||||||
// has the substitution prefix, but missing the setter extension
|
|
||||||
return errors.Errorf("missing x-k8s-cli.substitution for %s", key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// unmarshal the yaml for the substitution extension into the definition struct
|
|
||||||
b, err := substNode.String()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := yaml.Unmarshal([]byte(b), &subst); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if l.Name != "" && l.Name != subst.Name {
|
|
||||||
// not the substitution that was requested by list
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
l.Substitutions = append(l.Substitutions, subst)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// sort the substitutions by their name
|
|
||||||
sort.Slice(l.Substitutions, func(i, j int) bool {
|
|
||||||
return l.Substitutions[i].Name < l.Substitutions[j].Name
|
|
||||||
})
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// count returns the number of fields set by the setter with name
|
|
||||||
// this excludes all the subpackages with openAPI file in them
|
|
||||||
// set filter is leveraged for this but the resources are not written
|
|
||||||
// back to files as only LocalPackageReader is invoked and not writer
|
|
||||||
func (l *List) count(path, name string) (int, error) {
|
|
||||||
s := &Set{Name: name, SettersSchema: l.SettersSchema}
|
|
||||||
err := kio.Pipeline{
|
|
||||||
Inputs: []kio.Reader{&kio.LocalPackageReader{PackagePath: path, PackageFileName: l.OpenAPIFileName}},
|
|
||||||
Filters: []kio.Filter{kio.FilterAll(s)},
|
|
||||||
}.Execute()
|
|
||||||
|
|
||||||
return s.Count, err
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user