mirror of
https://github.com/kubevela/kubevela.git
synced 2026-03-01 17:20:45 +00:00
Compare commits
90 Commits
v1.5.0-alp
...
v1.4.7-pat
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b596b70ebe | ||
|
|
0cd370e867 | ||
|
|
d9adc73e5c | ||
|
|
4a2d9807c8 | ||
|
|
840cb8ce58 | ||
|
|
5a64fec916 | ||
|
|
657a374ded | ||
|
|
dfe12cd9ca | ||
|
|
cd42f67848 | ||
|
|
61d2c588e3 | ||
|
|
b3dad698a5 | ||
|
|
ec5159c2ca | ||
|
|
a7b2b221e0 | ||
|
|
caa495a5d9 | ||
|
|
15bea4fb64 | ||
|
|
1a094a4eea | ||
|
|
65b6f47330 | ||
|
|
3a4cd2dca6 | ||
|
|
9fabd950e5 | ||
|
|
0a012b4d34 | ||
|
|
7c231e6c48 | ||
|
|
36b6c3e7b5 | ||
|
|
4cc019722c | ||
|
|
b040ae65da | ||
|
|
f0fb4ed099 | ||
|
|
7f89d12059 | ||
|
|
3c61bcb8f0 | ||
|
|
a14b536fd1 | ||
|
|
ba5a726854 | ||
|
|
ffb9d06427 | ||
|
|
819dc26ace | ||
|
|
5e3ab732df | ||
|
|
62d5507499 | ||
|
|
c0daf688a6 | ||
|
|
48d19a2427 | ||
|
|
4da8d49e60 | ||
|
|
4db9e89816 | ||
|
|
667053409d | ||
|
|
eb9ddaabd3 | ||
|
|
f11a94612f | ||
|
|
56f9d7cb9c | ||
|
|
fbbc666019 | ||
|
|
d0788254cb | ||
|
|
c72a6aef87 | ||
|
|
195b7fe0c7 | ||
|
|
33c9e3b170 | ||
|
|
ea0508a634 | ||
|
|
23e29aa62a | ||
|
|
ed2cb80219 | ||
|
|
1a3d5debd5 | ||
|
|
d4a82fe292 | ||
|
|
963ae400fa | ||
|
|
8f7a8258fe | ||
|
|
70bc306678 | ||
|
|
57428bbc8d | ||
|
|
e08541ca5c | ||
|
|
521a4edc10 | ||
|
|
82b330710c | ||
|
|
4a649f2cf1 | ||
|
|
f6664106a2 | ||
|
|
bbe2a2dec6 | ||
|
|
404c7f6975 | ||
|
|
2edfbabdab | ||
|
|
e7b304de3b | ||
|
|
b8b54baf26 | ||
|
|
87b6c9416e | ||
|
|
cd171d27db | ||
|
|
6d8be8b061 | ||
|
|
e93912acff | ||
|
|
e48e39987f | ||
|
|
6264a66021 | ||
|
|
9191127e01 | ||
|
|
1b047c10ba | ||
|
|
02a1d390c4 | ||
|
|
62866e19d8 | ||
|
|
3dc645ed52 | ||
|
|
e20ef02a6a | ||
|
|
371affb389 | ||
|
|
b35145be82 | ||
|
|
d92c8844ba | ||
|
|
82aaf5098b | ||
|
|
7399666275 | ||
|
|
0b394e766b | ||
|
|
eb386ce9f7 | ||
|
|
e4fa5a5cf1 | ||
|
|
165e011bd0 | ||
|
|
9489b8d511 | ||
|
|
d95942c992 | ||
|
|
c6aa8ddbbc | ||
|
|
c370ef04f3 |
24
.github/CODEOWNERS
vendored
24
.github/CODEOWNERS
vendored
@@ -1,14 +1,14 @@
|
||||
# This file is a github code protect rule follow the codeowners https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-code-owners#example-of-a-codeowners-file
|
||||
|
||||
* @barnettZQG @wonderflow @leejanee @Somefive
|
||||
design/ @barnettZQG @leejanee @wonderflow @Somefive
|
||||
* @barnettZQG @wonderflow @leejanee
|
||||
design/ @barnettZQG @leejanee @wonderflow
|
||||
|
||||
# Owner of CUE
|
||||
pkg/cue @leejanee @FogDong @Somefive
|
||||
pkg/stdlib @leejanee @FogDong @Somefive
|
||||
pkg/cue @leejanee @FogDong
|
||||
pkg/stdlib @leejanee @FogDong
|
||||
|
||||
# Owner of Workflow
|
||||
pkg/workflow @leejanee @FogDong @Somefive
|
||||
pkg/workflow @leejanee @FogDong
|
||||
|
||||
# Owner of rollout
|
||||
pkg/controller/common/rollout/ @wangyikewxgm @wonderflow
|
||||
@@ -17,20 +17,20 @@ pkg/controller/standard.oam.dev/v1alpha1/rollout @wangyikewxgm @wonde
|
||||
runtime/rollout @wangyikewxgm @wonderflow
|
||||
|
||||
# Owner of definition controller
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/workflow/workflowstepdefinition @yangsoon @Somefive @FogDong
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/policies/policydefinition @yangsoon @Somefive @FogDong
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/components/componentdefinition @yangsoon @zzxwill @Somefive
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/traits/traitdefinition @yangsoon @zzxwill @Somefive
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/workflow/workflowstepdefinition @yangsoon @Somefive
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/policies/policydefinition @yangsoon @Somefive
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/components/componentdefinition @yangsoon @zzxwill
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/traits/traitdefinition @yangsoon @zzxwill
|
||||
|
||||
# Owner of health scope controller
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/scopes/healthscope @captainroy-hy @zzxwill @yangsoon
|
||||
pkg/controller/core.oam.dev/v1alpha2/core/scopes/healthscope @captainroy-hy @zzxwill
|
||||
|
||||
# Owner of vela templates
|
||||
vela-templates/ @Somefive @barnettZQG @wonderflow
|
||||
|
||||
# Owner of vela CLI
|
||||
references/cli/ @Somefive @zzxwill @StevenLeiZhang
|
||||
references/cli/ @Somefive @zzxwill
|
||||
|
||||
# Owner of vela APIServer
|
||||
pkg/apiserver/ @barnettZQG @yangsoon @FogDong
|
||||
pkg/apiserver/ @barnettZQG @yangsoon
|
||||
|
||||
|
||||
10
.github/workflows/issue-commands.yml
vendored
10
.github/workflows/issue-commands.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
|
||||
jobs:
|
||||
bot:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Actions
|
||||
uses: actions/checkout@v2
|
||||
@@ -15,13 +15,7 @@ jobs:
|
||||
repository: "oam-dev/kubevela-github-actions"
|
||||
path: ./actions
|
||||
ref: v0.4.2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: '14'
|
||||
cache: 'npm'
|
||||
cache-dependency-path: ./actions/package-lock.json
|
||||
- name: Install Dependencies
|
||||
- name: Install Actions
|
||||
run: npm ci --production --prefix ./actions
|
||||
- name: Run Commands
|
||||
uses: ./actions/commands
|
||||
|
||||
19
.github/workflows/registry.yml
vendored
19
.github/workflows/registry.yml
vendored
@@ -167,25 +167,6 @@ jobs:
|
||||
docker.io/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
${{ secrets.ACR_DOMAIN }}/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
- uses: docker/build-push-action@v2
|
||||
name: Build & Pushing CloudShell for Dockerhub, GHCR and ACR
|
||||
with:
|
||||
context: .
|
||||
file: Dockerfile.cloudshell
|
||||
labels: |-
|
||||
org.opencontainers.image.source=https://github.com/${{ github.repository }}
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
build-args: |
|
||||
GITVERSION=git-${{ steps.vars.outputs.git_revision }}
|
||||
VERSION=${{ steps.get_version.outputs.VERSION }}
|
||||
GOPROXY=https://proxy.golang.org
|
||||
tags: |-
|
||||
docker.io/oamdev/cloudshell:${{ steps.get_version.outputs.VERSION }}
|
||||
ghcr.io/${{ github.repository_owner }}/oamdev/cloudshell:${{ steps.get_version.outputs.VERSION }}
|
||||
${{ secrets.ACR_DOMAIN }}/oamdev/cloudshell:${{ steps.get_version.outputs.VERSION }}
|
||||
|
||||
publish-capabilities:
|
||||
env:
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,7 +7,6 @@
|
||||
bin
|
||||
_bin
|
||||
e2e/vela
|
||||
vela
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
@@ -50,4 +49,4 @@ tmp/
|
||||
git-page/
|
||||
|
||||
# e2e rollout runtime image build
|
||||
runtime/rollout/e2e/tmp
|
||||
runtime/rollout/e2e/tmp
|
||||
@@ -15,7 +15,7 @@ This is a minor fix for release-1.0, please refer to release-1.1.x for the lates
|
||||
# v1.0.5
|
||||
|
||||
1. Fix Terraform application status issue (#1611)
|
||||
2. application supports specifying different versions of Definition (#1597)
|
||||
2. applicaiton supports specifying different versions of Definition (#1597)
|
||||
3. Enable Dynamic Admission Control for Application (#1619)
|
||||
4. Update inner samples for "vela show xxx --web" (#1616)
|
||||
5. fix empty rolloutBatch will panic whole controller bug (#1646)
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
## What's Changed
|
||||
|
||||
* Fix: can't query data from the MongoDB by @barnettZQG in https://github.com/oam-dev/kubevela/pull/3095
|
||||
* Fix: use personal token of vela-bot instead of github token for homebrew update by @wonderflow in https://github.com/oam-dev/kubevela/pull/3096
|
||||
* Fix: use personel token of vela-bot instead of github token for homebrew update by @wonderflow in https://github.com/oam-dev/kubevela/pull/3096
|
||||
* Fix: acr image no version by @wangyikewxgm in https://github.com/oam-dev/kubevela/pull/3100
|
||||
* Fix: support generate cloud resource docs in Chinese by @zzxwill in https://github.com/oam-dev/kubevela/pull/3079
|
||||
* Fix: clear old data in mongodb unit test case by @barnettZQG in https://github.com/oam-dev/kubevela/pull/3103
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
ARG BASE_IMAGE
|
||||
# Build the cli binary
|
||||
FROM --platform=${BUILDPLATFORM:-linux/amd64} golang:1.17-alpine as builder
|
||||
ARG GOPROXY
|
||||
ENV GOPROXY=${GOPROXY:-https://goproxy.cn}
|
||||
WORKDIR /workspace
|
||||
# Copy the Go Modules manifests
|
||||
COPY go.mod go.mod
|
||||
COPY go.sum go.sum
|
||||
# cache deps before building and copying source so that we don't need to re-download as much
|
||||
# and so that source changes don't invalidate our downloaded layer
|
||||
RUN go mod download
|
||||
|
||||
# Copy the go source
|
||||
COPY apis/ apis/
|
||||
COPY pkg/ pkg/
|
||||
COPY version/ version/
|
||||
COPY references/ references/
|
||||
|
||||
# Build
|
||||
ARG VERSION
|
||||
ARG GITVERSION
|
||||
|
||||
RUN GO111MODULE=on CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
|
||||
go build -a -ldflags "-s -w -X github.com/oam-dev/kubevela/version.VelaVersion=${VERSION:-undefined} -X github.com/oam-dev/kubevela/version.GitRevision=${GITVERSION:-undefined}" \
|
||||
-o vela ./references/cmd/cli/main.go
|
||||
|
||||
FROM ghcr.io/cloudtty/cloudshell:v0.2.0
|
||||
RUN apt-get install -y vim
|
||||
ENV API_TOKEN_PATH=/usr/local/kubeconfig/token
|
||||
COPY --from=builder /workspace/vela /usr/local/bin/vela
|
||||
36
README.md
36
README.md
@@ -21,29 +21,23 @@
|
||||
|
||||
KubeVela is a modern application delivery platform that makes deploying and operating applications across today's hybrid, multi-cloud environments easier, faster and more reliable.
|
||||
|
||||

|
||||

|
||||
|
||||
## Highlights
|
||||
|
||||
KubeVela practices the "render, orchestrate, deploy" workflow with below highlighted values added to existing ecosystem:
|
||||
|
||||
* Deployment as Code
|
||||
- *Application Centric* - KubeVela introduces [Open Application Model (OAM)](https://oam.dev/) as the consistent yet higher level API to capture and render a full deployment of microservices on top of hybrid environments. Placement strategy, traffic shifting and rolling update are declared at application level. No infrastructure level concern, simply deploy.
|
||||
|
||||
Declare your deployment plan as workflow, run it automatically with any CI/CD or GitOps system, extend or re-program the workflow steps with CUE. No add-hoc scripts, no dirty glue code, just deploy. The deployment workflow in KubeVela is powered by [Open Application Model](https://oam.dev/).
|
||||
- *Programmable Workflow* - KubeVela models application delivery as DAG (Directed Acyclic Graph) and expresses it with [CUE](https://cuelang.org/) - a modern data configuration language. This allows you to design application deployment steps per needs and orchestrate them in programmable approach. No restrictions, natively extensible.
|
||||
|
||||
* Built-in security and compliance building blocks
|
||||
|
||||
Choose from the wide range of LDAP integrations we provided out-of-box, enjoy multi-cluster authorization that is fully automated, pick and apply fine-grained RBAC modules and customize them per your own supply chain requirements.
|
||||
|
||||
* Multi-cloud/hybrid-environments app delivery as first-class citizen
|
||||
|
||||
Progressive rollout across test/staging/production environments, automatic canary, blue-green and continuous verification, rich placement strategy across clusters and clouds, fully managed cloud environments provision.
|
||||
- *Infrastructure Agnostic* - KubeVela works as an application delivery control plane that is fully decoupled from runtime infrastructure. It can deploy any workload types including containers, cloud services, databases, or even VM instances to any cloud or Kubernetes cluster, following the workflow designed by you.
|
||||
|
||||
## Getting Started
|
||||
|
||||
* [Introduction](https://kubevela.io/docs)
|
||||
* [Installation](https://kubevela.io/docs/install)
|
||||
* [Deploy Your Application](https://kubevela.io/docs/quick-start)
|
||||
- [Introduction](https://kubevela.io/docs)
|
||||
- [Installation](https://kubevela.io/docs/install)
|
||||
- [Design Your First Deployment Plan](https://kubevela.io/docs/quick-start)
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -55,7 +49,7 @@ Official blog is available on [KubeVela blog](https://kubevela.io/blog).
|
||||
|
||||
## Community
|
||||
|
||||
We want your contributions and suggestions!
|
||||
We want your contributions and suggestions!
|
||||
One of the easiest ways to contribute is to participate in discussions on the Github Issues/Discussion, chat on IM or the bi-weekly community calls.
|
||||
For more information on the community engagement, developer and contributing guidelines and more, head over to the [KubeVela community repo](https://github.com/kubevela/community).
|
||||
|
||||
@@ -75,17 +69,23 @@ Every two weeks we host a community call to showcase new features, review upcomi
|
||||
|
||||
- Bi-weekly Community Call:
|
||||
- [Meeting Notes](https://docs.google.com/document/d/1nqdFEyULekyksFHtFvgvFAYE-0AMHKoS3RMnaKsarjs).
|
||||
- [Video Records](https://www.youtube.com/channel/UCSCTHhGI5XJ0SEhDHVakPAA/videos).
|
||||
- [Video Records](https://kubevela.io/videos/meetings/en/meetings).
|
||||
- Bi-weekly Chinese Community Call:
|
||||
- [Video Records](https://space.bilibili.com/180074935/channel/seriesdetail?sid=1842207).
|
||||
- [Video Records](https://kubevela.io/videos/meetings/cn/v1.3).
|
||||
|
||||
## Talks and Conferences
|
||||
|
||||
Check out [KubeVela videos](https://kubevela.io/videos/talks/en/oam-dapr) for these talks and conferences.
|
||||
| Engagement | Link |
|
||||
|:-----------|:------------|
|
||||
| 🎤 Talks | - [KubeVela - The Modern App Delivery System in Alibaba](https://docs.google.com/presentation/d/1CWCLcsKpDQB3bBDTfdv2BZ8ilGGJv2E8L-iOA5HMrV0/edit?usp=sharing) |
|
||||
| 🌎 KubeCon | - [ [NA 2020] Standardizing Cloud Native Application Delivery Across Different Clouds](https://www.youtube.com/watch?v=0yhVuBIbHcI) <br> - [ [EU 2021] Zero Pain Microservice Development and Deployment with Dapr and KubeVela](https://sched.co/iE4S) |
|
||||
| 📺 Conferences | - [Dapr, Rudr, OAM: Mark Russinovich presents next gen app development & deployment](https://www.youtube.com/watch?v=eJCu6a-x9uo) <br> - [Mark Russinovich presents "The Future of Cloud Native Applications with OAM and Dapr"](https://myignite.techcommunity.microsoft.com/sessions/82059)|
|
||||
|
||||
For more talks, please checkout [KubeVela Talks](https://kubevela.io/videos/talks/en/standardizing-app).
|
||||
|
||||
## Contributing
|
||||
|
||||
Check out [CONTRIBUTING](https://kubevela.io/docs/contributor/overview) to see how to develop with KubeVela.
|
||||
Check out [CONTRIBUTING](./CONTRIBUTING.md) to see how to develop with KubeVela.
|
||||
|
||||
## Report Vulnerability
|
||||
|
||||
|
||||
@@ -216,19 +216,19 @@ type WorkflowState string
|
||||
|
||||
const (
|
||||
// WorkflowStateInitializing means the workflow is in initial state
|
||||
WorkflowStateInitializing WorkflowState = "Initializing"
|
||||
WorkflowStateInitializing WorkflowState = "initializing"
|
||||
// WorkflowStateTerminated means workflow is terminated manually, and it won't be started unless the spec changed.
|
||||
WorkflowStateTerminated WorkflowState = "Terminated"
|
||||
WorkflowStateTerminated WorkflowState = "terminated"
|
||||
// WorkflowStateSuspended means workflow is suspended manually, and it can be resumed.
|
||||
WorkflowStateSuspended WorkflowState = "Suspended"
|
||||
WorkflowStateSuspended WorkflowState = "suspended"
|
||||
// WorkflowStateSucceeded means workflow is running successfully, all steps finished.
|
||||
WorkflowStateSucceeded WorkflowState = "Succeeded"
|
||||
// WorkflowStateFinished means workflow is end.
|
||||
WorkflowStateFinished WorkflowState = "Finished"
|
||||
WorkflowStateFinished WorkflowState = "finished"
|
||||
// WorkflowStateExecuting means workflow is still running or waiting some steps.
|
||||
WorkflowStateExecuting WorkflowState = "Executing"
|
||||
WorkflowStateExecuting WorkflowState = "executing"
|
||||
// WorkflowStateSkipping means it will skip this reconcile and let next reconcile to handle it.
|
||||
WorkflowStateSkipping WorkflowState = "Skipping"
|
||||
WorkflowStateSkipping WorkflowState = "skipping"
|
||||
)
|
||||
|
||||
// ApplicationComponentStatus record the health status of App component
|
||||
@@ -342,8 +342,6 @@ type WorkflowStep struct {
|
||||
|
||||
Type string `json:"type"`
|
||||
|
||||
Meta *WorkflowStepMeta `json:"meta,omitempty"`
|
||||
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
Properties *runtime.RawExtension `json:"properties,omitempty"`
|
||||
|
||||
@@ -351,8 +349,6 @@ type WorkflowStep struct {
|
||||
|
||||
If string `json:"if,omitempty"`
|
||||
|
||||
Timeout string `json:"timeout,omitempty"`
|
||||
|
||||
DependsOn []string `json:"dependsOn,omitempty"`
|
||||
|
||||
Inputs StepInputs `json:"inputs,omitempty"`
|
||||
@@ -360,11 +356,6 @@ type WorkflowStep struct {
|
||||
Outputs StepOutputs `json:"outputs,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowStepMeta contains the meta data of a workflow step
|
||||
type WorkflowStepMeta struct {
|
||||
Alias string `json:"alias,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowSubStep defines how to execute a workflow subStep.
|
||||
type WorkflowSubStep struct {
|
||||
// Name is the unique name of the workflow step.
|
||||
@@ -372,15 +363,11 @@ type WorkflowSubStep struct {
|
||||
|
||||
Type string `json:"type"`
|
||||
|
||||
Meta *WorkflowStepMeta `json:"meta,omitempty"`
|
||||
|
||||
// +kubebuilder:pruning:PreserveUnknownFields
|
||||
Properties *runtime.RawExtension `json:"properties,omitempty"`
|
||||
|
||||
If string `json:"if,omitempty"`
|
||||
|
||||
Timeout string `json:"timeout,omitempty"`
|
||||
|
||||
DependsOn []string `json:"dependsOn,omitempty"`
|
||||
|
||||
Inputs StepInputs `json:"inputs,omitempty"`
|
||||
|
||||
@@ -684,11 +684,6 @@ func (in *WorkflowStatus) DeepCopy() *WorkflowStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowStep) DeepCopyInto(out *WorkflowStep) {
|
||||
*out = *in
|
||||
if in.Meta != nil {
|
||||
in, out := &in.Meta, &out.Meta
|
||||
*out = new(WorkflowStepMeta)
|
||||
**out = **in
|
||||
}
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = new(runtime.RawExtension)
|
||||
@@ -728,21 +723,6 @@ func (in *WorkflowStep) DeepCopy() *WorkflowStep {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowStepMeta) DeepCopyInto(out *WorkflowStepMeta) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStepMeta.
|
||||
func (in *WorkflowStepMeta) DeepCopy() *WorkflowStepMeta {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(WorkflowStepMeta)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowStepStatus) DeepCopyInto(out *WorkflowStepStatus) {
|
||||
*out = *in
|
||||
@@ -769,11 +749,6 @@ func (in *WorkflowStepStatus) DeepCopy() *WorkflowStepStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowSubStep) DeepCopyInto(out *WorkflowSubStep) {
|
||||
*out = *in
|
||||
if in.Meta != nil {
|
||||
in, out := &in.Meta, &out.Meta
|
||||
*out = new(WorkflowStepMeta)
|
||||
**out = **in
|
||||
}
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = new(runtime.RawExtension)
|
||||
|
||||
@@ -25,8 +25,6 @@ const (
|
||||
type RefObjectsComponentSpec struct {
|
||||
// Objects the referrers to the Kubernetes objects
|
||||
Objects []ObjectReferrer `json:"objects,omitempty"`
|
||||
// URLs are the links that stores the referred objects
|
||||
URLs []string `json:"urls,omitempty"`
|
||||
}
|
||||
|
||||
// ObjectReferrer selects Kubernetes objects
|
||||
|
||||
@@ -18,7 +18,6 @@ package v1alpha1
|
||||
|
||||
import (
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/utils/strings/slices"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
)
|
||||
@@ -67,29 +66,6 @@ type ResourcePolicyRuleSelector struct {
|
||||
OAMResourceTypes []string `json:"oamTypes"`
|
||||
TraitTypes []string `json:"traitTypes"`
|
||||
ResourceTypes []string `json:"resourceTypes"`
|
||||
ResourceNames []string `json:"resourceNames"`
|
||||
}
|
||||
|
||||
// Match check if current rule selector match the target resource
|
||||
func (in *ResourcePolicyRuleSelector) Match(manifest *unstructured.Unstructured) bool {
|
||||
var compName, compType, oamType, traitType, resourceType, resourceName string
|
||||
if labels := manifest.GetLabels(); labels != nil {
|
||||
compName = labels[oam.LabelAppComponent]
|
||||
compType = labels[oam.WorkloadTypeLabel]
|
||||
oamType = labels[oam.LabelOAMResourceType]
|
||||
traitType = labels[oam.TraitTypeLabel]
|
||||
}
|
||||
resourceType = manifest.GetKind()
|
||||
resourceName = manifest.GetName()
|
||||
match := func(src []string, val string) (found bool) {
|
||||
return val != "" && slices.Contains(src, val)
|
||||
}
|
||||
return match(in.CompNames, compName) ||
|
||||
match(in.CompTypes, compType) ||
|
||||
match(in.OAMResourceTypes, oamType) ||
|
||||
match(in.TraitTypes, traitType) ||
|
||||
match(in.ResourceTypes, resourceType) ||
|
||||
match(in.ResourceNames, resourceName)
|
||||
}
|
||||
|
||||
// GarbageCollectStrategy the strategy for target resource to recycle
|
||||
@@ -108,7 +84,23 @@ const (
|
||||
// FindStrategy find gc strategy for target resource
|
||||
func (in GarbageCollectPolicySpec) FindStrategy(manifest *unstructured.Unstructured) *GarbageCollectStrategy {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
var compName, compType, oamType, traitType string
|
||||
if labels := manifest.GetLabels(); labels != nil {
|
||||
compName = labels[oam.LabelAppComponent]
|
||||
compType = labels[oam.WorkloadTypeLabel]
|
||||
oamType = labels[oam.LabelOAMResourceType]
|
||||
traitType = labels[oam.TraitTypeLabel]
|
||||
}
|
||||
match := func(src []string, val string) (found bool) {
|
||||
for _, _val := range src {
|
||||
found = found || _val == val
|
||||
}
|
||||
return val != "" && found
|
||||
}
|
||||
if match(rule.Selector.CompNames, compName) ||
|
||||
match(rule.Selector.CompTypes, compType) ||
|
||||
match(rule.Selector.OAMResourceTypes, oamType) ||
|
||||
match(rule.Selector.TraitTypes, traitType) {
|
||||
return &rule.Strategy
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@ limitations under the License.
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
||||
const (
|
||||
// TopologyPolicyType refers to the type of topology policy
|
||||
TopologyPolicyType = "topology"
|
||||
@@ -25,8 +23,6 @@ const (
|
||||
OverridePolicyType = "override"
|
||||
// DebugPolicyType refers to the type of debug policy
|
||||
DebugPolicyType = "debug"
|
||||
// SharedResourcePolicyType refers to the type of shared resource policy
|
||||
SharedResourcePolicyType = "shared-resource"
|
||||
)
|
||||
|
||||
// TopologyPolicySpec defines the spec of topology policy
|
||||
@@ -57,23 +53,3 @@ type OverridePolicySpec struct {
|
||||
Components []EnvComponentPatch `json:"components,omitempty"`
|
||||
Selector []string `json:"selector,omitempty"`
|
||||
}
|
||||
|
||||
// SharedResourcePolicySpec defines the spec of shared-resource policy
|
||||
type SharedResourcePolicySpec struct {
|
||||
Rules []SharedResourcePolicyRule `json:"rules"`
|
||||
}
|
||||
|
||||
// SharedResourcePolicyRule defines the rule for sharing resources
|
||||
type SharedResourcePolicyRule struct {
|
||||
Selector ResourcePolicyRuleSelector `json:"selector"`
|
||||
}
|
||||
|
||||
// FindStrategy return if the target resource should be shared
|
||||
func (in SharedResourcePolicySpec) FindStrategy(manifest *unstructured.Unstructured) bool {
|
||||
for _, rule := range in.Rules {
|
||||
if rule.Selector.Match(manifest) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package v1alpha1
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func TestSharedResourcePolicySpec_FindStrategy(t *testing.T) {
|
||||
testCases := map[string]struct {
|
||||
rules []SharedResourcePolicyRule
|
||||
input *unstructured.Unstructured
|
||||
matched bool
|
||||
}{
|
||||
"shared resource rule resourceName match": {
|
||||
rules: []SharedResourcePolicyRule{{
|
||||
Selector: ResourcePolicyRuleSelector{ResourceNames: []string{"example"}},
|
||||
}},
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"metadata": map[string]interface{}{
|
||||
"name": "example",
|
||||
},
|
||||
}},
|
||||
matched: true,
|
||||
},
|
||||
"shared resource rule resourceType match": {
|
||||
rules: []SharedResourcePolicyRule{{
|
||||
Selector: ResourcePolicyRuleSelector{ResourceTypes: []string{"ConfigMap", "Namespace"}},
|
||||
}},
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"kind": "Namespace",
|
||||
}},
|
||||
matched: true,
|
||||
},
|
||||
"shared resource rule mismatch": {
|
||||
rules: []SharedResourcePolicyRule{{
|
||||
Selector: ResourcePolicyRuleSelector{ResourceNames: []string{"mismatch"}},
|
||||
}},
|
||||
input: &unstructured.Unstructured{Object: map[string]interface{}{
|
||||
"kind": "Namespace",
|
||||
}},
|
||||
matched: false,
|
||||
},
|
||||
}
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
r := require.New(t)
|
||||
spec := SharedResourcePolicySpec{Rules: tc.rules}
|
||||
r.Equal(tc.matched, spec.FindStrategy(tc.input))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -595,11 +595,6 @@ func (in *RefObjectsComponentSpec) DeepCopyInto(out *RefObjectsComponentSpec) {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
if in.URLs != nil {
|
||||
in, out := &in.URLs, &out.URLs
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RefObjectsComponentSpec.
|
||||
@@ -640,11 +635,6 @@ func (in *ResourcePolicyRuleSelector) DeepCopyInto(out *ResourcePolicyRuleSelect
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.ResourceNames != nil {
|
||||
in, out := &in.ResourceNames, &out.ResourceNames
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourcePolicyRuleSelector.
|
||||
@@ -657,44 +647,6 @@ func (in *ResourcePolicyRuleSelector) DeepCopy() *ResourcePolicyRuleSelector {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SharedResourcePolicyRule) DeepCopyInto(out *SharedResourcePolicyRule) {
|
||||
*out = *in
|
||||
in.Selector.DeepCopyInto(&out.Selector)
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SharedResourcePolicyRule.
|
||||
func (in *SharedResourcePolicyRule) DeepCopy() *SharedResourcePolicyRule {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SharedResourcePolicyRule)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *SharedResourcePolicySpec) DeepCopyInto(out *SharedResourcePolicySpec) {
|
||||
*out = *in
|
||||
if in.Rules != nil {
|
||||
in, out := &in.Rules, &out.Rules
|
||||
*out = make([]SharedResourcePolicyRule, len(*in))
|
||||
for i := range *in {
|
||||
(*in)[i].DeepCopyInto(&(*out)[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SharedResourcePolicySpec.
|
||||
func (in *SharedResourcePolicySpec) DeepCopy() *SharedResourcePolicySpec {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(SharedResourcePolicySpec)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *TopologyPolicySpec) DeepCopyInto(out *TopologyPolicySpec) {
|
||||
*out = *in
|
||||
|
||||
@@ -54,15 +54,8 @@ type WorkflowStep common.WorkflowStep
|
||||
|
||||
// Workflow defines workflow steps and other attributes
|
||||
type Workflow struct {
|
||||
Ref string `json:"ref,omitempty"`
|
||||
Mode *WorkflowExecuteMode `json:"mode,omitempty"`
|
||||
Steps []WorkflowStep `json:"steps,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowExecuteMode defines the mode of workflow execution
|
||||
type WorkflowExecuteMode struct {
|
||||
Steps common.WorkflowMode `json:"steps,omitempty"`
|
||||
SubSteps common.WorkflowMode `json:"subSteps,omitempty"`
|
||||
Ref string `json:"ref,omitempty"`
|
||||
Steps []WorkflowStep `json:"steps,omitempty"`
|
||||
}
|
||||
|
||||
// ApplicationSpec is the spec of Application
|
||||
|
||||
@@ -927,11 +927,6 @@ func (in *TraitDefinitionStatus) DeepCopy() *TraitDefinitionStatus {
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *Workflow) DeepCopyInto(out *Workflow) {
|
||||
*out = *in
|
||||
if in.Mode != nil {
|
||||
in, out := &in.Mode, &out.Mode
|
||||
*out = new(WorkflowExecuteMode)
|
||||
**out = **in
|
||||
}
|
||||
if in.Steps != nil {
|
||||
in, out := &in.Steps, &out.Steps
|
||||
*out = make([]WorkflowStep, len(*in))
|
||||
@@ -951,29 +946,9 @@ func (in *Workflow) DeepCopy() *Workflow {
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowExecuteMode) DeepCopyInto(out *WorkflowExecuteMode) {
|
||||
*out = *in
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowExecuteMode.
|
||||
func (in *WorkflowExecuteMode) DeepCopy() *WorkflowExecuteMode {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(WorkflowExecuteMode)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *WorkflowStep) DeepCopyInto(out *WorkflowStep) {
|
||||
*out = *in
|
||||
if in.Meta != nil {
|
||||
in, out := &in.Meta, &out.Meta
|
||||
*out = new(common.WorkflowStepMeta)
|
||||
**out = **in
|
||||
}
|
||||
if in.Properties != nil {
|
||||
in, out := &in.Properties, &out.Properties
|
||||
*out = new(runtime.RawExtension)
|
||||
|
||||
@@ -80,8 +80,6 @@ const (
|
||||
OpenapiV3JSONSchema string = "openapi-v3-json-schema"
|
||||
// UISchema is the key to store ui custom schema
|
||||
UISchema string = "ui-schema"
|
||||
// VelaQLConfigmapKey is the key to store velaql view
|
||||
VelaQLConfigmapKey string = "template"
|
||||
)
|
||||
|
||||
// CapabilityCategory defines the category of a capability
|
||||
|
||||
@@ -93,7 +93,6 @@ helm install --create-namespace -n vela-system kubevela kubevela/vela-core --wai
|
||||
| `optimize.enableInMemoryWorkflowContext` | Optimize workflow by use in-memory context. | `false` |
|
||||
| `optimize.disableResourceApplyDoubleCheck` | Optimize workflow by ignoring resource double check after apply. | `false` |
|
||||
| `optimize.enableResourceTrackerDeleteOnlyTrigger` | Optimize resourcetracker by only trigger reconcile when resourcetracker is deleted. | `true` |
|
||||
| `featureGates.enableLegacyComponentRevision` | if disabled, only component with rollout trait will create component revisions | `false` |
|
||||
|
||||
|
||||
### MultiCluster parameters
|
||||
|
||||
@@ -2198,17 +2198,6 @@ spec:
|
||||
a context in annotation. - should mark "finish" phase in
|
||||
status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -2236,13 +2225,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta
|
||||
data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -2289,13 +2271,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the
|
||||
meta data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the
|
||||
workflow step.
|
||||
@@ -2317,8 +2292,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -2326,8 +2299,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4002,13 +3973,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -4053,13 +4017,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -4081,8 +4038,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4090,8 +4045,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -1009,17 +1009,6 @@ spec:
|
||||
order, and each step: - will have a context in annotation. - should
|
||||
mark "finish" phase in status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -1046,13 +1035,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -1097,13 +1079,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -1125,8 +1100,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -1134,8 +1107,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -57,13 +57,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a workflow
|
||||
step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -107,13 +100,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a
|
||||
workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -133,8 +119,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -142,8 +126,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -159,16 +141,6 @@ spec:
|
||||
openAPIV3Schema:
|
||||
description: Workflow defines workflow steps and other attributes
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -194,13 +166,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a workflow
|
||||
step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -244,13 +209,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a
|
||||
workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -270,8 +228,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -279,8 +235,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -1,574 +0,0 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/daemon.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Describes daemonset services in Kubernetes.
|
||||
name: daemon
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
mountsArray: {
|
||||
pvc: *[
|
||||
for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
configMap: *[
|
||||
for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
secret: *[
|
||||
for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
emptyDir: *[
|
||||
for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
hostPath: *[
|
||||
for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
if v.mountPropagation != _|_ {
|
||||
mountPropagation: v.mountPropagation
|
||||
}
|
||||
name: v.name
|
||||
if v.readOnly != _|_ {
|
||||
readOnly: v.readOnly
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
}
|
||||
volumesArray: {
|
||||
pvc: *[
|
||||
for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
name: v.name
|
||||
persistentVolumeClaim: claimName: v.claimName
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
configMap: *[
|
||||
for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
name: v.name
|
||||
configMap: {
|
||||
defaultMode: v.defaultMode
|
||||
name: v.cmName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
secret: *[
|
||||
for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
name: v.name
|
||||
secret: {
|
||||
defaultMode: v.defaultMode
|
||||
secretName: v.secretName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
emptyDir: *[
|
||||
for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
name: v.name
|
||||
emptyDir: medium: v.medium
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
hostPath: *[
|
||||
for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
name: v.name
|
||||
hostPath: path: v.path
|
||||
}
|
||||
},
|
||||
] | []
|
||||
}
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "DaemonSet"
|
||||
spec: {
|
||||
selector: matchLabels: "app.oam.dev/component": context.name
|
||||
|
||||
template: {
|
||||
metadata: {
|
||||
labels: {
|
||||
if parameter.labels != _|_ {
|
||||
parameter.labels
|
||||
}
|
||||
if parameter.addRevisionLabel {
|
||||
"app.oam.dev/revision": context.revision
|
||||
}
|
||||
"app.oam.dev/name": context.appName
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
if parameter.annotations != _|_ {
|
||||
annotations: parameter.annotations
|
||||
}
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
if parameter["port"] != _|_ && parameter["ports"] == _|_ {
|
||||
ports: [{
|
||||
containerPort: parameter.port
|
||||
}]
|
||||
}
|
||||
if parameter["ports"] != _|_ {
|
||||
ports: [ for v in parameter.ports {
|
||||
{
|
||||
containerPort: v.port
|
||||
protocol: v.protocol
|
||||
if v.name != _|_ {
|
||||
name: v.name
|
||||
}
|
||||
if v.name == _|_ {
|
||||
name: "port-" + strconv.FormatInt(v.port, 10)
|
||||
}
|
||||
}}]
|
||||
}
|
||||
|
||||
if parameter["imagePullPolicy"] != _|_ {
|
||||
imagePullPolicy: parameter.imagePullPolicy
|
||||
}
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
|
||||
if parameter["env"] != _|_ {
|
||||
env: parameter.env
|
||||
}
|
||||
|
||||
if context["config"] != _|_ {
|
||||
env: context.config
|
||||
}
|
||||
|
||||
if parameter["cpu"] != _|_ {
|
||||
resources: {
|
||||
limits: cpu: parameter.cpu
|
||||
requests: cpu: parameter.cpu
|
||||
}
|
||||
}
|
||||
|
||||
if parameter["memory"] != _|_ {
|
||||
resources: {
|
||||
limits: memory: parameter.memory
|
||||
requests: memory: parameter.memory
|
||||
}
|
||||
}
|
||||
|
||||
if parameter["volumes"] != _|_ && parameter["volumeMounts"] == _|_ {
|
||||
volumeMounts: [ for v in parameter.volumes {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}}]
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumeMounts: mountsArray.pvc + mountsArray.configMap + mountsArray.secret + mountsArray.emptyDir + mountsArray.hostPath
|
||||
}
|
||||
|
||||
if parameter["livenessProbe"] != _|_ {
|
||||
livenessProbe: parameter.livenessProbe
|
||||
}
|
||||
|
||||
if parameter["readinessProbe"] != _|_ {
|
||||
readinessProbe: parameter.readinessProbe
|
||||
}
|
||||
|
||||
}]
|
||||
|
||||
if parameter["hostAliases"] != _|_ {
|
||||
// +patchKey=ip
|
||||
hostAliases: parameter.hostAliases
|
||||
}
|
||||
|
||||
if parameter["imagePullSecrets"] != _|_ {
|
||||
imagePullSecrets: [ for v in parameter.imagePullSecrets {
|
||||
name: v
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
if parameter["volumes"] != _|_ && parameter["volumeMounts"] == _|_ {
|
||||
volumes: [ for v in parameter.volumes {
|
||||
{
|
||||
name: v.name
|
||||
if v.type == "pvc" {
|
||||
persistentVolumeClaim: claimName: v.claimName
|
||||
}
|
||||
if v.type == "configMap" {
|
||||
configMap: {
|
||||
defaultMode: v.defaultMode
|
||||
name: v.cmName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.type == "secret" {
|
||||
secret: {
|
||||
defaultMode: v.defaultMode
|
||||
secretName: v.secretName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.type == "emptyDir" {
|
||||
emptyDir: medium: v.medium
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumes: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exposePorts: [
|
||||
for v in parameter.ports if v.expose == true {
|
||||
port: v.port
|
||||
targetPort: v.port
|
||||
if v.name != _|_ {
|
||||
name: v.name
|
||||
}
|
||||
if v.name == _|_ {
|
||||
name: "port-" + strconv.FormatInt(v.port, 10)
|
||||
}
|
||||
},
|
||||
]
|
||||
outputs: {
|
||||
if len(exposePorts) != 0 {
|
||||
webserviceExpose: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
selector: "app.oam.dev/component": context.name
|
||||
ports: exposePorts
|
||||
type: parameter.exposeType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the labels in the workload
|
||||
labels?: [string]: string
|
||||
|
||||
// +usage=Specify the annotations in the workload
|
||||
annotations?: [string]: string
|
||||
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Specify image pull policy for your service
|
||||
imagePullPolicy?: "Always" | "Never" | "IfNotPresent"
|
||||
|
||||
// +usage=Specify image pull secrets for your service
|
||||
imagePullSecrets?: [...string]
|
||||
|
||||
// +ignore
|
||||
// +usage=Deprecated field, please use ports instead
|
||||
// +short=p
|
||||
port?: int
|
||||
|
||||
// +usage=Which ports do you want customer traffic sent to, defaults to 80
|
||||
ports?: [...{
|
||||
// +usage=Number of port to expose on the pod's IP address
|
||||
port: int
|
||||
// +usage=Name of the port
|
||||
name?: string
|
||||
// +usage=Protocol for port. Must be UDP, TCP, or SCTP
|
||||
protocol: *"TCP" | "UDP" | "SCTP"
|
||||
// +usage=Specify if the port should be exposed
|
||||
expose: *false | bool
|
||||
}]
|
||||
|
||||
// +ignore
|
||||
// +usage=Specify what kind of Service you want. options: "ClusterIP", "NodePort", "LoadBalancer", "ExternalName"
|
||||
exposeType: *"ClusterIP" | "NodePort" | "LoadBalancer" | "ExternalName"
|
||||
|
||||
// +ignore
|
||||
// +usage=If addRevisionLabel is true, the revision label will be added to the underlying pods
|
||||
addRevisionLabel: *false | bool
|
||||
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
|
||||
// +usage=Define arguments by using environment variables
|
||||
env?: [...{
|
||||
// +usage=Environment variable name
|
||||
name: string
|
||||
// +usage=The value of the environment variable
|
||||
value?: string
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef?: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Selects a key of a config map in the pod's namespace
|
||||
configMapKeyRef?: {
|
||||
// +usage=The name of the config map in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
// +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)
|
||||
cpu?: string
|
||||
|
||||
// +usage=Specifies the attributes of the memory resource required for the container.
|
||||
memory?: string
|
||||
|
||||
volumeMounts?: {
|
||||
// +usage=Mount PVC type volume
|
||||
pvc?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
// +usage=The name of the PVC
|
||||
claimName: string
|
||||
}]
|
||||
// +usage=Mount ConfigMap type volume
|
||||
configMap?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}]
|
||||
// +usage=Mount Secret type volume
|
||||
secret?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}]
|
||||
// +usage=Mount EmptyDir type volume
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
// +usage=Mount HostPath type volume
|
||||
hostPath?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
mountPropagation?: "None" | "HostToContainer" | "Bidirectional"
|
||||
path: string
|
||||
readOnly?: bool
|
||||
}]
|
||||
}
|
||||
|
||||
// +usage=Deprecated field, use volumeMounts instead.
|
||||
volumes?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
// +usage=Specify volume type, options: "pvc","configMap","secret","emptyDir"
|
||||
type: "pvc" | "configMap" | "secret" | "emptyDir"
|
||||
if type == "pvc" {
|
||||
claimName: string
|
||||
}
|
||||
if type == "configMap" {
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}
|
||||
if type == "secret" {
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}
|
||||
if type == "emptyDir" {
|
||||
medium: *"" | "Memory"
|
||||
}
|
||||
}]
|
||||
|
||||
// +usage=Instructions for assessing whether the container is alive.
|
||||
livenessProbe?: #HealthProbe
|
||||
|
||||
// +usage=Instructions for assessing whether the container is in a suitable state to serve traffic.
|
||||
readinessProbe?: #HealthProbe
|
||||
|
||||
// +usage=Specify the hostAliases to add
|
||||
hostAliases?: [...{
|
||||
ip: string
|
||||
hostnames: [...string]
|
||||
}]
|
||||
}
|
||||
#HealthProbe: {
|
||||
|
||||
// +usage=Instructions for assessing container health by executing a command. Either this attribute or the httpGet attribute or the tcpSocket attribute MUST be specified. This attribute is mutually exclusive with both the httpGet attribute and the tcpSocket attribute.
|
||||
exec?: {
|
||||
// +usage=A command to be executed inside the container to assess its health. Each space delimited token of the command is a separate array element. Commands exiting 0 are considered to be successful probes, whilst all other exit codes are considered failures.
|
||||
command: [...string]
|
||||
}
|
||||
|
||||
// +usage=Instructions for assessing container health by executing an HTTP GET request. Either this attribute or the exec attribute or the tcpSocket attribute MUST be specified. This attribute is mutually exclusive with both the exec attribute and the tcpSocket attribute.
|
||||
httpGet?: {
|
||||
// +usage=The endpoint, relative to the port, to which the HTTP GET request should be directed.
|
||||
path: string
|
||||
// +usage=The TCP socket within the container to which the HTTP GET request should be directed.
|
||||
port: int
|
||||
host?: string
|
||||
scheme?: *"HTTP" | string
|
||||
httpHeaders?: [...{
|
||||
name: string
|
||||
value: string
|
||||
}]
|
||||
}
|
||||
|
||||
// +usage=Instructions for assessing container health by probing a TCP socket. Either this attribute or the exec attribute or the httpGet attribute MUST be specified. This attribute is mutually exclusive with both the exec attribute and the httpGet attribute.
|
||||
tcpSocket?: {
|
||||
// +usage=The TCP socket within the container that should be probed to assess container health.
|
||||
port: int
|
||||
}
|
||||
|
||||
// +usage=Number of seconds after the container is started before the first probe is initiated.
|
||||
initialDelaySeconds: *0 | int
|
||||
|
||||
// +usage=How often, in seconds, to execute the probe.
|
||||
periodSeconds: *10 | int
|
||||
|
||||
// +usage=Number of seconds after which the probe times out.
|
||||
timeoutSeconds: *1 | int
|
||||
|
||||
// +usage=Minimum consecutive successes for the probe to be considered successful after having failed.
|
||||
successThreshold: *1 | int
|
||||
|
||||
// +usage=Number of consecutive failures required to determine the container is not alive (liveness probe) or not ready (readiness probe).
|
||||
failureThreshold: *3 | int
|
||||
}
|
||||
status:
|
||||
customStatus: |-
|
||||
ready: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.numberReady != _|_ {
|
||||
replicas: context.output.status.numberReady
|
||||
}
|
||||
}
|
||||
desired: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.desiredNumberScheduled != _|_ {
|
||||
replicas: context.output.status.desiredNumberScheduled
|
||||
}
|
||||
}
|
||||
message: "Ready:\(ready.replicas)/\(desired.replicas)"
|
||||
healthPolicy: |-
|
||||
ready: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.numberReady != _|_ {
|
||||
replicas: context.output.status.numberReady
|
||||
}
|
||||
}
|
||||
desired: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.desiredNumberScheduled != _|_ {
|
||||
replicas: context.output.status.desiredNumberScheduled
|
||||
}
|
||||
}
|
||||
current: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.currentNumberScheduled != _|_ {
|
||||
replicas: context.output.status.currentNumberScheduled
|
||||
}
|
||||
}
|
||||
updated: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.updatedNumberScheduled != _|_ {
|
||||
replicas: context.output.status.updatedNumberScheduled
|
||||
}
|
||||
}
|
||||
generation: {
|
||||
metadata: context.output.metadata.generation
|
||||
observed: *0 | int
|
||||
} & {
|
||||
if context.output.status.observedGeneration != _|_ {
|
||||
observed: context.output.status.observedGeneration
|
||||
}
|
||||
}
|
||||
isHealth: (desired.replicas == ready.replicas) && (desired.replicas == updated.replicas) && (desired.replicas == current.replicas) && (generation.observed == generation.metadata || generation.observed > generation.metadata)
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
type: daemonsets.apps
|
||||
|
||||
@@ -14,20 +14,21 @@ spec:
|
||||
cue:
|
||||
template: |
|
||||
#K8sObject: {
|
||||
resource?: string
|
||||
group?: string
|
||||
name?: string
|
||||
// +usage=The resource type for the Kubernetes objects
|
||||
resource?: string
|
||||
// +usage=The group name for the Kubernetes objects
|
||||
group?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects with the name, exclusive to labelSelector
|
||||
name?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects from the namespace. Otherwise, fetch from the application's namespace.
|
||||
namespace?: string
|
||||
cluster?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects from the cluster. Otherwise, fetch from the local cluster.
|
||||
cluster?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects according to the label selector, exclusive to name
|
||||
labelSelector?: [string]: string
|
||||
...
|
||||
}
|
||||
output: {
|
||||
if len(parameter.objects) > 0 {
|
||||
parameter.objects[0]
|
||||
}
|
||||
...
|
||||
}
|
||||
output: parameter.objects[0]
|
||||
outputs: {
|
||||
for i, v in parameter.objects {
|
||||
if i > 0 {
|
||||
@@ -35,7 +36,12 @@ spec:
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: objects: [...#K8sObject]
|
||||
parameter: {
|
||||
// +usage=If specified, application will fetch native Kubernetes objects according to the object description
|
||||
objects?: [...#K8sObject]
|
||||
// +usage=If specified, the objects in the urls will be loaded.
|
||||
urls?: [...string]
|
||||
}
|
||||
status:
|
||||
customStatus: |-
|
||||
if context.output.apiVersion == "apps/v1" && context.output.kind == "Deployment" {
|
||||
|
||||
@@ -64,6 +64,9 @@ spec:
|
||||
{
|
||||
name: "pvc-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -73,6 +76,9 @@ spec:
|
||||
{
|
||||
name: "configmap-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -103,6 +109,9 @@ spec:
|
||||
{
|
||||
name: "secret-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -133,6 +142,9 @@ spec:
|
||||
{
|
||||
name: "emptydir-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -141,12 +153,28 @@ spec:
|
||||
{
|
||||
name: "pvc-" + v.name
|
||||
devicePath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
volumesList: pvcVolumesList + configMapVolumesList + secretVolumesList + emptyDirVolumesList
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
patch: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
volumes: pvcVolumesList + configMapVolumesList + secretVolumesList + emptyDirVolumesList
|
||||
volumes: deDupVolumesArray
|
||||
|
||||
containers: [{
|
||||
// +patchKey=name
|
||||
@@ -234,6 +262,7 @@ spec:
|
||||
name: string
|
||||
mountOnly: *false | bool
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
volumeMode: *"Filesystem" | string
|
||||
volumeName?: string
|
||||
accessModes: *["ReadWriteOnce"] | [...string]
|
||||
@@ -275,6 +304,7 @@ spec:
|
||||
configMapKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
data?: {...}
|
||||
@@ -298,6 +328,7 @@ spec:
|
||||
secretKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
stringData?: {...}
|
||||
@@ -313,6 +344,7 @@ spec:
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@ spec:
|
||||
for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -29,7 +32,10 @@ spec:
|
||||
for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -38,7 +44,10 @@ spec:
|
||||
for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -47,7 +56,10 @@ spec:
|
||||
for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -56,7 +68,10 @@ spec:
|
||||
for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -119,6 +134,19 @@ spec:
|
||||
},
|
||||
] | []
|
||||
}
|
||||
volumesList: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
@@ -262,7 +290,7 @@ spec:
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumes: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
volumes: deDupVolumesArray
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,6 +403,7 @@ spec:
|
||||
pvc?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
// +usage=The name of the PVC
|
||||
claimName: string
|
||||
}]
|
||||
@@ -382,6 +411,7 @@ spec:
|
||||
configMap?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
@@ -394,6 +424,7 @@ spec:
|
||||
secret?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
@@ -406,12 +437,14 @@ spec:
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
// +usage=Mount HostPath type volume
|
||||
hostPath?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
path: string
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -217,7 +217,6 @@ spec:
|
||||
- "--max-workflow-step-error-retry-times={{ .Values.workflow.step.errorRetryTimes }}"
|
||||
- "--feature-gates=EnableSuspendOnFailure={{- .Values.workflow.enableSuspendOnFailure | toString -}}"
|
||||
- "--feature-gates=AuthenticateApplication={{- .Values.authentication.enabled | toString -}}"
|
||||
- "--feature-gates=LegacyComponentRevision={{- .Values.featureGates.enableLegacyComponentRevision | toString -}}"
|
||||
{{ if .Values.authentication.enabled }}
|
||||
{{ if .Values.authentication.withUser }}
|
||||
- "--authentication-with-user"
|
||||
|
||||
@@ -109,10 +109,6 @@ optimize:
|
||||
disableResourceApplyDoubleCheck: false
|
||||
enableResourceTrackerDeleteOnlyTrigger: true
|
||||
|
||||
##@param featureGates.enableLegacyComponentRevision if disabled, only component with rollout trait will create component revisions
|
||||
featureGates:
|
||||
enableLegacyComponentRevision: false
|
||||
|
||||
## @section MultiCluster parameters
|
||||
|
||||
## @param multicluster.enabled Whether to enable multi-cluster
|
||||
|
||||
@@ -2198,17 +2198,6 @@ spec:
|
||||
a context in annotation. - should mark "finish" phase in
|
||||
status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -2236,13 +2225,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta
|
||||
data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -2289,13 +2271,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the
|
||||
meta data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the
|
||||
workflow step.
|
||||
@@ -2317,8 +2292,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -2326,8 +2299,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4002,13 +3973,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -4053,13 +4017,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -4081,8 +4038,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4090,8 +4045,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -1009,17 +1009,6 @@ spec:
|
||||
order, and each step: - will have a context in annotation. - should
|
||||
mark "finish" phase in status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -1046,13 +1035,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -1097,13 +1079,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -1125,8 +1100,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
x-kubernetes-preserve-unknown-fields: true
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -1134,8 +1107,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -1,574 +0,0 @@
|
||||
# Code generated by KubeVela templates. DO NOT EDIT. Please edit the original cue file.
|
||||
# Definition source cue file: vela-templates/definitions/internal/daemon.cue
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: ComponentDefinition
|
||||
metadata:
|
||||
annotations:
|
||||
definition.oam.dev/description: Describes daemonset services in Kubernetes.
|
||||
name: daemon
|
||||
namespace: {{ include "systemDefinitionNamespace" . }}
|
||||
spec:
|
||||
schematic:
|
||||
cue:
|
||||
template: |
|
||||
import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
mountsArray: {
|
||||
pvc: *[
|
||||
for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
configMap: *[
|
||||
for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
secret: *[
|
||||
for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
emptyDir: *[
|
||||
for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
hostPath: *[
|
||||
for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
if v.mountPropagation != _|_ {
|
||||
mountPropagation: v.mountPropagation
|
||||
}
|
||||
name: v.name
|
||||
if v.readOnly != _|_ {
|
||||
readOnly: v.readOnly
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
}
|
||||
volumesArray: {
|
||||
pvc: *[
|
||||
for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
name: v.name
|
||||
persistentVolumeClaim: claimName: v.claimName
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
configMap: *[
|
||||
for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
name: v.name
|
||||
configMap: {
|
||||
defaultMode: v.defaultMode
|
||||
name: v.cmName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
secret: *[
|
||||
for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
name: v.name
|
||||
secret: {
|
||||
defaultMode: v.defaultMode
|
||||
secretName: v.secretName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
emptyDir: *[
|
||||
for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
name: v.name
|
||||
emptyDir: medium: v.medium
|
||||
}
|
||||
},
|
||||
] | []
|
||||
|
||||
hostPath: *[
|
||||
for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
name: v.name
|
||||
hostPath: path: v.path
|
||||
}
|
||||
},
|
||||
] | []
|
||||
}
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "DaemonSet"
|
||||
spec: {
|
||||
selector: matchLabels: "app.oam.dev/component": context.name
|
||||
|
||||
template: {
|
||||
metadata: {
|
||||
labels: {
|
||||
if parameter.labels != _|_ {
|
||||
parameter.labels
|
||||
}
|
||||
if parameter.addRevisionLabel {
|
||||
"app.oam.dev/revision": context.revision
|
||||
}
|
||||
"app.oam.dev/name": context.appName
|
||||
"app.oam.dev/component": context.name
|
||||
}
|
||||
if parameter.annotations != _|_ {
|
||||
annotations: parameter.annotations
|
||||
}
|
||||
}
|
||||
|
||||
spec: {
|
||||
containers: [{
|
||||
name: context.name
|
||||
image: parameter.image
|
||||
if parameter["port"] != _|_ && parameter["ports"] == _|_ {
|
||||
ports: [{
|
||||
containerPort: parameter.port
|
||||
}]
|
||||
}
|
||||
if parameter["ports"] != _|_ {
|
||||
ports: [ for v in parameter.ports {
|
||||
{
|
||||
containerPort: v.port
|
||||
protocol: v.protocol
|
||||
if v.name != _|_ {
|
||||
name: v.name
|
||||
}
|
||||
if v.name == _|_ {
|
||||
name: "port-" + strconv.FormatInt(v.port, 10)
|
||||
}
|
||||
}}]
|
||||
}
|
||||
|
||||
if parameter["imagePullPolicy"] != _|_ {
|
||||
imagePullPolicy: parameter.imagePullPolicy
|
||||
}
|
||||
|
||||
if parameter["cmd"] != _|_ {
|
||||
command: parameter.cmd
|
||||
}
|
||||
|
||||
if parameter["env"] != _|_ {
|
||||
env: parameter.env
|
||||
}
|
||||
|
||||
if context["config"] != _|_ {
|
||||
env: context.config
|
||||
}
|
||||
|
||||
if parameter["cpu"] != _|_ {
|
||||
resources: {
|
||||
limits: cpu: parameter.cpu
|
||||
requests: cpu: parameter.cpu
|
||||
}
|
||||
}
|
||||
|
||||
if parameter["memory"] != _|_ {
|
||||
resources: {
|
||||
limits: memory: parameter.memory
|
||||
requests: memory: parameter.memory
|
||||
}
|
||||
}
|
||||
|
||||
if parameter["volumes"] != _|_ && parameter["volumeMounts"] == _|_ {
|
||||
volumeMounts: [ for v in parameter.volumes {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
}}]
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumeMounts: mountsArray.pvc + mountsArray.configMap + mountsArray.secret + mountsArray.emptyDir + mountsArray.hostPath
|
||||
}
|
||||
|
||||
if parameter["livenessProbe"] != _|_ {
|
||||
livenessProbe: parameter.livenessProbe
|
||||
}
|
||||
|
||||
if parameter["readinessProbe"] != _|_ {
|
||||
readinessProbe: parameter.readinessProbe
|
||||
}
|
||||
|
||||
}]
|
||||
|
||||
if parameter["hostAliases"] != _|_ {
|
||||
// +patchKey=ip
|
||||
hostAliases: parameter.hostAliases
|
||||
}
|
||||
|
||||
if parameter["imagePullSecrets"] != _|_ {
|
||||
imagePullSecrets: [ for v in parameter.imagePullSecrets {
|
||||
name: v
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
if parameter["volumes"] != _|_ && parameter["volumeMounts"] == _|_ {
|
||||
volumes: [ for v in parameter.volumes {
|
||||
{
|
||||
name: v.name
|
||||
if v.type == "pvc" {
|
||||
persistentVolumeClaim: claimName: v.claimName
|
||||
}
|
||||
if v.type == "configMap" {
|
||||
configMap: {
|
||||
defaultMode: v.defaultMode
|
||||
name: v.cmName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.type == "secret" {
|
||||
secret: {
|
||||
defaultMode: v.defaultMode
|
||||
secretName: v.secretName
|
||||
if v.items != _|_ {
|
||||
items: v.items
|
||||
}
|
||||
}
|
||||
}
|
||||
if v.type == "emptyDir" {
|
||||
emptyDir: medium: v.medium
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumes: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exposePorts: [
|
||||
for v in parameter.ports if v.expose == true {
|
||||
port: v.port
|
||||
targetPort: v.port
|
||||
if v.name != _|_ {
|
||||
name: v.name
|
||||
}
|
||||
if v.name == _|_ {
|
||||
name: "port-" + strconv.FormatInt(v.port, 10)
|
||||
}
|
||||
},
|
||||
]
|
||||
outputs: {
|
||||
if len(exposePorts) != 0 {
|
||||
webserviceExpose: {
|
||||
apiVersion: "v1"
|
||||
kind: "Service"
|
||||
metadata: name: context.name
|
||||
spec: {
|
||||
selector: "app.oam.dev/component": context.name
|
||||
ports: exposePorts
|
||||
type: parameter.exposeType
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: {
|
||||
// +usage=Specify the labels in the workload
|
||||
labels?: [string]: string
|
||||
|
||||
// +usage=Specify the annotations in the workload
|
||||
annotations?: [string]: string
|
||||
|
||||
// +usage=Which image would you like to use for your service
|
||||
// +short=i
|
||||
image: string
|
||||
|
||||
// +usage=Specify image pull policy for your service
|
||||
imagePullPolicy?: "Always" | "Never" | "IfNotPresent"
|
||||
|
||||
// +usage=Specify image pull secrets for your service
|
||||
imagePullSecrets?: [...string]
|
||||
|
||||
// +ignore
|
||||
// +usage=Deprecated field, please use ports instead
|
||||
// +short=p
|
||||
port?: int
|
||||
|
||||
// +usage=Which ports do you want customer traffic sent to, defaults to 80
|
||||
ports?: [...{
|
||||
// +usage=Number of port to expose on the pod's IP address
|
||||
port: int
|
||||
// +usage=Name of the port
|
||||
name?: string
|
||||
// +usage=Protocol for port. Must be UDP, TCP, or SCTP
|
||||
protocol: *"TCP" | "UDP" | "SCTP"
|
||||
// +usage=Specify if the port should be exposed
|
||||
expose: *false | bool
|
||||
}]
|
||||
|
||||
// +ignore
|
||||
// +usage=Specify what kind of Service you want. options: "ClusterIP", "NodePort", "LoadBalancer", "ExternalName"
|
||||
exposeType: *"ClusterIP" | "NodePort" | "LoadBalancer" | "ExternalName"
|
||||
|
||||
// +ignore
|
||||
// +usage=If addRevisionLabel is true, the revision label will be added to the underlying pods
|
||||
addRevisionLabel: *false | bool
|
||||
|
||||
// +usage=Commands to run in the container
|
||||
cmd?: [...string]
|
||||
|
||||
// +usage=Define arguments by using environment variables
|
||||
env?: [...{
|
||||
// +usage=Environment variable name
|
||||
name: string
|
||||
// +usage=The value of the environment variable
|
||||
value?: string
|
||||
// +usage=Specifies a source the value of this var should come from
|
||||
valueFrom?: {
|
||||
// +usage=Selects a key of a secret in the pod's namespace
|
||||
secretKeyRef?: {
|
||||
// +usage=The name of the secret in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the secret to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
// +usage=Selects a key of a config map in the pod's namespace
|
||||
configMapKeyRef?: {
|
||||
// +usage=The name of the config map in the pod's namespace to select from
|
||||
name: string
|
||||
// +usage=The key of the config map to select from. Must be a valid secret key
|
||||
key: string
|
||||
}
|
||||
}
|
||||
}]
|
||||
|
||||
// +usage=Number of CPU units for the service, like `0.5` (0.5 CPU core), `1` (1 CPU core)
|
||||
cpu?: string
|
||||
|
||||
// +usage=Specifies the attributes of the memory resource required for the container.
|
||||
memory?: string
|
||||
|
||||
volumeMounts?: {
|
||||
// +usage=Mount PVC type volume
|
||||
pvc?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
// +usage=The name of the PVC
|
||||
claimName: string
|
||||
}]
|
||||
// +usage=Mount ConfigMap type volume
|
||||
configMap?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}]
|
||||
// +usage=Mount Secret type volume
|
||||
secret?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}]
|
||||
// +usage=Mount EmptyDir type volume
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
// +usage=Mount HostPath type volume
|
||||
hostPath?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
mountPropagation?: "None" | "HostToContainer" | "Bidirectional"
|
||||
path: string
|
||||
readOnly?: bool
|
||||
}]
|
||||
}
|
||||
|
||||
// +usage=Deprecated field, use volumeMounts instead.
|
||||
volumes?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
// +usage=Specify volume type, options: "pvc","configMap","secret","emptyDir"
|
||||
type: "pvc" | "configMap" | "secret" | "emptyDir"
|
||||
if type == "pvc" {
|
||||
claimName: string
|
||||
}
|
||||
if type == "configMap" {
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}
|
||||
if type == "secret" {
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
key: string
|
||||
path: string
|
||||
mode: *511 | int
|
||||
}]
|
||||
}
|
||||
if type == "emptyDir" {
|
||||
medium: *"" | "Memory"
|
||||
}
|
||||
}]
|
||||
|
||||
// +usage=Instructions for assessing whether the container is alive.
|
||||
livenessProbe?: #HealthProbe
|
||||
|
||||
// +usage=Instructions for assessing whether the container is in a suitable state to serve traffic.
|
||||
readinessProbe?: #HealthProbe
|
||||
|
||||
// +usage=Specify the hostAliases to add
|
||||
hostAliases?: [...{
|
||||
ip: string
|
||||
hostnames: [...string]
|
||||
}]
|
||||
}
|
||||
#HealthProbe: {
|
||||
|
||||
// +usage=Instructions for assessing container health by executing a command. Either this attribute or the httpGet attribute or the tcpSocket attribute MUST be specified. This attribute is mutually exclusive with both the httpGet attribute and the tcpSocket attribute.
|
||||
exec?: {
|
||||
// +usage=A command to be executed inside the container to assess its health. Each space delimited token of the command is a separate array element. Commands exiting 0 are considered to be successful probes, whilst all other exit codes are considered failures.
|
||||
command: [...string]
|
||||
}
|
||||
|
||||
// +usage=Instructions for assessing container health by executing an HTTP GET request. Either this attribute or the exec attribute or the tcpSocket attribute MUST be specified. This attribute is mutually exclusive with both the exec attribute and the tcpSocket attribute.
|
||||
httpGet?: {
|
||||
// +usage=The endpoint, relative to the port, to which the HTTP GET request should be directed.
|
||||
path: string
|
||||
// +usage=The TCP socket within the container to which the HTTP GET request should be directed.
|
||||
port: int
|
||||
host?: string
|
||||
scheme?: *"HTTP" | string
|
||||
httpHeaders?: [...{
|
||||
name: string
|
||||
value: string
|
||||
}]
|
||||
}
|
||||
|
||||
// +usage=Instructions for assessing container health by probing a TCP socket. Either this attribute or the exec attribute or the httpGet attribute MUST be specified. This attribute is mutually exclusive with both the exec attribute and the httpGet attribute.
|
||||
tcpSocket?: {
|
||||
// +usage=The TCP socket within the container that should be probed to assess container health.
|
||||
port: int
|
||||
}
|
||||
|
||||
// +usage=Number of seconds after the container is started before the first probe is initiated.
|
||||
initialDelaySeconds: *0 | int
|
||||
|
||||
// +usage=How often, in seconds, to execute the probe.
|
||||
periodSeconds: *10 | int
|
||||
|
||||
// +usage=Number of seconds after which the probe times out.
|
||||
timeoutSeconds: *1 | int
|
||||
|
||||
// +usage=Minimum consecutive successes for the probe to be considered successful after having failed.
|
||||
successThreshold: *1 | int
|
||||
|
||||
// +usage=Number of consecutive failures required to determine the container is not alive (liveness probe) or not ready (readiness probe).
|
||||
failureThreshold: *3 | int
|
||||
}
|
||||
status:
|
||||
customStatus: |-
|
||||
ready: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.numberReady != _|_ {
|
||||
replicas: context.output.status.numberReady
|
||||
}
|
||||
}
|
||||
desired: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.desiredNumberScheduled != _|_ {
|
||||
replicas: context.output.status.desiredNumberScheduled
|
||||
}
|
||||
}
|
||||
message: "Ready:\(ready.replicas)/\(desired.replicas)"
|
||||
healthPolicy: |-
|
||||
ready: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.numberReady != _|_ {
|
||||
replicas: context.output.status.numberReady
|
||||
}
|
||||
}
|
||||
desired: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.desiredNumberScheduled != _|_ {
|
||||
replicas: context.output.status.desiredNumberScheduled
|
||||
}
|
||||
}
|
||||
current: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.currentNumberScheduled != _|_ {
|
||||
replicas: context.output.status.currentNumberScheduled
|
||||
}
|
||||
}
|
||||
updated: {
|
||||
replicas: *0 | int
|
||||
} & {
|
||||
if context.output.status.updatedNumberScheduled != _|_ {
|
||||
replicas: context.output.status.updatedNumberScheduled
|
||||
}
|
||||
}
|
||||
generation: {
|
||||
metadata: context.output.metadata.generation
|
||||
observed: *0 | int
|
||||
} & {
|
||||
if context.output.status.observedGeneration != _|_ {
|
||||
observed: context.output.status.observedGeneration
|
||||
}
|
||||
}
|
||||
isHealth: (desired.replicas == ready.replicas) && (desired.replicas == updated.replicas) && (desired.replicas == current.replicas) && (generation.observed == generation.metadata || generation.observed > generation.metadata)
|
||||
workload:
|
||||
definition:
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
type: daemonsets.apps
|
||||
|
||||
@@ -14,20 +14,21 @@ spec:
|
||||
cue:
|
||||
template: |
|
||||
#K8sObject: {
|
||||
resource?: string
|
||||
group?: string
|
||||
name?: string
|
||||
// +usage=The resource type for the Kubernetes objects
|
||||
resource?: string
|
||||
// +usage=The group name for the Kubernetes objects
|
||||
group?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects with the name, exclusive to labelSelector
|
||||
name?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects from the namespace. Otherwise, fetch from the application's namespace.
|
||||
namespace?: string
|
||||
cluster?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects from the cluster. Otherwise, fetch from the local cluster.
|
||||
cluster?: string
|
||||
// +usage=If specified, fetch the Kubernetes objects according to the label selector, exclusive to name
|
||||
labelSelector?: [string]: string
|
||||
...
|
||||
}
|
||||
output: {
|
||||
if len(parameter.objects) > 0 {
|
||||
parameter.objects[0]
|
||||
}
|
||||
...
|
||||
}
|
||||
output: parameter.objects[0]
|
||||
outputs: {
|
||||
for i, v in parameter.objects {
|
||||
if i > 0 {
|
||||
@@ -35,7 +36,12 @@ spec:
|
||||
}
|
||||
}
|
||||
}
|
||||
parameter: objects: [...#K8sObject]
|
||||
parameter: {
|
||||
// +usage=If specified, application will fetch native Kubernetes objects according to the object description
|
||||
objects?: [...#K8sObject]
|
||||
// +usage=If specified, the objects in the urls will be loaded.
|
||||
urls?: [...string]
|
||||
}
|
||||
status:
|
||||
customStatus: |-
|
||||
if context.output.apiVersion == "apps/v1" && context.output.kind == "Deployment" {
|
||||
|
||||
@@ -64,6 +64,9 @@ spec:
|
||||
{
|
||||
name: "pvc-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -73,6 +76,9 @@ spec:
|
||||
{
|
||||
name: "configmap-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -103,6 +109,9 @@ spec:
|
||||
{
|
||||
name: "secret-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -133,6 +142,9 @@ spec:
|
||||
{
|
||||
name: "emptydir-" + v.name
|
||||
mountPath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -141,12 +153,28 @@ spec:
|
||||
{
|
||||
name: "pvc-" + v.name
|
||||
devicePath: v.mountPath
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
}
|
||||
},
|
||||
] | []
|
||||
volumesList: pvcVolumesList + configMapVolumesList + secretVolumesList + emptyDirVolumesList
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
patch: spec: template: spec: {
|
||||
// +patchKey=name
|
||||
volumes: pvcVolumesList + configMapVolumesList + secretVolumesList + emptyDirVolumesList
|
||||
volumes: deDupVolumesArray
|
||||
|
||||
containers: [{
|
||||
// +patchKey=name
|
||||
@@ -234,6 +262,7 @@ spec:
|
||||
name: string
|
||||
mountOnly: *false | bool
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
volumeMode: *"Filesystem" | string
|
||||
volumeName?: string
|
||||
accessModes: *["ReadWriteOnce"] | [...string]
|
||||
@@ -275,6 +304,7 @@ spec:
|
||||
configMapKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
data?: {...}
|
||||
@@ -298,6 +328,7 @@ spec:
|
||||
secretKey: string
|
||||
}]
|
||||
mountPath?: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
readOnly: *false | bool
|
||||
stringData?: {...}
|
||||
@@ -313,6 +344,7 @@ spec:
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -20,7 +20,10 @@ spec:
|
||||
for v in parameter.volumeMounts.pvc {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -29,7 +32,10 @@ spec:
|
||||
for v in parameter.volumeMounts.configMap {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -38,7 +44,10 @@ spec:
|
||||
for v in parameter.volumeMounts.secret {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -47,7 +56,10 @@ spec:
|
||||
for v in parameter.volumeMounts.emptyDir {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -56,7 +68,10 @@ spec:
|
||||
for v in parameter.volumeMounts.hostPath {
|
||||
{
|
||||
mountPath: v.mountPath
|
||||
name: v.name
|
||||
if v.subPath != _|_ {
|
||||
subPath: v.subPath
|
||||
}
|
||||
name: v.name
|
||||
}
|
||||
},
|
||||
] | []
|
||||
@@ -119,6 +134,19 @@ spec:
|
||||
},
|
||||
] | []
|
||||
}
|
||||
volumesList: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
deDupVolumesArray: [
|
||||
for val in [
|
||||
for i, vi in volumesList {
|
||||
for j, vj in volumesList if j < i && vi.name == vj.name {
|
||||
_ignore: true
|
||||
}
|
||||
vi
|
||||
},
|
||||
] if val._ignore == _|_ {
|
||||
val
|
||||
},
|
||||
]
|
||||
output: {
|
||||
apiVersion: "apps/v1"
|
||||
kind: "Deployment"
|
||||
@@ -262,7 +290,7 @@ spec:
|
||||
}
|
||||
|
||||
if parameter["volumeMounts"] != _|_ {
|
||||
volumes: volumesArray.pvc + volumesArray.configMap + volumesArray.secret + volumesArray.emptyDir + volumesArray.hostPath
|
||||
volumes: deDupVolumesArray
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -375,6 +403,7 @@ spec:
|
||||
pvc?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
// +usage=The name of the PVC
|
||||
claimName: string
|
||||
}]
|
||||
@@ -382,6 +411,7 @@ spec:
|
||||
configMap?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
cmName: string
|
||||
items?: [...{
|
||||
@@ -394,6 +424,7 @@ spec:
|
||||
secret?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
defaultMode: *420 | int
|
||||
secretName: string
|
||||
items?: [...{
|
||||
@@ -406,12 +437,14 @@ spec:
|
||||
emptyDir?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
medium: *"" | "Memory"
|
||||
}]
|
||||
// +usage=Mount HostPath type volume
|
||||
hostPath?: [...{
|
||||
name: string
|
||||
mountPath: string
|
||||
subPath?: string
|
||||
path: string
|
||||
}]
|
||||
}
|
||||
|
||||
@@ -36,7 +36,6 @@ import (
|
||||
ctrl "sigs.k8s.io/controller-runtime"
|
||||
"sigs.k8s.io/controller-runtime/pkg/healthz"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
ctrlClient "github.com/oam-dev/kubevela/pkg/client"
|
||||
@@ -47,7 +46,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/controller/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/cue/packages"
|
||||
_ "github.com/oam-dev/kubevela/pkg/monitor/metrics"
|
||||
"github.com/oam-dev/kubevela/pkg/monitor/watcher"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/discoverymapper"
|
||||
@@ -56,7 +54,8 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/utils/system"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/util"
|
||||
oamwebhook "github.com/oam-dev/kubevela/pkg/webhook/core.oam.dev"
|
||||
wfTypes "github.com/oam-dev/kubevela/pkg/workflow/types"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow"
|
||||
"github.com/oam-dev/kubevela/pkg/workflow/tasks/custom"
|
||||
"github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
@@ -142,9 +141,9 @@ func main() {
|
||||
standardcontroller.AddOptimizeFlags()
|
||||
standardcontroller.AddAdmissionFlags()
|
||||
flag.IntVar(&resourcekeeper.MaxDispatchConcurrent, "max-dispatch-concurrent", 10, "Set the max dispatch concurrent number, default is 10")
|
||||
flag.IntVar(&wfTypes.MaxWorkflowWaitBackoffTime, "max-workflow-wait-backoff-time", 60, "Set the max workflow wait backoff time, default is 60")
|
||||
flag.IntVar(&wfTypes.MaxWorkflowFailedBackoffTime, "max-workflow-failed-backoff-time", 300, "Set the max workflow wait backoff time, default is 300")
|
||||
flag.IntVar(&wfTypes.MaxWorkflowStepErrorRetryTimes, "max-workflow-step-error-retry-times", 10, "Set the max workflow step error retry times, default is 10")
|
||||
flag.IntVar(&workflow.MaxWorkflowWaitBackoffTime, "max-workflow-wait-backoff-time", 60, "Set the max workflow wait backoff time, default is 60")
|
||||
flag.IntVar(&workflow.MaxWorkflowFailedBackoffTime, "max-workflow-failed-backoff-time", 300, "Set the max workflow wait backoff time, default is 300")
|
||||
flag.IntVar(&custom.MaxWorkflowStepErrorRetryTimes, "max-workflow-step-error-retry-times", 10, "Set the max workflow step error retry times, default is 10")
|
||||
utilfeature.DefaultMutableFeatureGate.AddFlag(flag.CommandLine)
|
||||
|
||||
flag.Parse()
|
||||
@@ -324,13 +323,6 @@ func main() {
|
||||
}
|
||||
klog.InfoS("Use storage driver", "storageDriver", os.Getenv(system.StorageDriverEnv))
|
||||
|
||||
klog.Info("Start the vela application monitor")
|
||||
informer, err := mgr.GetCache().GetInformer(context.Background(), &v1beta1.Application{})
|
||||
if err != nil {
|
||||
klog.ErrorS(err, "Unable to get informer for application")
|
||||
}
|
||||
watcher.StartApplicationMetricsWatcher(informer)
|
||||
|
||||
klog.Info("Start the vela controller manager")
|
||||
|
||||
if err := mgr.Start(ctrl.SetupSignalHandler()); err != nil {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 154 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 113 KiB |
@@ -1,47 +0,0 @@
|
||||
# Shared Resource
|
||||
|
||||
### Background
|
||||
|
||||
In KubeVela, by default, application **owns** resources.
|
||||
It means that resources create by the application should only be controlled by the application that creates it.
|
||||
|
||||
So there are basically two requirements for application creating resources:
|
||||
1. The resource must not exist before the application creating it. It exists, there will be a resource conflict error.
|
||||
2. The resource is expected to be only manageable through its creator. "Others" should not be able to modify it or edit it.
|
||||
|
||||
While dispatching resources, the application will
|
||||
1. Check if resource exists. If exists, check its labels.
|
||||
If "app.oam.dev/name" and "app.oam.dev/namespace" equals to the application's name and namespace, it means this resource is previously created by the same application and the dispatching operation now will become an update operation.
|
||||
The two labels identify the owner of the resource.
|
||||
2. If resource exists, but no label found, then this resource is created before this application. At this time, the application will report a resource conflict error.
|
||||
3. If resource exists, and the labels point to another application, then this resource is managed by other applications. At this time, the current application will also report a resource conflict error.
|
||||
|
||||
With these checks, different applications cannot manage the same resource.
|
||||
|
||||
### Usage
|
||||
|
||||
However, there are scenarios that these two requirements are not met. One of the scenarios is sharing across different Applications.
|
||||
For example, each application wants to create a ConfigMap, but their ConfigMaps are the same.
|
||||
|
||||
To achieve that, KubeVela application could utilize the `shared-resource` policy to make it possible.
|
||||
|
||||
#### create
|
||||
|
||||
When one resource is created as sharing resource, one special annotation `app.oam.dev/shared-by` will be added to the resource.
|
||||
It will record the "sharer" of the resource in time order. The application that firstly creates the resource will set its owner labels to itself.
|
||||
Then it will add itself to the sharer annotation.
|
||||
|
||||
#### share
|
||||
|
||||
When another application comes and wants to share the resource, it will check if the resource is sharable, aka there is at least one sharer in the sharer annotation.
|
||||
If it is sharable, it will add itself to the sharer annotation, but not modify the content of the resource.
|
||||
|
||||
#### delete
|
||||
|
||||
With this mechanism, only the owner of the resource can modify the resource (including updating and state-keeping). Other sharer can only see that resource.
|
||||
When the owner of the resource is gone (application is deleted or do not use this resource anymore), it will give the owner of the application to the next sharer. If no sharer exists, it will finally delete that resource.
|
||||
|
||||
See the following figures for details.
|
||||
|
||||

|
||||

|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,91 +0,0 @@
|
||||
## How to share resources across applications
|
||||
|
||||
Sometimes, you may want different applications to share the same resource.
|
||||
For example, you might have various applications that needs the same namespace to exist.
|
||||
In this case, you can use the `shared-resource` policy to declare which resources should be shared.
|
||||
|
||||
### Usage
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app1
|
||||
spec:
|
||||
components:
|
||||
- name: ns1
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: example
|
||||
- name: cm1
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm1
|
||||
namespace: example
|
||||
data:
|
||||
key: value1
|
||||
policies:
|
||||
- name: shared-resource
|
||||
type: shared-resource
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
resourceTypes: ["Namespace"]
|
||||
```
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app2
|
||||
spec:
|
||||
components:
|
||||
- name: ns2
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: example
|
||||
- name: cm2
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: cm2
|
||||
namespace: example
|
||||
data:
|
||||
key: value2
|
||||
policies:
|
||||
- name: shared-resource
|
||||
type: shared-resource
|
||||
properties:
|
||||
rules:
|
||||
- selector:
|
||||
resourceTypes: ["Namespace"]
|
||||
```
|
||||
|
||||
The above two applications will dispatch the same namespace "example".
|
||||
They will create two different ConfigMap inside namespace "example" respectively.
|
||||
|
||||
Both application use the `shared-resource` policy and declared the namespace resource as shared.
|
||||
In this way, there will be no conflict for creating the same namespace.
|
||||
If the `shared-resource` policy is not used, the second application will report error after it finds that the namespace "example" is managed by the first application.
|
||||
|
||||
The namespace will only be recycled when both applications are removed.
|
||||
|
||||
### Working Detail
|
||||
|
||||
One of the problem for sharing resource is that what will happen if different application holds different configuration for the shared resource.
|
||||
In the `shared-resource` policy, all sharers will be recorded by time order. The first sharer will be able to write the resource while other sharers can only read it. After the first sharer is deleted, it will give the control of the resource to the next sharer. If no sharer is handling it, the resource will be finally removed.
|
||||
@@ -25,3 +25,7 @@ spec:
|
||||
- name: my-mount
|
||||
mountPath: /test
|
||||
claimName: myclaim
|
||||
- name: my-mount
|
||||
mountPath: /test2
|
||||
subPath: /sub
|
||||
claimName: myclaim
|
||||
|
||||
@@ -16,8 +16,9 @@ spec:
|
||||
pvc:
|
||||
- name: test1
|
||||
mountPath: /test/mount/pvc
|
||||
- name: test2
|
||||
- name: test1
|
||||
mountPath: /test/mount2/pvc
|
||||
subPath: /sub
|
||||
configMap:
|
||||
- name: test1
|
||||
mountPath: /test/mount/cm
|
||||
|
||||
@@ -83,7 +83,7 @@ component-pod-view{appName=demo,appNs=default,cluster=prod,clusterNs=default,nam
|
||||
|
||||
#### describe
|
||||
|
||||
Query the pods detail information
|
||||
Query the pods detail infomation
|
||||
|
||||
#### parameter
|
||||
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
# Steps with if
|
||||
|
||||
Every step can specify a `if`, you can use the `if` to determine whether the step should be executed or not.
|
||||
|
||||
## Always
|
||||
|
||||
If you want to execute the step no matter what, for example, send a notification after the component is deployed even it's failed, you can use the `if` with the value `always` like:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: if-always-with-err
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: err-component
|
||||
type: k8s-objects
|
||||
properties:
|
||||
objects:
|
||||
- err: "error case"
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply-err-comp
|
||||
type: apply-component
|
||||
properties:
|
||||
component: err-component
|
||||
- name: notification
|
||||
type: notification
|
||||
if: always
|
||||
properties:
|
||||
slack:
|
||||
url:
|
||||
value: <your slack webhook url>
|
||||
message:
|
||||
text: always
|
||||
```
|
||||
|
||||
## Custom Judgement
|
||||
|
||||
You can also write your own judgement logic to determine whether the step should be executed or not, note that the values of `if` will be executed as cue code. We support some built-in variables to use in `if`, they are:
|
||||
|
||||
* `status`: in this value, you can get the status of the step for judgement like `status.<step-name>.phase == "succeeded"`, or you can use the simplify way `status.<step-name>.succeeded`.
|
||||
* `inputs`: in this value, you can get the inputs of the step for judgement like `inputs.<input-name> == "value"`.
|
||||
|
||||
### Status Example
|
||||
|
||||
If you want to control the step by the status of another step, you can follow the example:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: if-timeout
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: comp-custom-timeout
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
workflow:
|
||||
steps:
|
||||
- name: suspend
|
||||
timeout: 5s
|
||||
type: suspend
|
||||
- name: suspend2
|
||||
# or `status.suspend.reason == "Timeout"`
|
||||
if: status.suspend.timeout
|
||||
type: suspend
|
||||
timeout: 5s
|
||||
- name: notification-1
|
||||
type: notification
|
||||
if: suspend.timeout
|
||||
properties:
|
||||
slack:
|
||||
url:
|
||||
value: <your slack webhook url>
|
||||
message:
|
||||
text: suspend is timeout
|
||||
- name: notification-2
|
||||
type: notification
|
||||
if: status["notification-1"].succeeded
|
||||
properties:
|
||||
slack:
|
||||
url:
|
||||
value: <your slack webhook url>
|
||||
message:
|
||||
text: notification-1 is succeeded
|
||||
```
|
||||
|
||||
### Inputs example
|
||||
|
||||
If you want to control the step by the inputs of another step, you can follow the example:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: if-input
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: comp-custom-timeout
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
workflow:
|
||||
steps:
|
||||
- name: suspend
|
||||
type: suspend
|
||||
timeout: 5s
|
||||
outputs:
|
||||
- name: test
|
||||
valueFrom: context.name + " message"
|
||||
- name: notification
|
||||
type: notification
|
||||
inputs:
|
||||
- from: test
|
||||
parameterKey: slack.message.text
|
||||
if: inputs.test == "if-input message"
|
||||
properties:
|
||||
slack:
|
||||
url:
|
||||
value: <your slack webhook url>
|
||||
message:
|
||||
text: from input
|
||||
```
|
||||
@@ -1,62 +0,0 @@
|
||||
# Timeout steps
|
||||
|
||||
Every step can specify a `timeout`, if the timeout expires and the step has not succeeded, the step will fail with the reason `Timeout`.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```yaml
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: app-with-timeout
|
||||
namespace: default
|
||||
spec:
|
||||
components:
|
||||
- name: comp
|
||||
type: webservice
|
||||
properties:
|
||||
image: crccheck/hello-world
|
||||
port: 8000
|
||||
traits:
|
||||
- type: scaler
|
||||
properties:
|
||||
replicas: 10
|
||||
workflow:
|
||||
steps:
|
||||
- name: apply
|
||||
timeout: 1m
|
||||
type: apply-component
|
||||
properties:
|
||||
component: comp
|
||||
- name: suspend
|
||||
type: suspend
|
||||
timeout: 5s
|
||||
```
|
||||
|
||||
If the first step is succeeded in the time of `1m`, the second step will be executed. If the second step is not resumed in the time of `5s`, the suspend step will be failed with the reason `Timeout`, and the application will end up with the status of `WorkflowTerminated` like:
|
||||
|
||||
```yaml
|
||||
status:
|
||||
status: workflowTerminated
|
||||
workflow:
|
||||
...
|
||||
finished: true
|
||||
message: Terminated
|
||||
mode: StepByStep
|
||||
steps:
|
||||
- firstExecuteTime: "2022-06-22T09:19:42Z"
|
||||
id: gdcwh929ih
|
||||
lastExecuteTime: "2022-06-22T09:20:08Z"
|
||||
name: apply
|
||||
phase: succeeded
|
||||
type: apply-component
|
||||
- firstExecuteTime: "2022-06-22T09:20:08Z"
|
||||
id: rloz8axnju
|
||||
lastExecuteTime: "2022-06-22T09:20:13Z"
|
||||
name: suspend
|
||||
phase: failed
|
||||
reason: Timeout
|
||||
type: suspend
|
||||
suspend: false
|
||||
terminated: true
|
||||
```
|
||||
@@ -14,3 +14,10 @@ Edit a yaml file as `example.yaml`, then execute it with `vela up` command.
|
||||
|
||||
When executing the `step-group` step, the subSteps in the step group are executed in dag mode. The step group will only complete when all subSteps have been executed to completion.
|
||||
SubStep has the same execution behavior as a normal step.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -22,10 +22,10 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Netflix/go-expect"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
|
||||
@@ -49,13 +49,13 @@ var _ = Describe("Addon Test", func() {
|
||||
It("Enable addon test-addon", func() {
|
||||
output, err := e2e.Exec("vela addon enable test-addon")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
Expect(output).To(ContainSubstring("enabled Successfully."))
|
||||
})
|
||||
|
||||
It("Upgrade addon test-addon", func() {
|
||||
output, err := e2e.Exec("vela addon upgrade test-addon")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
Expect(output).To(ContainSubstring("enabled Successfully."))
|
||||
})
|
||||
|
||||
It("Disable addon test-addon", func() {
|
||||
@@ -71,7 +71,7 @@ var _ = Describe("Addon Test", func() {
|
||||
It("Enable addon with input", func() {
|
||||
output, err := e2e.LongTimeExec("vela addon enable test-addon example=redis", 300*time.Second)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
Expect(output).To(ContainSubstring("enabled Successfully."))
|
||||
})
|
||||
|
||||
It("Disable addon test-addon", func() {
|
||||
@@ -83,12 +83,6 @@ var _ = Describe("Addon Test", func() {
|
||||
}, 60*time.Second).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Enable local addon with . as path", func() {
|
||||
output, err := e2e.LongTimeExec("vela addon enable ../../e2e/addon/mock/testdata/sample/.", 600*time.Second)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("sample enabled successfully."))
|
||||
})
|
||||
|
||||
It("Test Change default namespace can work", func() {
|
||||
output, err := e2e.LongTimeExecWithEnv("vela addon list", 600*time.Second, []string{"DEFAULT_VELA_NS=test-vela"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
@@ -97,7 +91,7 @@ var _ = Describe("Addon Test", func() {
|
||||
|
||||
output, err = e2e.LongTimeExecWithEnv("vela addon enable test-addon", 600*time.Second, []string{"DEFAULT_VELA_NS=test-vela"})
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("enabled successfully."))
|
||||
Expect(output).To(ContainSubstring("enabled Successfully."))
|
||||
|
||||
Eventually(func(g Gomega) {
|
||||
g.Expect(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-test-addon", Namespace: "test-vela"}, &v1beta1.Application{})).Should(BeNil())
|
||||
@@ -110,30 +104,6 @@ var _ = Describe("Addon Test", func() {
|
||||
g.Expect(apierrors.IsNotFound(k8sClient.Get(context.Background(), types.NamespacedName{Name: "addon-test-addon", Namespace: "test-vela"}, &v1beta1.Application{}))).Should(BeTrue())
|
||||
}, 60*time.Second).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Enable fluxcd-test-version whose version can't suit system requirements", func() {
|
||||
output, err := e2e.InteractiveExec("vela addon enable fluxcd-test-version", func(c *expect.Console) {
|
||||
_, err = c.SendLine("y")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
Expect(output).To(ContainSubstring("enabled successfully"))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
|
||||
It("Disable addon fluxcd-test-version", func() {
|
||||
output, err := e2e.LongTimeExec("vela addon disable fluxcd-test-version", 600*time.Second)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(output).To(ContainSubstring("Successfully disable addon"))
|
||||
})
|
||||
|
||||
It("Enable fluxcd-test-version whose version can't suit system requirements with 'n' input", func() {
|
||||
output, err := e2e.InteractiveExec("vela addon enable fluxcd-test-version", func(c *expect.Console) {
|
||||
_, err = c.SendLine("n")
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
Expect(output).To(ContainSubstring("you can try another version by command"))
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Addon registry test", func() {
|
||||
|
||||
15
e2e/addon/mock/testdata/sample/metadata.yaml
vendored
15
e2e/addon/mock/testdata/sample/metadata.yaml
vendored
@@ -1,15 +0,0 @@
|
||||
name: sample
|
||||
version: 1.0.1
|
||||
description: This is a test sample addon
|
||||
icon: https://www.terraform.io/assets/images/logo-text-8c3ba8a6.svg
|
||||
url: https://terraform.io/
|
||||
|
||||
tags: []
|
||||
|
||||
deployTo:
|
||||
control_plane: true
|
||||
runtime_cluster: false
|
||||
|
||||
dependencies: []
|
||||
|
||||
invisible: false
|
||||
@@ -1,3 +0,0 @@
|
||||
parameter: {
|
||||
example: *"default" | string
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,26 +0,0 @@
|
||||
apiVersion: v1
|
||||
entries:
|
||||
fluxcd-test-version:
|
||||
- apiVersion: v2
|
||||
appVersion: 1.16.0
|
||||
description: A Helm chart for Kubernetes
|
||||
name: fluxcd-test-version
|
||||
type: application
|
||||
urls:
|
||||
- http://127.0.0.1:9098/helm/fluxcd-test-version-1.0.0.tgz
|
||||
version: 1.0.0
|
||||
annotations:
|
||||
system.vela: ">=1.3.0"
|
||||
system.kubernetes: ">=1.10.0"
|
||||
- apiVersion: v2
|
||||
appVersion: 1.16.0
|
||||
description: A Helm chart for Kubernetes
|
||||
name: fluxcd-test-version
|
||||
type: application
|
||||
urls:
|
||||
- http://127.0.0.1:9098/helm/fluxcd-test-version-2.0.0.tgz
|
||||
version: 2.0.0
|
||||
annotations:
|
||||
system.vela: ">=1.5.0"
|
||||
system.kubernetes: ">=1.30.0"
|
||||
generated: "2022-06-15T13:17:04.733573+08:00"
|
||||
@@ -39,7 +39,7 @@ var (
|
||||
apiVersion: v1
|
||||
data:
|
||||
registries: '{ "KubeVela":{ "name": "KubeVela", "oss": { "end_point": "http://REGISTRY_ADDR",
|
||||
"bucket": "" } }, "Test-Helm":{ "name": "Test-Helm", "helm": { "name":"", "password":"", "url": "http://HELM_ADDR"} } }'
|
||||
"bucket": "" } } }'
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: vela-addon-registry
|
||||
@@ -59,7 +59,6 @@ func ApplyMockServerConfig() error {
|
||||
cm := v1.ConfigMap{}
|
||||
|
||||
registryCmStr := strings.ReplaceAll(velaRegistry, "REGISTRY_ADDR", fmt.Sprintf("127.0.0.1:%d", Port))
|
||||
registryCmStr = strings.ReplaceAll(registryCmStr, "HELM_ADDR", fmt.Sprintf("127.0.0.1:%d/helm", Port))
|
||||
|
||||
err = yaml.Unmarshal([]byte(registryCmStr), &cm)
|
||||
if err != nil {
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"fmt"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"path"
|
||||
@@ -47,7 +46,6 @@ func main() {
|
||||
log.Fatal("Apply mock server config to ConfigMap fail")
|
||||
}
|
||||
http.HandleFunc("/", ossHandler)
|
||||
http.HandleFunc("/helm/", helmHandler)
|
||||
err = http.ListenAndServe(fmt.Sprintf(":%d", utils.Port), nil)
|
||||
if err != nil {
|
||||
log.Fatal("ListenAndServe: ", err)
|
||||
@@ -105,29 +103,6 @@ var ossHandler http.HandlerFunc = func(rw http.ResponseWriter, req *http.Request
|
||||
}
|
||||
}
|
||||
|
||||
var helmHandler http.HandlerFunc = func(rw http.ResponseWriter, req *http.Request) {
|
||||
switch {
|
||||
case strings.Contains(req.URL.Path, "index.yaml"):
|
||||
file, err := ioutil.ReadFile("./e2e/addon/mock/testrepo/helm-repo/index.yaml")
|
||||
if err != nil {
|
||||
_, _ = rw.Write([]byte(err.Error()))
|
||||
}
|
||||
rw.Write(file)
|
||||
case strings.Contains(req.URL.Path, "fluxcd-test-version-1.0.0.tgz"):
|
||||
file, err := ioutil.ReadFile("./e2e/addon/mock/testrepo/helm-repo/fluxcd-test-version-1.0.0.tgz")
|
||||
if err != nil {
|
||||
_, _ = rw.Write([]byte(err.Error()))
|
||||
}
|
||||
rw.Write(file)
|
||||
case strings.Contains(req.URL.Path, "fluxcd-test-version-2.0.0.tgz"):
|
||||
file, err := ioutil.ReadFile("./e2e/addon/mock/testrepo/helm-repo/fluxcd-test-version-2.0.0.tgz")
|
||||
if err != nil {
|
||||
_, _ = rw.Write([]byte(err.Error()))
|
||||
}
|
||||
rw.Write(file)
|
||||
}
|
||||
}
|
||||
|
||||
func init() {
|
||||
_ = fs.WalkDir(testData, "testdata", func(path string, d fs.DirEntry, err error) error {
|
||||
path = strings.TrimPrefix(path, "testdata/")
|
||||
|
||||
@@ -190,7 +190,7 @@ var ApplicationInitIntercativeCliContext = func(context string, appName string,
|
||||
var ApplicationDeleteWithWaitOptions = func(context string, appName string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should print successful deletion information", func() {
|
||||
cli := fmt.Sprintf("vela delete %s --wait -y", appName)
|
||||
cli := fmt.Sprintf("vela delete %s --wait", appName)
|
||||
output, err := e2e.ExecAndTerminate(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("deleted"))
|
||||
@@ -218,7 +218,7 @@ var ApplicationDeleteWithForceOptions = func(context string, appName string) boo
|
||||
return k8sClient.Update(ctx, app)
|
||||
}, time.Second*3, time.Millisecond*300).Should(gomega.BeNil())
|
||||
|
||||
cli := fmt.Sprintf("vela delete %s --force -y", appName)
|
||||
cli := fmt.Sprintf("vela delete %s --force", appName)
|
||||
output, err := e2e.LongTimeExec(cli, 3*time.Minute)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("timed out"))
|
||||
@@ -230,7 +230,7 @@ var ApplicationDeleteWithForceOptions = func(context string, appName string) boo
|
||||
g.Expect(k8sClient.Update(ctx, app)).Should(gomega.Succeed())
|
||||
}, time.Second*5, time.Millisecond*300).Should(gomega.Succeed())
|
||||
|
||||
cli = fmt.Sprintf("vela delete %s --force -y", appName)
|
||||
cli = fmt.Sprintf("vela delete %s --force", appName)
|
||||
output, err = e2e.ExecAndTerminate(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("deleted"))
|
||||
|
||||
@@ -133,7 +133,7 @@ var (
|
||||
WorkloadDeleteContext = func(context string, applicationName string) bool {
|
||||
return ginkgo.Context(context, func() {
|
||||
ginkgo.It("should print successful deletion information", func() {
|
||||
cli := fmt.Sprintf("vela delete %s -y", applicationName)
|
||||
cli := fmt.Sprintf("vela delete %s", applicationName)
|
||||
output, err := Exec(cli)
|
||||
gomega.Expect(err).NotTo(gomega.HaveOccurred())
|
||||
gomega.Expect(output).To(gomega.ContainSubstring("deleted from namespace"))
|
||||
|
||||
53
go.mod
53
go.mod
@@ -16,8 +16,6 @@ require (
|
||||
github.com/barnettZQG/inject v0.0.1
|
||||
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869
|
||||
github.com/briandowns/spinner v1.11.1
|
||||
github.com/chartmuseum/helm-push v0.10.2
|
||||
github.com/cloudtty/cloudtty v0.2.0
|
||||
github.com/containerd/containerd v1.5.13
|
||||
github.com/coreos/go-oidc v2.1.0+incompatible
|
||||
github.com/coreos/prometheus-operator v0.41.1
|
||||
@@ -25,7 +23,7 @@ require (
|
||||
github.com/davecgh/go-spew v1.1.1
|
||||
github.com/deckarep/golang-set v1.7.1
|
||||
github.com/emicklei/go-restful-openapi/v2 v2.3.0
|
||||
github.com/emicklei/go-restful/v3 v3.8.0
|
||||
github.com/emicklei/go-restful/v3 v3.0.0-rc2
|
||||
github.com/evanphx/json-patch v4.12.0+incompatible
|
||||
github.com/fatih/camelcase v1.0.0
|
||||
github.com/fatih/color v1.13.0
|
||||
@@ -48,7 +46,6 @@ require (
|
||||
github.com/hashicorp/hcl/v2 v2.9.1
|
||||
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
|
||||
github.com/imdario/mergo v0.3.12
|
||||
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c
|
||||
github.com/kubevela/prism v1.4.1-0.20220613123457-94f1190f87c2
|
||||
github.com/kyokomi/emoji v2.2.4+incompatible
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.1
|
||||
@@ -59,7 +56,7 @@ require (
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/onsi/ginkgo v1.16.5
|
||||
github.com/onsi/gomega v1.19.0
|
||||
github.com/opencontainers/runc v1.1.3 // indirect
|
||||
github.com/opencontainers/runc v1.0.3 // indirect
|
||||
github.com/openkruise/kruise-api v1.1.0
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
@@ -76,7 +73,7 @@ require (
|
||||
go.mongodb.org/mongo-driver v1.5.1
|
||||
go.uber.org/zap v1.19.1
|
||||
golang.org/x/crypto v0.0.0-20220507011949-2cf3adece122
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211
|
||||
golang.org/x/tools v0.1.11-0.20220316014157-77aa08bb151a // indirect
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0
|
||||
@@ -86,7 +83,7 @@ require (
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
gotest.tools v2.2.0+incompatible
|
||||
helm.sh/helm/v3 v3.7.2
|
||||
istio.io/client-go v1.13.4
|
||||
istio.io/client-go v0.0.0-20210128182905-ee2edd059e02
|
||||
k8s.io/api v0.23.6
|
||||
k8s.io/apiextensions-apiserver v0.23.6
|
||||
k8s.io/apimachinery v0.23.6
|
||||
@@ -94,7 +91,6 @@ require (
|
||||
k8s.io/cli-runtime v0.23.6
|
||||
k8s.io/client-go v0.23.6
|
||||
k8s.io/component-base v0.23.6
|
||||
k8s.io/helm v2.17.0+incompatible
|
||||
k8s.io/klog v1.0.0
|
||||
k8s.io/klog/v2 v2.60.1
|
||||
k8s.io/kube-aggregator v0.23.0
|
||||
@@ -110,21 +106,7 @@ require (
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/ghodss/yaml v1.0.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute v1.7.0 // indirect
|
||||
cloud.google.com/go/compute v1.6.1 // indirect
|
||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest v0.11.18 // indirect
|
||||
@@ -164,8 +146,9 @@ require (
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/creack/pty v1.1.11 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 // indirect
|
||||
github.com/docker/cli v20.10.16+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.1+incompatible // indirect
|
||||
github.com/docker/docker v20.10.16+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
@@ -183,6 +166,7 @@ require (
|
||||
github.com/fluxcd/pkg/apis/meta v0.13.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.5.1 // indirect
|
||||
github.com/fvbommel/sortorder v1.0.1 // indirect
|
||||
github.com/ghodss/yaml v1.0.0 // indirect
|
||||
github.com/go-errors/errors v1.0.1 // indirect
|
||||
github.com/go-logr/zapr v1.2.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
@@ -206,6 +190,8 @@ require (
|
||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
@@ -215,6 +201,7 @@ require (
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/klauspost/compress v1.15.4 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/kr/pty v1.1.8 // indirect
|
||||
@@ -267,6 +254,7 @@ require (
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/tjfoc/gmsm v1.3.2 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.0.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.2 // indirect
|
||||
@@ -293,13 +281,16 @@ require (
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f // indirect
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
|
||||
golang.org/x/net v0.0.0-20220516155154-20f960328961 // indirect
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 // indirect
|
||||
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 // indirect
|
||||
google.golang.org/grpc v1.47.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3 // indirect
|
||||
google.golang.org/grpc v1.45.0 // indirect
|
||||
google.golang.org/protobuf v1.28.0 // indirect
|
||||
gopkg.in/gorp.v1 v1.7.2 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.63.2 // indirect
|
||||
@@ -308,8 +299,8 @@ require (
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
|
||||
gopkg.in/warnings.v0 v0.1.2 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
istio.io/api v0.0.0-20220512212136-561ffec82582 // indirect
|
||||
istio.io/gogo-genproto v0.0.0-20211208193508-5ab4acc9eb1e // indirect
|
||||
istio.io/api v0.0.0-20210128181506-0c4b8e54850f // indirect
|
||||
istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a // indirect
|
||||
oras.land/oras-go v0.4.0 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy v0.0.30 // indirect
|
||||
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.30 // indirect
|
||||
|
||||
141
go.sum
141
go.sum
@@ -34,9 +34,8 @@ cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+Y
|
||||
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
|
||||
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
|
||||
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
|
||||
cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y=
|
||||
cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A=
|
||||
cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8=
|
||||
cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
@@ -48,14 +47,12 @@ cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTB
|
||||
cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM=
|
||||
cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M=
|
||||
cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s=
|
||||
cloud.google.com/go/compute v1.6.1 h1:2sMmt8prCn7DPaG4Pmh0N3Inmc8cT8ae5k1M6VJ9Wqc=
|
||||
cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU=
|
||||
cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk=
|
||||
cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/firestore v1.6.0/go.mod h1:afJwI0vaXwAG54kI7A//lP/lSPDkQORQuMkv56TxEPU=
|
||||
cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
@@ -68,7 +65,6 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y=
|
||||
collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE=
|
||||
contrib.go.opencensus.io/exporter/ocagent v0.6.0/go.mod h1:zmKjrJcdo0aYcVS7bmEeSEBLPA9YJp5bjrofdU3pIXs=
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.4/go.mod h1:aXENhDJ1Y4lIg4EUaVTwzvYETVNZk10Pu26tevFKLUc=
|
||||
@@ -161,7 +157,6 @@ github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZC
|
||||
github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o=
|
||||
github.com/Masterminds/sprig/v3 v3.2.2 h1:17jRggJu518dr3QaafizSXOjKYp94wKfABxUmyxvxX8=
|
||||
github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
|
||||
github.com/Masterminds/squirrel v1.5.0/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/Masterminds/squirrel v1.5.2 h1:UiOEi2ZX4RCSkpiNDQN5kro/XIBpSRk9iTqdIRPzUXE=
|
||||
github.com/Masterminds/squirrel v1.5.2/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
|
||||
github.com/Masterminds/vcs v1.13.1/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA=
|
||||
@@ -182,7 +177,6 @@ github.com/Microsoft/hcsshim v0.8.9/go.mod h1:5692vkUqntj1idxauYlpoINNKeqCiG6Sg3
|
||||
github.com/Microsoft/hcsshim v0.8.14/go.mod h1:NtVKoYxQuTLx6gEq0L96c9Ju4JbRJ4nY2ow3VK6a9Lg=
|
||||
github.com/Microsoft/hcsshim v0.8.15/go.mod h1:x38A4YbHbdxJtc0sF6oIz+RG0npwSCAvn69iY6URG00=
|
||||
github.com/Microsoft/hcsshim v0.8.16/go.mod h1:o5/SZqmR7x9JNKsW3pu+nqHm0MF8vbA+VxGOoXdC600=
|
||||
github.com/Microsoft/hcsshim v0.8.18/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||
github.com/Microsoft/hcsshim v0.8.21/go.mod h1:+w2gRZ5ReXQhFOrvSQeNfhrYB/dg3oDwTOcER2fw4I4=
|
||||
github.com/Microsoft/hcsshim v0.8.24 h1:jP+GMeRXIR1sH1kG4lJr9ShmSjVrua5jmFZDtfYGkn4=
|
||||
github.com/Microsoft/hcsshim v0.8.24/go.mod h1:4zegtUJth7lAvFyc6cH2gGQ5B3OFQim01nnU2M8jKDg=
|
||||
@@ -372,12 +366,9 @@ github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41
|
||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
||||
github.com/charithe/durationcheck v0.0.8/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
|
||||
github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6prSM8ap1UCpNKtgg=
|
||||
github.com/chartmuseum/helm-push v0.10.2 h1:vuzgu+j+2yKOpPtfF4ksD7RC9Y7wAwrHNpiWDnzAZzM=
|
||||
github.com/chartmuseum/helm-push v0.10.2/go.mod h1:s6xTICU31jKdLkOXS+GgaR61E+oU4h8TWb1yZcHq8OE=
|
||||
github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU=
|
||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||
github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
@@ -387,13 +378,10 @@ github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLI
|
||||
github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs=
|
||||
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
|
||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cloudtty/cloudtty v0.2.0 h1:QvDbb2hZl7nSfLDrKkbjIixjkW6seSVBX3N/GRmioyM=
|
||||
github.com/cloudtty/cloudtty v0.2.0/go.mod h1:RRVb8fLrfpzjsLFqaUk74ouRvZ2drVCvSN3ZzidHju8=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
@@ -401,7 +389,6 @@ github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XP
|
||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
@@ -433,7 +420,6 @@ github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on
|
||||
github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE=
|
||||
github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw=
|
||||
github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ=
|
||||
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
|
||||
github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
|
||||
@@ -449,7 +435,6 @@ github.com/containerd/containerd v1.5.0-beta.4/go.mod h1:GmdgZd2zA2GYIBZ0w09Zvgq
|
||||
github.com/containerd/containerd v1.5.0-rc.0/go.mod h1:V/IXoMqNGgBlabz3tHD2TWDoTJseu1FGOKuoA4nNb2s=
|
||||
github.com/containerd/containerd v1.5.1/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||
github.com/containerd/containerd v1.5.2/go.mod h1:0DOxVqwDy2iZvrZp2JUx/E+hS0UNTVn7dJnIOwtYR4g=
|
||||
github.com/containerd/containerd v1.5.4/go.mod h1:sx18RgvW6ABJ4iYUw7Q5x7bgFOAB9B6G7+yO0XBc4zw=
|
||||
github.com/containerd/containerd v1.5.7/go.mod h1:gyvv6+ugqY25TiXxcZC3L5yOeYgEw0QMhscqVp1AR9c=
|
||||
github.com/containerd/containerd v1.5.13 h1:XqvKw9i4P7/mFrC3TSM7yV5cwFZ9avXe6M3YANKnzEE=
|
||||
github.com/containerd/containerd v1.5.13/go.mod h1:3AlCrzKROjIuP3JALsY14n8YtntaUDBu7vek+rPN5Vc=
|
||||
@@ -546,9 +531,8 @@ github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd h1:2ZdR/HyjXFIo6KxmM08jBLeiJs7GRdGmb6qPKQANGvI=
|
||||
github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd/go.mod h1:0sB8XOV2zy1GdZvSMY0/5QzKQJUiNSek08wbAYHJbws=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg=
|
||||
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI=
|
||||
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||
github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ=
|
||||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
||||
@@ -629,9 +613,8 @@ github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao
|
||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||
github.com/emicklei/go-restful-openapi/v2 v2.3.0 h1:tDgSCzQrkk4N+Isos0zGBYX/GTINjmQuP9BvITbEe38=
|
||||
github.com/emicklei/go-restful-openapi/v2 v2.3.0/go.mod h1:bs67E3SEVgSmB3qDuRLqpS0NcpheqtsCCMhW2/jml1E=
|
||||
github.com/emicklei/go-restful/v3 v3.0.0-rc2 h1:UkWzdUozgtjQzYuqSNQy+PuYxD4/DCzYucakgzWKolU=
|
||||
github.com/emicklei/go-restful/v3 v3.0.0-rc2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw=
|
||||
github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
|
||||
github.com/emicklei/proto v1.6.15 h1:XbpwxmuOPrdES97FrSfpyy67SSCV/wBIKXqgJzh6hNw=
|
||||
github.com/emicklei/proto v1.6.15/go.mod h1:rn1FgRS/FANiZdD2djyH7TMA9jdRDcYQ9IEN9yvjX0A=
|
||||
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
|
||||
@@ -645,7 +628,6 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.0.14/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/esimonov/ifshort v1.0.2/go.mod h1:yZqNJUrNn20K8Q9n2CrjTKYyVEmX209Hgu+M1LBpeZE=
|
||||
@@ -914,7 +896,6 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf
|
||||
github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
|
||||
github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE=
|
||||
github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
|
||||
@@ -1076,7 +1057,6 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/gax-go v2.0.2+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
@@ -1084,7 +1064,6 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf
|
||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
||||
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/gnostic v0.0.0-20170426233943-68f4ded48ba9/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
github.com/googleapis/gnostic v0.1.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
|
||||
@@ -1095,7 +1074,6 @@ github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3i
|
||||
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
|
||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
|
||||
github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
|
||||
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
|
||||
@@ -1347,8 +1325,6 @@ github.com/klauspost/compress v1.15.4/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHU
|
||||
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg=
|
||||
github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c h1:N7A4JCA2G+j5fuFxCsJqjFU/sZe0mj8H0sSoSwbaikw=
|
||||
github.com/koding/websocketproxy v0.0.0-20181220232114-7ed82d81a28c/go.mod h1:Nn5wlyECw3iJrzi0AhIWg+AJUb4PlRQVW4/3XHH1LZA=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -1529,9 +1505,8 @@ github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/
|
||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||
github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
||||
github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM=
|
||||
github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A=
|
||||
github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI=
|
||||
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
|
||||
github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ=
|
||||
github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo=
|
||||
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
|
||||
@@ -1626,8 +1601,6 @@ github.com/onsi/ginkgo v1.16.1/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvw
|
||||
github.com/onsi/ginkgo v1.16.2/go.mod h1:CObGmKUOKaSC0RjmoAK7tKyn4Azo5P2IWuoMnvwxz1E=
|
||||
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
|
||||
github.com/onsi/ginkgo/v2 v2.1.4 h1:GNapqRSid3zijZ9H77KrgVG4/8KqiyRsxcSxe+7ApXY=
|
||||
@@ -1647,7 +1620,6 @@ github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDs
|
||||
github.com/onsi/gomega v1.11.0/go.mod h1:azGKhqFUon9Vuj0YmTfLSmx0FUwqXYSTl5re8lQLTUg=
|
||||
github.com/onsi/gomega v1.13.0/go.mod h1:lRk9szgn8TxENtWd0Tp4c3wjlRfMTMH27I+3Je41yGY=
|
||||
github.com/onsi/gomega v1.14.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/onsi/gomega v1.15.0/go.mod h1:cIuvLEne0aoVhAgh/O6ac0Op8WWw9H6eYCriF+tEHG0=
|
||||
github.com/onsi/gomega v1.16.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
|
||||
@@ -1670,8 +1642,8 @@ github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h
|
||||
github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U=
|
||||
github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0=
|
||||
github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w=
|
||||
github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
|
||||
github.com/opencontainers/runc v1.0.3 h1:1hbqejyQWCJBvtKAfdO0b1FmaEf2z/bxnjqbARass5k=
|
||||
github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0=
|
||||
github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
@@ -1682,12 +1654,8 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo
|
||||
github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE=
|
||||
github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo=
|
||||
github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8=
|
||||
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
|
||||
github.com/openkruise/kruise-api v1.0.0/go.mod h1:kxV/UA/vrf/hz3z+kL21c0NOawC6K1ZjaKcJFgiOwsE=
|
||||
github.com/openkruise/kruise-api v1.1.0 h1:ZRhV0FnxUp4XHc60YPkUqj2LJD4GRFB92qhtdgU6Zhc=
|
||||
github.com/openkruise/kruise-api v1.1.0/go.mod h1:kxV/UA/vrf/hz3z+kL21c0NOawC6K1ZjaKcJFgiOwsE=
|
||||
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e h1:jUMEDsA0OOpp0262pK8MV8M2glac+jIjx+q5Aydn6G0=
|
||||
github.com/openkruise/rollouts v0.1.1-0.20220622054609-149e5a48da5e/go.mod h1:SORsT96ssCqMJYSVA90v6Z52utlV2jxPlyGh4czRfHA=
|
||||
github.com/openshift/api v0.0.0-20210915110300-3cd8091317c4/go.mod h1:RsQCVJu4qhUawxxDP7pGlwU3IA4F01wYm3qKEu29Su8=
|
||||
github.com/openshift/api v0.0.0-20211209135129-c58d9f695577/go.mod h1:DoslCwtqUpr3d/gsbq4ZlkaMEdYqKxuypsDjorcHhME=
|
||||
github.com/openshift/build-machinery-go v0.0.0-20210115170933-e575b44a7a94/go.mod h1:b1BuldmJlbA/xYtdZvKi+7j5YGB44qJUJDZ9zwiNCfE=
|
||||
@@ -1880,7 +1848,6 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
|
||||
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||
github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo=
|
||||
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
|
||||
github.com/securego/gosec/v2 v2.8.0/go.mod h1:hJZ6NT5TqoY+jmOsaxAV4cXoEdrMRLVaNPnSpUCvCZs=
|
||||
github.com/securego/gosec/v2 v2.9.1/go.mod h1:oDcDLcatOJxkCGaCaq8lua1jTnYf6Sou4wdiJ1n4iHc=
|
||||
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
|
||||
@@ -2223,7 +2190,6 @@ go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
golang.org/x/arch v0.0.0-20180920145803-b19384d3c130/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8=
|
||||
@@ -2400,17 +2366,13 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211215060638-4ddde0e984e9/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220516155154-20f960328961 h1:+W/iTMPG0EL7aW+/atntZwZrvSRIj3m3yX414dSULUU=
|
||||
golang.org/x/net v0.0.0-20220516155154-20f960328961/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -2432,10 +2394,8 @@ golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ
|
||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE=
|
||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2 h1:+jnHzr9VPj32ykQVai5DNahi9+NSp7yYuCsl5eAQtL0=
|
||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@@ -2448,9 +2408,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4=
|
||||
golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f h1:Ax0t5p6N38Ga0dThY21weqDEyz2oklo4IvDkpigvkD8=
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180117170059-2c42eef0765b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -2579,20 +2538,16 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210817190340-bfb29a6856f2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -2602,13 +2557,8 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a h1:N2T1jUrTQE9Re6TFF5PhvEHXHCguynGhKjWVsIUt5cY=
|
||||
golang.org/x/sys v0.0.0-20220513210249-45d2b4557a2a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
@@ -2779,10 +2729,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
|
||||
golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f h1:uF6paiQQebLeSXkrTqHqz0MXhXXS1KgF41eUdBNvxK0=
|
||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
gomodules.xyz/jsonpatch/v2 v2.0.1/go.mod h1:IhYNNY4jnS53ZnfE4PAmpKtDpTCj1JFXc+3mwe7XcUU=
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0 h1:4pT439QV83L+G9FkcCriY6EkpcK6r6bK+A5FBUMI7qY=
|
||||
gomodules.xyz/jsonpatch/v2 v2.2.0/go.mod h1:WXp+iVDkoLQqPudfQ9GBlwB2eZ5DKOnjQZCYdOS8GPY=
|
||||
@@ -2835,9 +2783,6 @@ google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/S
|
||||
google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8=
|
||||
google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs=
|
||||
google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA=
|
||||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
@@ -2905,7 +2850,6 @@ google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6D
|
||||
google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
|
||||
google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A=
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||
@@ -2937,15 +2881,8 @@ google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2I
|
||||
google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3 h1:SeX3QUcBj3fciwnfPT9kt5gBhFy/FCZtYZ+I/RB8agc=
|
||||
google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo=
|
||||
google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
|
||||
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 h1:W70HjnmXFJm+8RNjOpIDYW2nKsSi/af0VvIZUtYkwuU=
|
||||
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
|
||||
@@ -2964,6 +2901,7 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.0/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
@@ -2984,11 +2922,8 @@ google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
|
||||
google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.45.0 h1:NEpgUqV3Z+ZjkqMsxMg11IaDrXY4RY6CQukSGK0uI1M=
|
||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
@@ -3083,7 +3018,6 @@ gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81
|
||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
helm.sh/helm/v3 v3.7.0/go.mod h1:DajHtQTe8KrjNmvy5gxWkosFKaADrS3uRS5EkDtsmI4=
|
||||
helm.sh/helm/v3 v3.7.2 h1:xn1OxcZEpgKpp4CCpPz1KKUyb9gAtTouXV2E3S8ChYQ=
|
||||
helm.sh/helm/v3 v3.7.2/go.mod h1:UXuiAn0+FfBpqbiMuwWt8/aAKkfJvnWLBJ6f4HcFs0M=
|
||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
@@ -3097,12 +3031,12 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||
honnef.co/go/tools v0.2.0/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
||||
honnef.co/go/tools v0.2.1/go.mod h1:lPVVZ2BS5TfnjLyizF7o7hv7j9/L+8cZY2hLyjP9cGY=
|
||||
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
|
||||
istio.io/api v0.0.0-20220512212136-561ffec82582 h1:AzLIET6ePAqxlWaXA6GOzapoRX1GRC6mZ8GY+cQIWYU=
|
||||
istio.io/api v0.0.0-20220512212136-561ffec82582/go.mod h1:8ZZgyVgYrHhsFQarEgTfPnMGpdgTDZbxSjYhdwTUuAQ=
|
||||
istio.io/client-go v1.13.4 h1:QJBFBkOaplyL/uBL7xo75mdE5G0i1uR6BR0u9/Wuo1E=
|
||||
istio.io/client-go v1.13.4/go.mod h1:kM3WH/HCojq7BhCD894SZuaAXUKMswT+VQRaEEhTGj0=
|
||||
istio.io/gogo-genproto v0.0.0-20211208193508-5ab4acc9eb1e h1:z2WI3y55w0K3c6hmarcp5EcOiP4vVpTBXA8nYstP+cE=
|
||||
istio.io/gogo-genproto v0.0.0-20211208193508-5ab4acc9eb1e/go.mod h1:vJDAniIqryf/z///fgZqVPKJ7N2lBk7Gg8DCTB7oCfU=
|
||||
istio.io/api v0.0.0-20210128181506-0c4b8e54850f h1:zUFsawgPj5oI9p5cf91YCExRlxLIVsEkIunN9ODUSJs=
|
||||
istio.io/api v0.0.0-20210128181506-0c4b8e54850f/go.mod h1:88HN3o1fSD1jo+Z1WTLlJfMm9biopur6Ct9BFKjiB64=
|
||||
istio.io/client-go v0.0.0-20210128182905-ee2edd059e02 h1:ZA8Y2gKkKtEeYuKfqlEzIBDfU4IE5uIAdsXDeD41T9w=
|
||||
istio.io/client-go v0.0.0-20210128182905-ee2edd059e02/go.mod h1:oXMjFUWhxlReUSbg4i3GjKgOhSX1WgD68ZNlHQEcmQg=
|
||||
istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a h1:w7zILua2dnYo9CxImhpNW4NE/8ZxEoc/wfBfHrhUhrE=
|
||||
istio.io/gogo-genproto v0.0.0-20190930162913-45029607206a/go.mod h1:OzpAts7jljZceG4Vqi5/zXy/pOg1b209T3jb7Nv5wIs=
|
||||
k8s.io/api v0.0.0-20190620084959-7cf5895f2711/go.mod h1:TBhBqb1AWbBQbW3XRusr7n7E4v2+5ZY8r8sAMnyFC5A=
|
||||
k8s.io/api v0.0.0-20190813020757-36bff7324fb7/go.mod h1:3Iy+myeAORNCLgjd/Xu9ebwN7Vh59Bw0vh9jhoX+V58=
|
||||
k8s.io/api v0.0.0-20190918155943-95b840bb6a1f/go.mod h1:uWuOHnjmNrtQomJrvEBg0c0HRNyQ+8KTEERVsK0PW48=
|
||||
@@ -3114,6 +3048,7 @@ k8s.io/api v0.17.2/go.mod h1:BS9fjjLc4CMuqfSO8vgbHPKMt5+SF0ET6u/RVDihTo4=
|
||||
k8s.io/api v0.17.5/go.mod h1:0zV5/ungglgy2Rlm3QK8fbxkXVs+BSJWpJP/+8gUVLY=
|
||||
k8s.io/api v0.18.0-beta.2/go.mod h1:2oeNnWEqcSmaM/ibSh3t7xcIqbkGXhzZdn4ezV9T4m0=
|
||||
k8s.io/api v0.18.0/go.mod h1:q2HRQkfDzHMBZL9l/y9rH63PkQl4vae0xRT+8prbrK8=
|
||||
k8s.io/api v0.18.1/go.mod h1:3My4jorQWzSs5a+l7Ge6JBbIxChLnY8HnuT58ZWolss=
|
||||
k8s.io/api v0.18.2/go.mod h1:SJCWI7OLzhZSvbY7U8zwNl9UA4o1fizoug34OV/2r78=
|
||||
k8s.io/api v0.18.3/go.mod h1:UOaMwERbqJMfeeeHc8XJKawj4P9TgDRnViIqqBeH2QA=
|
||||
k8s.io/api v0.18.6/go.mod h1:eeyxr+cwCjMdLAmr2W3RyDI0VvTawSg/3RFFBEnmZGI=
|
||||
@@ -3126,10 +3061,7 @@ k8s.io/api v0.21.1/go.mod h1:FstGROTmsSHBarKc8bylzXih8BLNYTiS3TZcsoEDg2s=
|
||||
k8s.io/api v0.21.2/go.mod h1:Lv6UGJZ1rlMI1qusN8ruAp9PUBFyBwpEHAdG24vIsiU=
|
||||
k8s.io/api v0.21.3/go.mod h1:hUgeYHUbBp23Ue4qdX9tR8/ANi/g3ehylAqDn9NWVOg=
|
||||
k8s.io/api v0.22.1/go.mod h1:bh13rkTp3F1XEaLGykbyRD2QaTTzPm0e/BMd8ptFONY=
|
||||
k8s.io/api v0.22.2/go.mod h1:y3ydYpLJAaDI+BbSe2xmGcqxiWHmWjkEeIbiwHvnPR8=
|
||||
k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk=
|
||||
k8s.io/api v0.22.4/go.mod h1:Rgs+9gIGYC5laXQSZZ9JqT5NevNgoGiOdVWi1BAB3qk=
|
||||
k8s.io/api v0.22.6/go.mod h1:q1F7IfaNrbi/83ebLy3YFQYLjPSNyunZ/IXQxMmbwCg=
|
||||
k8s.io/api v0.23.0/go.mod h1:8wmDdLBHBNxtOIytwLstXt5E9PddnZb0GaMcqsvDBpg=
|
||||
k8s.io/api v0.23.1/go.mod h1:WfXnOnwSqNtG62Y1CdjoMxh7r7u9QXGCkA1u0na2jgo=
|
||||
k8s.io/api v0.23.5/go.mod h1:Na4XuKng8PXJ2JsploYYrivXrINeTaycCGcYgF91Xm8=
|
||||
@@ -3145,9 +3077,7 @@ k8s.io/apiextensions-apiserver v0.18.6/go.mod h1:lv89S7fUysXjLZO7ke783xOwVTm6lKi
|
||||
k8s.io/apiextensions-apiserver v0.21.2/go.mod h1:+Axoz5/l3AYpGLlhJDfcVQzCerVYq3K3CvDMvw6X1RA=
|
||||
k8s.io/apiextensions-apiserver v0.21.3/go.mod h1:kl6dap3Gd45+21Jnh6utCx8Z2xxLm8LGDkprcd+KbsE=
|
||||
k8s.io/apiextensions-apiserver v0.22.1/go.mod h1:HeGmorjtRmRLE+Q8dJu6AYRoZccvCMsghwS8XTUYb2c=
|
||||
k8s.io/apiextensions-apiserver v0.22.2/go.mod h1:2E0Ve/isxNl7tWLSUDgi6+cmwHi5fQRdwGVCxbC+KFA=
|
||||
k8s.io/apiextensions-apiserver v0.22.4/go.mod h1:kH9lxD8dbJ+k0ZizGET55lFgdGjO8t45fgZnCVdZEpw=
|
||||
k8s.io/apiextensions-apiserver v0.22.6/go.mod h1:wNsLwy8mfIkGThiv4Qq/Hy4qRazViKXqmH5pfYiRKyY=
|
||||
k8s.io/apiextensions-apiserver v0.23.0/go.mod h1:xIFAEEDlAZgpVBl/1VSjGDmLoXAWRG40+GsWhKhAxY4=
|
||||
k8s.io/apiextensions-apiserver v0.23.5/go.mod h1:ntcPWNXS8ZPKN+zTXuzYMeg731CP0heCTl6gYBxLcuQ=
|
||||
k8s.io/apiextensions-apiserver v0.23.6 h1:v58cQ6Z0/GK1IXYr+oW0fnYl52o9LTY0WgoWvI8uv5Q=
|
||||
@@ -3164,6 +3094,7 @@ k8s.io/apimachinery v0.17.2/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZ
|
||||
k8s.io/apimachinery v0.17.5/go.mod h1:ioIo1G/a+uONV7Tv+ZmCbMG1/a3kVw5YcDdncd8ugQ0=
|
||||
k8s.io/apimachinery v0.18.0-beta.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apimachinery v0.18.0/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apimachinery v0.18.1/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apimachinery v0.18.2/go.mod h1:9SnR/e11v5IbyPCGbvJViimtJ0SwHG4nfZFjU77ftcA=
|
||||
k8s.io/apimachinery v0.18.3/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
|
||||
k8s.io/apimachinery v0.18.6/go.mod h1:OaXp26zu/5J7p0f92ASynJa1pZo06YlV9fG7BoWbCko=
|
||||
@@ -3176,9 +3107,7 @@ k8s.io/apimachinery v0.21.1/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswP
|
||||
k8s.io/apimachinery v0.21.2/go.mod h1:CdTY8fU/BlvAbJ2z/8kBwimGki5Zp8/fbVuLY8gJumM=
|
||||
k8s.io/apimachinery v0.21.3/go.mod h1:H/IM+5vH9kZRNJ4l3x/fXP/5bOPJaVP/guptnZPeCFI=
|
||||
k8s.io/apimachinery v0.22.1/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||
k8s.io/apimachinery v0.22.2/go.mod h1:O3oNtNadZdeOMxHFVxOreoznohCpy0z6mocxbZr7oJ0=
|
||||
k8s.io/apimachinery v0.22.4/go.mod h1:yU6oA6Gnax9RrxGzVvPFFJ+mpnW6PBSqp0sx0I0HHW0=
|
||||
k8s.io/apimachinery v0.22.6/go.mod h1:ZvVLP5iLhwVFg2Yx9Gh5W0um0DUauExbRhe+2Z8I1EU=
|
||||
k8s.io/apimachinery v0.23.0/go.mod h1:fFCTTBKvKcwTPFzjlcxp91uPFZr+JA0FubU4fLzzFYc=
|
||||
k8s.io/apimachinery v0.23.1/go.mod h1:SADt2Kl8/sttJ62RRsi9MIV4o8f5S3coArm0Iu3fBno=
|
||||
k8s.io/apimachinery v0.23.5/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||
@@ -3198,10 +3127,7 @@ k8s.io/apiserver v0.20.6/go.mod h1:QIJXNt6i6JB+0YQRNcS0hdRHJlMhflFmsBDeSgT1r8Q=
|
||||
k8s.io/apiserver v0.21.2/go.mod h1:lN4yBoGyiNT7SC1dmNk0ue6a5Wi6O3SWOIw91TsucQw=
|
||||
k8s.io/apiserver v0.21.3/go.mod h1:eDPWlZG6/cCCMj/JBcEpDoK+I+6i3r9GsChYBHSbAzU=
|
||||
k8s.io/apiserver v0.22.1/go.mod h1:2mcM6dzSt+XndzVQJX21Gx0/Klo7Aen7i0Ai6tIa400=
|
||||
k8s.io/apiserver v0.22.2/go.mod h1:vrpMmbyjWrgdyOvZTSpsusQq5iigKNWv9o9KlDAbBHI=
|
||||
k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E=
|
||||
k8s.io/apiserver v0.22.4/go.mod h1:38WmcUZiiy41A7Aty8/VorWRa8vDGqoUzDf2XYlku0E=
|
||||
k8s.io/apiserver v0.22.6/go.mod h1:OlL1rGa2kKWGj2JEXnwBcul/BwC9Twe95gm4ohtiIIs=
|
||||
k8s.io/apiserver v0.23.0/go.mod h1:Cec35u/9zAepDPPFyT+UMrgqOCjgJ5qtfVJDxjZYmt4=
|
||||
k8s.io/apiserver v0.23.1/go.mod h1:Bqt0gWbeM2NefS8CjWswwd2VNAKN6lUKR85Ft4gippY=
|
||||
k8s.io/apiserver v0.23.5/go.mod h1:7wvMtGJ42VRxzgVI7jkbKvMbuCbVbgsWFT7RyXiRNTw=
|
||||
@@ -3209,7 +3135,6 @@ k8s.io/apiserver v0.23.6 h1:p94LiXcsSnpSDIl4cv98liBuFKcaygSCNopFNfMg/Ac=
|
||||
k8s.io/apiserver v0.23.6/go.mod h1:5PU32F82tfErXPmf7FXhd/UcuLfh97tGepjKUgJ2atg=
|
||||
k8s.io/cli-runtime v0.0.0-20191214191754-e6dc6d5c8724/go.mod h1:wzlq80lvjgHW9if6MlE4OIGC86MDKsy5jtl9nxz/IYY=
|
||||
k8s.io/cli-runtime v0.17.2/go.mod h1:aa8t9ziyQdbkuizkNLAw3qe3srSyWh9zlSB7zTqRNPI=
|
||||
k8s.io/cli-runtime v0.22.1/go.mod h1:YqwGrlXeEk15Yn3em2xzr435UGwbrCw5x+COQoTYfoo=
|
||||
k8s.io/cli-runtime v0.22.4/go.mod h1:x35r0ERHXr/MrbR1C6MPJxQ3xKG6+hXi9m2xLzlMPZA=
|
||||
k8s.io/cli-runtime v0.23.6 h1:zvsGa4An+udUnznKSfD1Q17sETWHNOaMqYKHwHCvg+4=
|
||||
k8s.io/cli-runtime v0.23.6/go.mod h1:0Z3VR/HRIFKiLzKIAkm1mPtcH98GT/fXu2IU0E4vFmw=
|
||||
@@ -3223,6 +3148,7 @@ k8s.io/client-go v0.17.2/go.mod h1:QAzRgsa0C2xl4/eVpeVAZMvikCn8Nm81yqVx3Kk9XYI=
|
||||
k8s.io/client-go v0.17.5/go.mod h1:S8uZpBpjJJdEH/fEyxcqg7Rn0P5jH+ilkgBHjriSmNo=
|
||||
k8s.io/client-go v0.18.0-beta.2/go.mod h1:UvuVxHjKWIcgy0iMvF+bwNDW7l0mskTNOaOW1Qv5BMA=
|
||||
k8s.io/client-go v0.18.0/go.mod h1:uQSYDYs4WhVZ9i6AIoEZuwUggLVEF64HOD37boKAtF8=
|
||||
k8s.io/client-go v0.18.1/go.mod h1:iCikYRiXOj/yRRFE/aWqrpPtDt4P2JVWhtHkmESTcfY=
|
||||
k8s.io/client-go v0.18.2/go.mod h1:Xcm5wVGXX9HAA2JJ2sSBUn3tCJ+4SVlCbl2MNNv+CIU=
|
||||
k8s.io/client-go v0.18.3/go.mod h1:4a/dpQEvzAhT1BbuWW09qvIaGw6Gbu1gZYiQZIi1DMw=
|
||||
k8s.io/client-go v0.18.6/go.mod h1:/fwtGLjYMS1MaM5oi+eXhKwG+1UHidUEXRh6cNsdO0Q=
|
||||
@@ -3235,9 +3161,7 @@ k8s.io/client-go v0.21.1/go.mod h1:/kEw4RgW+3xnBGzvp9IWxKSNA+lXn3A7AuH3gdOAzLs=
|
||||
k8s.io/client-go v0.21.2/go.mod h1:HdJ9iknWpbl3vMGtib6T2PyI/VYxiZfq936WNVHBRrA=
|
||||
k8s.io/client-go v0.21.3/go.mod h1:+VPhCgTsaFmGILxR/7E1N0S+ryO010QBeNCv5JwRGYU=
|
||||
k8s.io/client-go v0.22.1/go.mod h1:BquC5A4UOo4qVDUtoc04/+Nxp1MeHcVc1HJm1KmG8kk=
|
||||
k8s.io/client-go v0.22.2/go.mod h1:sAlhrkVDf50ZHx6z4K0S40wISNTarf1r800F+RlCF6U=
|
||||
k8s.io/client-go v0.22.4/go.mod h1:Yzw4e5e7h1LNHA4uqnMVrpEpUs1hJOiuBsJKIlRCHDA=
|
||||
k8s.io/client-go v0.22.6/go.mod h1:TffU4AV2idZGeP+g3kdFZP+oHVHWPL1JYFySOALriw0=
|
||||
k8s.io/client-go v0.23.0/go.mod h1:hrDnpnK1mSr65lHHcUuIZIXDgEbzc7/683c6hyG4jTA=
|
||||
k8s.io/client-go v0.23.1/go.mod h1:6QSI8fEuqD4zgFK0xbdwfB/PthBsIxCJMa3s17WlcO0=
|
||||
k8s.io/client-go v0.23.5/go.mod h1:flkeinTO1CirYgzMPRWxUCnV0G4Fbu2vLhYCObnt/r4=
|
||||
@@ -3253,13 +3177,10 @@ k8s.io/code-generator v0.18.2/go.mod h1:+UHX5rSbxmR8kzS+FAv7um6dtYrZokQvjHpDSYRV
|
||||
k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c=
|
||||
k8s.io/code-generator v0.20.0/go.mod h1:UsqdF+VX4PU2g46NC2JRs4gc+IfrctnwHb76RNbWHJg=
|
||||
k8s.io/code-generator v0.20.10/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU=
|
||||
k8s.io/code-generator v0.20.10/go.mod h1:i6FmG+QxaLxvJsezvZp0q/gAEzzOz3U53KFibghWToU=
|
||||
k8s.io/code-generator v0.21.2/go.mod h1:8mXJDCB7HcRo1xiEQstcguZkbxZaqeUOrO9SsicWs3U=
|
||||
k8s.io/code-generator v0.21.3/go.mod h1:K3y0Bv9Cz2cOW2vXUrNZlFbflhuPvuadW6JdnN6gGKo=
|
||||
k8s.io/code-generator v0.22.1/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
|
||||
k8s.io/code-generator v0.22.2/go.mod h1:eV77Y09IopzeXOJzndrDyCI88UBok2h6WxAlBwpxa+o=
|
||||
k8s.io/code-generator v0.22.4/go.mod h1:qjYl54pQ/emhkT0UxbufbREYJMWsHNNV/jSVwhYZQGw=
|
||||
k8s.io/code-generator v0.22.6/go.mod h1:iOZwYADSgFPNGWfqHFfg1V0TNJnl1t0WyZluQp4baqU=
|
||||
k8s.io/code-generator v0.23.0/go.mod h1:vQvOhDXhuzqiVfM/YHp+dmg10WDZCchJVObc9MvowsE=
|
||||
k8s.io/code-generator v0.23.1/go.mod h1:V7yn6VNTCWW8GqodYCESVo95fuiEg713S8B7WacWZDA=
|
||||
k8s.io/code-generator v0.23.5/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||
@@ -3280,15 +3201,12 @@ k8s.io/component-base v0.20.10/go.mod h1:ZKOEin1xu68aJzxgzl5DZSp5J1IrjAOPlPN90/t
|
||||
k8s.io/component-base v0.21.2/go.mod h1:9lvmIThzdlrJj5Hp8Z/TOgIkdfsNARQ1pT+3PByuiuc=
|
||||
k8s.io/component-base v0.21.3/go.mod h1:kkuhtfEHeZM6LkX0saqSK8PbdO7A0HigUngmhhrwfGQ=
|
||||
k8s.io/component-base v0.22.1/go.mod h1:0D+Bl8rrnsPN9v0dyYvkqFfBeAd4u7n77ze+p8CMiPo=
|
||||
k8s.io/component-base v0.22.2/go.mod h1:5Br2QhI9OTe79p+TzPe9JKNQYvEKbq9rTJDWllunGug=
|
||||
k8s.io/component-base v0.22.4/go.mod h1:MrSaQy4a3tFVViff8TZL6JHYSewNCLshZCwHYM58v5A=
|
||||
k8s.io/component-base v0.22.6/go.mod h1:ngHLefY4J5fq2fApNdbWyj4yh0lvw36do4aAjNN8rc8=
|
||||
k8s.io/component-base v0.23.0/go.mod h1:DHH5uiFvLC1edCpvcTDV++NKULdYYU6pR9Tt3HIKMKI=
|
||||
k8s.io/component-base v0.23.1/go.mod h1:6llmap8QtJIXGDd4uIWJhAq0Op8AtQo6bDW2RrNMTeo=
|
||||
k8s.io/component-base v0.23.5/go.mod h1:c5Nq44KZyt1aLl0IpHX82fhsn84Sb0jjzwjpcA42bY0=
|
||||
k8s.io/component-base v0.23.6 h1:8dhVZ4VrRcNdV2EGjl8tj8YOHwX6ysgCGMJ2Oyy0NW8=
|
||||
k8s.io/component-base v0.23.6/go.mod h1:FGMPeMrjYu0UZBSAFcfloVDplj9IvU+uRMTOdE23Fj0=
|
||||
k8s.io/component-helpers v0.22.1/go.mod h1:QvBcDbX+qU5I2tMZABBF5fRwAlQwiv771IGBHK9WYh4=
|
||||
k8s.io/component-helpers v0.22.4/go.mod h1:A50qTyczDFbhZDifIfS2zFrHuPk9UNOWPpvNZ+3RSIs=
|
||||
k8s.io/component-helpers v0.23.6/go.mod h1:kgvl6wvnYg9oebklLPpbW8UhvAZ9Qds26/RANEbny/8=
|
||||
k8s.io/cri-api v0.17.3/go.mod h1:X1sbHmuXhwaHs9xxYffLqJogVsnI+f6cPRcgPel7ywM=
|
||||
@@ -3302,8 +3220,6 @@ k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8
|
||||
k8s.io/gengo v0.0.0-20201113003025-83324d819ded/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/gengo v0.0.0-20201214224949-b6c5ce23f027/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/gengo v0.0.0-20210813121822-485abfe95c7c/go.mod h1:FiNAH4ZV3gBg2Kwh89tzAEV2be7d5xI0vBa/VySYy3E=
|
||||
k8s.io/helm v2.17.0+incompatible h1:Bpn6o1wKLYqKM3+Osh8e+1/K2g/GsQJ4F4yNF2+deao=
|
||||
k8s.io/helm v2.17.0+incompatible/go.mod h1:LZzlS4LQBHfciFOurYBFkCMTaZ0D1l+p0teMg7TSULI=
|
||||
k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
|
||||
@@ -3334,17 +3250,14 @@ k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAG
|
||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
|
||||
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65 h1:E3J9oCLlaobFUqsjG9DfKbP2BmgwBL2p7pn0A3dG9W4=
|
||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||
k8s.io/kubectl v0.0.0-20191219154910-1528d4eea6dd/go.mod h1:9ehGcuUGjXVZh0qbYSB0vvofQw2JQe6c6cO0k4wu/Oo=
|
||||
k8s.io/kubectl v0.22.1/go.mod h1:mjAOgEbMNMtZWxnfM6jd+nPjPsaoLqO5xanc78WcSbw=
|
||||
k8s.io/kubectl v0.22.4/go.mod h1:ok2qRT6y2Gy4+y+mniJVyUMKeBHP4OWS9Rdtf/QTM5I=
|
||||
k8s.io/kubectl v0.23.6 h1:ajzrqj88GqlH/gpscMCts+mKNeSJprpkWJEHO8CR2Ss=
|
||||
k8s.io/kubectl v0.23.6/go.mod h1:mMtJhc2QtQiSfvIQoMEUIjGHtZuP4uxMy/ees6j6zx8=
|
||||
k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
|
||||
k8s.io/metrics v0.0.0-20191214191643-6b1944c9f765/go.mod h1:5V7rewilItwK0cz4nomU0b3XCcees2Ka5EBYWS1HBeM=
|
||||
k8s.io/metrics v0.22.1/go.mod h1:i/ZNap89UkV1gLa26dn7fhKAdheJaKy+moOqJbiif7E=
|
||||
k8s.io/metrics v0.22.4/go.mod h1:6F/iwuYb1w2QDCoHkeMFLf4pwHBcYKLm4mPtVHKYrIw=
|
||||
k8s.io/metrics v0.23.6 h1:GH9tTTq7l6DNhzFsLW3Q3xG1LWEk/VT853T6r1mo3uI=
|
||||
k8s.io/metrics v0.23.6/go.mod h1:Fm9VzVMZ7KVEEeLStF2y3XogfcDwpGyI15o1xB6PbYk=
|
||||
@@ -3362,7 +3275,6 @@ k8s.io/utils v0.0.0-20210707171843-4b05e18ac7d9/go.mod h1:jPW/WVKK9YHAvNhRxK0md/
|
||||
k8s.io/utils v0.0.0-20210722164352-7f3ee0f31471/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
k8s.io/utils v0.0.0-20211208161948-7d6a63dca704/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||
@@ -3406,7 +3318,6 @@ sigs.k8s.io/controller-runtime v0.6.0/go.mod h1:CpYf5pdNY/B352A1TFLAS2JVSlnGQ5O2
|
||||
sigs.k8s.io/controller-runtime v0.6.2/go.mod h1:vhcq/rlnENJ09SIRp3EveTaZ0yqH526hjf9iJdbUJ/E=
|
||||
sigs.k8s.io/controller-runtime v0.9.2/go.mod h1:TxzMCHyEUpaeuOiZx/bIdc2T81vfs/aKdvJt9wuu0zk=
|
||||
sigs.k8s.io/controller-runtime v0.9.5/go.mod h1:q6PpkM5vqQubEKUKOM6qr06oXGzOBcCby1DA9FbyZeA=
|
||||
sigs.k8s.io/controller-runtime v0.10.3/go.mod h1:CQp8eyUQZ/Q7PJvnIrB6/hgfTC1kBkGylwsLgOQi1WY=
|
||||
sigs.k8s.io/controller-runtime v0.11.0/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
||||
sigs.k8s.io/controller-runtime v0.11.1/go.mod h1:KKwLiTooNGu+JmLZGn9Sl3Gjmfj66eMbCQznLP5zcqA=
|
||||
sigs.k8s.io/controller-runtime v0.11.2 h1:H5GTxQl0Mc9UjRJhORusqfJCIjBO8UtUxGggCwL1rLA=
|
||||
@@ -3447,11 +3358,7 @@ sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.0/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
|
||||
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
|
||||
sigs.k8s.io/testing_frameworks v0.1.2/go.mod h1:ToQrwSC3s8Xf/lADdZp3Mktcql9CG0UAmdJG9th5i0w=
|
||||
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
|
||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
||||
|
||||
@@ -2198,17 +2198,6 @@ spec:
|
||||
a context in annotation. - should mark "finish" phase in
|
||||
status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -2236,13 +2225,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta
|
||||
data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -2289,13 +2271,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the
|
||||
meta data of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the
|
||||
workflow step.
|
||||
@@ -2317,8 +2292,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -2326,8 +2299,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4002,13 +3973,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -4053,13 +4017,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -4081,8 +4038,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -4090,8 +4045,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -1010,17 +1010,6 @@ spec:
|
||||
order, and each step: - will have a context in annotation. - should
|
||||
mark "finish" phase in status.conditions.'
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow
|
||||
execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -1047,13 +1036,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of
|
||||
a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -1098,13 +1080,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data
|
||||
of a workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow
|
||||
step.
|
||||
@@ -1126,8 +1101,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -1135,8 +1108,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -57,13 +57,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a workflow
|
||||
step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -107,13 +100,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a
|
||||
workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -133,8 +119,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -142,8 +126,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -159,16 +141,6 @@ spec:
|
||||
openAPIV3Schema:
|
||||
description: Workflow defines workflow steps and other attributes
|
||||
properties:
|
||||
mode:
|
||||
description: WorkflowExecuteMode defines the mode of workflow execution
|
||||
properties:
|
||||
steps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
subSteps:
|
||||
description: WorkflowMode describes the mode of workflow
|
||||
type: string
|
||||
type: object
|
||||
ref:
|
||||
type: string
|
||||
steps:
|
||||
@@ -194,13 +166,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a workflow
|
||||
step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -244,13 +209,6 @@ spec:
|
||||
- parameterKey
|
||||
type: object
|
||||
type: array
|
||||
meta:
|
||||
description: WorkflowStepMeta contains the meta data of a
|
||||
workflow step
|
||||
properties:
|
||||
alias:
|
||||
type: string
|
||||
type: object
|
||||
name:
|
||||
description: Name is the unique name of the workflow step.
|
||||
type: string
|
||||
@@ -270,8 +228,6 @@ spec:
|
||||
properties:
|
||||
type: object
|
||||
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -279,8 +235,6 @@ spec:
|
||||
- type
|
||||
type: object
|
||||
type: array
|
||||
timeout:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
|
||||
@@ -60,10 +60,7 @@ KUSTOMIZE_VERSION ?= 4.5.4
|
||||
KUSTOMIZE = $(shell pwd)/bin/kustomize
|
||||
.PHONY: kustomize
|
||||
kustomize:
|
||||
ifneq (, $(shell kustomize version | grep $(KUSTOMIZE_VERSION)))
|
||||
KUSTOMIZE=$(shell which kustomize)
|
||||
else ifneq (, $(shell $(KUSTOMIZE) version | grep $(KUSTOMIZE_VERSION)))
|
||||
else
|
||||
ifeq (, $(shell $(KUSTOMIZE) version | grep $(KUSTOMIZE_VERSION)))
|
||||
@{ \
|
||||
set -eo pipefail ;\
|
||||
echo "installing kustomize-v$(KUSTOMIZE_VERSION) into $(shell pwd)/bin" ;\
|
||||
|
||||
@@ -36,10 +36,10 @@ import (
|
||||
cueyaml "cuelang.org/go/encoding/yaml"
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/google/go-github/v32/github"
|
||||
prismclusterv1alpha1 "github.com/kubevela/prism/pkg/apis/cluster/v1alpha1"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/xanzy/go-gitlab"
|
||||
"golang.org/x/oauth2"
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
@@ -50,7 +50,6 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
k8syaml "k8s.io/apimachinery/pkg/runtime/serializer/yaml"
|
||||
types2 "k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
"k8s.io/client-go/discovery"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/util/retry"
|
||||
@@ -71,10 +70,8 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/velaql"
|
||||
version2 "github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
@@ -97,9 +94,6 @@ const (
|
||||
// DefSchemaName is the addon definition schemas dir name
|
||||
DefSchemaName string = "schemas"
|
||||
|
||||
// ViewDirName is the addon views dir name
|
||||
ViewDirName string = "views"
|
||||
|
||||
// AddonParameterDataKey is the key of parameter in addon args secrets
|
||||
AddonParameterDataKey string = "addonParameterDataKey"
|
||||
|
||||
@@ -197,7 +191,7 @@ type Pattern struct {
|
||||
}
|
||||
|
||||
// Patterns is the file pattern that the addon should be in
|
||||
var Patterns = []Pattern{{Value: ReadmeFileName}, {Value: MetadataFileName}, {Value: TemplateFileName}, {Value: ParameterFileName}, {IsDir: true, Value: ResourcesDirName}, {IsDir: true, Value: DefinitionsDirName}, {IsDir: true, Value: DefSchemaName}, {IsDir: true, Value: ViewDirName}}
|
||||
var Patterns = []Pattern{{Value: ReadmeFileName}, {Value: MetadataFileName}, {Value: TemplateFileName}, {Value: ParameterFileName}, {IsDir: true, Value: ResourcesDirName}, {IsDir: true, Value: DefinitionsDirName}, {IsDir: true, Value: DefSchemaName}}
|
||||
|
||||
// GetPatternFromItem will check if the file path has a valid pattern, return empty string if it's invalid.
|
||||
// AsyncReader is needed to calculate relative path
|
||||
@@ -312,7 +306,6 @@ func GetInstallPackageFromReader(r AsyncReader, meta *SourceMeta, uiData *UIData
|
||||
TemplateFileName: readTemplate,
|
||||
ResourcesDirName: readResFile,
|
||||
DefSchemaName: readDefSchemaFile,
|
||||
ViewDirName: readViewFile,
|
||||
}
|
||||
ptItems := ClassifyItemByPattern(meta, r)
|
||||
|
||||
@@ -415,24 +408,6 @@ func readDefFile(a *UIData, reader AsyncReader, readPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// readViewFile read single view file
|
||||
func readViewFile(a *InstallPackage, reader AsyncReader, readPath string) error {
|
||||
b, err := reader.ReadFile(readPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
filename := path.Base(readPath)
|
||||
switch filepath.Ext(filename) {
|
||||
case ".cue":
|
||||
a.CUEViews = append(a.CUEViews, ElementFile{Data: b, Name: filepath.Base(readPath)})
|
||||
case ".yaml", ".yml":
|
||||
a.YAMLViews = append(a.YAMLViews, ElementFile{Data: b, Name: filepath.Base(readPath)})
|
||||
default:
|
||||
// skip other file formats
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func readMetadata(a *UIData, reader AsyncReader, readPath string) error {
|
||||
b, err := reader.ReadFile(readPath)
|
||||
if err != nil {
|
||||
@@ -612,9 +587,6 @@ func renderResources(addon *InstallPackage, args map[string]interface{}) ([]comm
|
||||
|
||||
for _, tmpl := range addon.CUETemplates {
|
||||
comp, err := renderCUETemplate(tmpl, addon.Parameters, args, addon.Meta)
|
||||
if err != nil && strings.Contains(err.Error(), "var(path=output) not exist") {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, NewAddonError(fmt.Sprintf("fail to render cue template %s", err.Error()))
|
||||
}
|
||||
@@ -639,7 +611,7 @@ func formatAppFramework(addon *InstallPackage) *v1beta1.Application {
|
||||
if app.Spec.Components == nil {
|
||||
app.Spec.Components = []common2.ApplicationComponent{}
|
||||
}
|
||||
app.Name = addonutil.Addon2AppName(addon.Name)
|
||||
app.Name = Convert2AppName(addon.Name)
|
||||
// force override the namespace defined vela with DefaultVelaNS,this value can be modified by Env
|
||||
app.SetNamespace(types.DefaultKubeVelaNS)
|
||||
if app.Labels == nil {
|
||||
@@ -655,26 +627,24 @@ func checkDeployClusters(ctx context.Context, k8sClient client.Client, args map[
|
||||
if len(deployClusters) == 0 || k8sClient == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
clusters, err := prismclusterv1alpha1.NewClusterClient(k8sClient).List(ctx)
|
||||
vcs, err := multicluster.ListVirtualClusters(ctx, k8sClient)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fail to get registered cluster")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clusterNames := sets.String{}
|
||||
if len(clusters.Items) != 0 {
|
||||
for _, cluster := range clusters.Items {
|
||||
clusterNames.Insert(cluster.Name)
|
||||
}
|
||||
}
|
||||
|
||||
var res []string
|
||||
for _, c := range deployClusters {
|
||||
c = strings.TrimSpace(c)
|
||||
if c == "" {
|
||||
continue
|
||||
}
|
||||
if !clusterNames.Has(c) {
|
||||
var found bool
|
||||
for _, vc := range vcs {
|
||||
if c == vc.Name {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return nil, errors.Errorf("cluster %s not exist", c)
|
||||
}
|
||||
res = append(res, c)
|
||||
@@ -742,10 +712,7 @@ func RenderApp(ctx context.Context, addon *InstallPackage, k8sClient client.Clie
|
||||
if app.Spec.Policies == nil {
|
||||
app.Spec.Policies = []v1beta1.AppPolicy{}
|
||||
}
|
||||
body, err := json.Marshal(map[string][]string{types.ClustersArg: deployClusters})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
body, _ := json.Marshal(map[string][]string{types.ClustersArg: deployClusters})
|
||||
app.Spec.Policies = append(app.Spec.Policies, v1beta1.AppPolicy{
|
||||
Name: "specified-addon-clusters",
|
||||
Type: v1alpha1.TopologyPolicyType,
|
||||
@@ -799,7 +766,7 @@ func RenderApp(ctx context.Context, addon *InstallPackage, k8sClient client.Clie
|
||||
func RenderDefinitions(addon *InstallPackage, config *rest.Config) ([]*unstructured.Unstructured, error) {
|
||||
defObjs := make([]*unstructured.Unstructured, 0)
|
||||
|
||||
// No matter runtime mode or control mode, definition only needs to control plane k8s.
|
||||
// No matter runtime mode or control mode , definition only needs to control plane k8s.
|
||||
for _, def := range addon.Definitions {
|
||||
obj, err := renderObject(def)
|
||||
if err != nil {
|
||||
@@ -839,26 +806,6 @@ func RenderDefinitionSchema(addon *InstallPackage) ([]*unstructured.Unstructured
|
||||
return schemaConfigmaps, nil
|
||||
}
|
||||
|
||||
// RenderViews will render views in addons.
|
||||
func RenderViews(addon *InstallPackage) ([]*unstructured.Unstructured, error) {
|
||||
views := make([]*unstructured.Unstructured, 0)
|
||||
for _, view := range addon.YAMLViews {
|
||||
obj, err := renderObject(view)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
views = append(views, obj)
|
||||
}
|
||||
for _, view := range addon.CUEViews {
|
||||
obj, err := renderCUEView(view)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
views = append(views, obj)
|
||||
}
|
||||
return views, nil
|
||||
}
|
||||
|
||||
func allocateDomainForAddon(ctx context.Context, k8sClient client.Client) ([]ObservabilityEnvironment, error) {
|
||||
secrets, err := multicluster.ListExistingClusterSecrets(ctx, k8sClient)
|
||||
if err != nil {
|
||||
@@ -1003,20 +950,6 @@ func renderSchemaConfigmap(elem ElementFile) (*unstructured.Unstructured, error)
|
||||
return util.Object2Unstructured(cm)
|
||||
}
|
||||
|
||||
func renderCUEView(elem ElementFile) (*unstructured.Unstructured, error) {
|
||||
name, err := utils.GetFilenameFromLocalOrRemote(elem.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cm, err := velaql.ParseViewIntoConfigMap(elem.Data, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return util.Object2Unstructured(*cm)
|
||||
}
|
||||
|
||||
// renderCUETemplate will return a component from cue template
|
||||
func renderCUETemplate(elem ElementFile, parameters string, args map[string]interface{}, metadata Meta) (*common2.ApplicationComponent, error) {
|
||||
bt, err := json.Marshal(args)
|
||||
@@ -1067,6 +1000,14 @@ func renderCUETemplate(elem ElementFile, parameters string, args map[string]inte
|
||||
return &comp, err
|
||||
}
|
||||
|
||||
const addonAppPrefix = "addon-"
|
||||
const addonSecPrefix = "addon-secret-"
|
||||
|
||||
// Convert2AppName -
|
||||
func Convert2AppName(name string) string {
|
||||
return addonAppPrefix + name
|
||||
}
|
||||
|
||||
// RenderArgsSecret render addon enable argument to secret
|
||||
func RenderArgsSecret(addon *InstallPackage, args map[string]interface{}) *unstructured.Unstructured {
|
||||
argsByte, err := json.Marshal(args)
|
||||
@@ -1076,7 +1017,7 @@ func RenderArgsSecret(addon *InstallPackage, args map[string]interface{}) *unstr
|
||||
sec := v1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Secret"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: addonutil.Addon2SecName(addon.Name),
|
||||
Name: Convert2SecName(addon.Name),
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
Data: map[string][]byte{
|
||||
@@ -1110,6 +1051,11 @@ func FetchArgsFromSecret(sec *v1.Secret) (map[string]interface{}, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// Convert2SecName generate addon argument secret name
|
||||
func Convert2SecName(name string) string {
|
||||
return addonSecPrefix + name
|
||||
}
|
||||
|
||||
// Installer helps addon enable, dependency-check, dispatch resources
|
||||
type Installer struct {
|
||||
ctx context.Context
|
||||
@@ -1150,8 +1096,7 @@ func (h *Installer) enableAddon(addon *InstallPackage) error {
|
||||
if !h.skipVersionValidate {
|
||||
err = checkAddonVersionMeetRequired(h.ctx, addon.SystemRequirements, h.cli, h.dc)
|
||||
if err != nil {
|
||||
version := h.getAddonVersionMeetSystemRequirement(addon.Name)
|
||||
return VersionUnMatchError{addonName: addon.Name, err: err, userSelectedAddonVersion: addon.Version, availableVersion: version}
|
||||
return VersionUnMatchError{addonName: addon.Name, err: err}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1222,7 +1167,7 @@ func (h *Installer) installDependency(addon *InstallPackage) error {
|
||||
for _, dep := range addon.Dependencies {
|
||||
err := h.cli.Get(h.ctx, client.ObjectKey{
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Name: addonutil.Addon2AppName(dep.Name),
|
||||
Name: Convert2AppName(dep.Name),
|
||||
}, &app)
|
||||
if err == nil {
|
||||
continue
|
||||
@@ -1251,7 +1196,7 @@ func (h *Installer) checkDependency(addon *InstallPackage) ([]string, error) {
|
||||
for _, dep := range addon.Dependencies {
|
||||
err := h.cli.Get(h.ctx, client.ObjectKey{
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Name: addonutil.Addon2AppName(dep.Name),
|
||||
Name: Convert2AppName(dep.Name),
|
||||
}, &app)
|
||||
if err == nil {
|
||||
continue
|
||||
@@ -1308,11 +1253,6 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
return errors.Wrap(err, "render addon definitions' schema fail")
|
||||
}
|
||||
|
||||
views, err := RenderViews(addon)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "render addon views fail")
|
||||
}
|
||||
|
||||
if err := passDefInAppAnnotation(defs, app); err != nil {
|
||||
return errors.Wrapf(err, "cannot pass definition to addon app's annotation")
|
||||
}
|
||||
@@ -1337,14 +1277,6 @@ func (h *Installer) dispatchAddonResource(addon *InstallPackage) error {
|
||||
}
|
||||
}
|
||||
|
||||
for _, view := range views {
|
||||
addOwner(view, app)
|
||||
err = h.apply.Apply(h.ctx, view, apply.DisableUpdateAnnotation())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if h.args != nil && len(h.args) > 0 {
|
||||
sec := RenderArgsSecret(addon, h.args)
|
||||
addOwner(sec, app)
|
||||
@@ -1393,27 +1325,6 @@ func (h *Installer) continueOrRestartWorkflow() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// getAddonVersionMeetSystemRequirement return the addon's latest version which meet the system requirements
|
||||
func (h *Installer) getAddonVersionMeetSystemRequirement(addonName string) string {
|
||||
if h.r != nil && IsVersionRegistry(*h.r) {
|
||||
versionedRegistry := BuildVersionedRegistry(h.r.Name, h.r.Helm.URL, &common.HTTPOption{
|
||||
Username: h.r.Helm.Username,
|
||||
Password: h.r.Helm.Password,
|
||||
})
|
||||
versions, err := versionedRegistry.GetAddonAvailableVersion(addonName)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
for _, version := range versions {
|
||||
req := LoadSystemRequirements(version.Annotations)
|
||||
if checkAddonVersionMeetRequired(h.ctx, req, h.cli, h.dc) == nil {
|
||||
return version.Version
|
||||
}
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func addOwner(child *unstructured.Unstructured, app *v1beta1.Application) {
|
||||
child.SetOwnerReferences(append(child.GetOwnerReferences(),
|
||||
*metav1.NewControllerRef(app, v1beta1.ApplicationKindVersionKind)))
|
||||
@@ -1427,7 +1338,7 @@ func determineAddonAppName(ctx context.Context, cli client.Client, addonName str
|
||||
return "", err
|
||||
}
|
||||
// if the app still not exist, use addon-{addonName}
|
||||
return addonutil.Addon2AppName(addonName), nil
|
||||
return Convert2AppName(addonName), nil
|
||||
}
|
||||
return app.Name, nil
|
||||
}
|
||||
@@ -1436,7 +1347,7 @@ func determineAddonAppName(ctx context.Context, cli client.Client, addonName str
|
||||
// if not find will try to get 1.1 legacy addon related app by using NamespacedName(vela-system, `addonName`)
|
||||
func FetchAddonRelatedApp(ctx context.Context, cli client.Client, addonName string) (*v1beta1.Application, error) {
|
||||
app := &v1beta1.Application{}
|
||||
if err := cli.Get(ctx, types2.NamespacedName{Namespace: types.DefaultKubeVelaNS, Name: addonutil.Addon2AppName(addonName)}, app); err != nil {
|
||||
if err := cli.Get(ctx, types2.NamespacedName{Namespace: types.DefaultKubeVelaNS, Name: Convert2AppName(addonName)}, app); err != nil {
|
||||
if !apierrors.IsNotFound(err) {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1575,8 +1486,32 @@ func fetchVelaCoreImageTag(ctx context.Context, k8sClient client.Client) (string
|
||||
|
||||
// PackageAddon package vela addon directory into a helm chart compatible archive and return its absolute path
|
||||
func PackageAddon(addonDictPath string) (string, error) {
|
||||
meta := &Meta{}
|
||||
metaData, err := ioutil.ReadFile(filepath.Clean(filepath.Join(addonDictPath, MetadataFileName)))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(metaData, meta)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
chartFile := &chart.Metadata{
|
||||
Name: meta.Name,
|
||||
Description: meta.Description,
|
||||
// define Vela addon's type to be library in order to prevent installation of a common chart. Please refer to https://helm.sh/docs/topics/library_charts/
|
||||
Type: "library",
|
||||
Version: meta.Version,
|
||||
AppVersion: meta.Version,
|
||||
APIVersion: chart.APIVersionV2,
|
||||
Icon: meta.Icon,
|
||||
Home: meta.URL,
|
||||
Keywords: meta.Tags,
|
||||
}
|
||||
|
||||
// save the Chart.yaml file in order to be compatible with helm chart
|
||||
err := MakeChartCompatible(addonDictPath, true)
|
||||
err = chartutil.SaveChartfile(filepath.Join(addonDictPath, chartutil.ChartfileName), chartFile)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -39,7 +39,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam/util"
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
)
|
||||
|
||||
@@ -253,7 +252,7 @@ var _ = Describe("Test addon util func", func() {
|
||||
secArgs := v1.Secret{
|
||||
TypeMeta: metav1.TypeMeta{APIVersion: "v1", Kind: "Secret"},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: addonutil.Addon2SecName("test-addon-old-args"),
|
||||
Name: Convert2SecName("test-addon-old-args"),
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
StringData: map[string]string{
|
||||
@@ -379,23 +378,6 @@ var _ = Describe("test enable addon in local dir", func() {
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("test enable addon which applies the views independently", func() {
|
||||
BeforeEach(func() {
|
||||
app := v1beta1.Application{ObjectMeta: metav1.ObjectMeta{Namespace: "vela-system", Name: "addon-test-view"}}
|
||||
Expect(k8sClient.Delete(ctx, &app)).Should(SatisfyAny(BeNil(), util.NotFoundMatcher{}))
|
||||
})
|
||||
|
||||
It("test enable addon which applies the views independently", func() {
|
||||
ctx := context.Background()
|
||||
err := EnableAddonByLocalDir(ctx, "test-view", "./testdata/test-view", k8sClient, dc, apply.NewAPIApplicator(k8sClient), cfg, map[string]interface{}{"example": "test"})
|
||||
Expect(err).Should(BeNil())
|
||||
app := v1beta1.Application{}
|
||||
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "addon-test-view"}, &app)).Should(BeNil())
|
||||
configMap := v1.ConfigMap{}
|
||||
Expect(k8sClient.Get(ctx, types2.NamespacedName{Namespace: "vela-system", Name: "pod-view"}, &configMap)).Should(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
const (
|
||||
appYaml = `apiVersion: core.oam.dev/v1beta1
|
||||
kind: Application
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
"encoding/xml"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@@ -50,7 +49,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
version2 "github.com/oam-dev/kubevela/version"
|
||||
)
|
||||
|
||||
@@ -114,29 +112,6 @@ var ossHandler http.HandlerFunc = func(rw http.ResponseWriter, req *http.Request
|
||||
}
|
||||
}
|
||||
|
||||
var helmHandler http.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) {
|
||||
switch {
|
||||
case strings.Contains(request.URL.Path, "index.yaml"):
|
||||
files, err := ioutil.ReadFile("./testdata/multiversion-helm-repo/index.yaml")
|
||||
if err != nil {
|
||||
_, _ = writer.Write([]byte(err.Error()))
|
||||
}
|
||||
writer.Write(files)
|
||||
case strings.Contains(request.URL.Path, "fluxcd-1.0.0.tgz"):
|
||||
files, err := ioutil.ReadFile("./testdata/multiversion-helm-repo/fluxcd-1.0.0.tgz")
|
||||
if err != nil {
|
||||
_, _ = writer.Write([]byte(err.Error()))
|
||||
}
|
||||
writer.Write(files)
|
||||
case strings.Contains(request.URL.Path, "fluxcd-2.0.0.tgz"):
|
||||
files, err := ioutil.ReadFile("./testdata/multiversion-helm-repo/fluxcd-2.0.0.tgz")
|
||||
if err != nil {
|
||||
_, _ = writer.Write([]byte(err.Error()))
|
||||
}
|
||||
writer.Write(files)
|
||||
}
|
||||
}
|
||||
|
||||
var ctx = context.Background()
|
||||
|
||||
func testReaderFunc(t *testing.T, reader AsyncReader) {
|
||||
@@ -315,30 +290,6 @@ func TestRenderDefinitions(t *testing.T) {
|
||||
assert.Nil(t, app.Spec.Workflow)
|
||||
}
|
||||
|
||||
func TestRenderViews(t *testing.T) {
|
||||
addonDeployToRuntime := viewAddon
|
||||
addonDeployToRuntime.Meta.DeployTo = &DeployTo{
|
||||
DisableControlPlane: false,
|
||||
RuntimeCluster: false,
|
||||
}
|
||||
views, err := RenderViews(&addonDeployToRuntime)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(views), 2)
|
||||
|
||||
view := views[0]
|
||||
assert.Equal(t, view.GetKind(), "ConfigMap")
|
||||
assert.Equal(t, view.GetAPIVersion(), "v1")
|
||||
assert.Equal(t, view.GetNamespace(), types.DefaultKubeVelaNS)
|
||||
assert.Equal(t, view.GetName(), "cloud-resource-view")
|
||||
|
||||
view = views[1]
|
||||
assert.Equal(t, view.GetKind(), "ConfigMap")
|
||||
assert.Equal(t, view.GetAPIVersion(), "v1")
|
||||
assert.Equal(t, view.GetNamespace(), types.DefaultKubeVelaNS)
|
||||
assert.Equal(t, view.GetName(), "pod-view")
|
||||
|
||||
}
|
||||
|
||||
func TestRenderK8sObjects(t *testing.T) {
|
||||
addonMultiYaml := multiYamlAddon
|
||||
addonMultiYaml.Meta.DeployTo = &DeployTo{
|
||||
@@ -442,7 +393,7 @@ func TestGetAddonStatus4Observability(t *testing.T) {
|
||||
|
||||
addonSecret := &corev1.Secret{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: addonutil.Addon2SecName(ObservabilityAddon),
|
||||
Name: Convert2SecName(ObservabilityAddon),
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
Data: map[string][]byte{},
|
||||
@@ -497,22 +448,6 @@ func TestGetAddonStatus4Observability(t *testing.T) {
|
||||
assert.Equal(t, addonStatus.AddonPhase, enabled)
|
||||
}
|
||||
|
||||
func TestGetAddonVersionMeetSystemRequirement(t *testing.T) {
|
||||
server := httptest.NewServer(helmHandler)
|
||||
defer server.Close()
|
||||
i := &Installer{
|
||||
r: &Registry{
|
||||
Helm: &HelmSource{
|
||||
URL: server.URL,
|
||||
},
|
||||
},
|
||||
}
|
||||
version := i.getAddonVersionMeetSystemRequirement("fluxcd-no-requirements")
|
||||
assert.Equal(t, version, "1.0.0")
|
||||
version = i.getAddonVersionMeetSystemRequirement("not-exist")
|
||||
assert.Equal(t, version, "")
|
||||
}
|
||||
|
||||
var baseAddon = InstallPackage{
|
||||
Meta: Meta{
|
||||
Name: "test-render-cue-definition-addon",
|
||||
@@ -542,24 +477,6 @@ var multiYamlAddon = InstallPackage{
|
||||
},
|
||||
}
|
||||
|
||||
var viewAddon = InstallPackage{
|
||||
Meta: Meta{
|
||||
Name: "test-render-view-addon",
|
||||
},
|
||||
YAMLViews: []ElementFile{
|
||||
{
|
||||
Data: testYAMLView,
|
||||
Name: "cloud-resource-view",
|
||||
},
|
||||
},
|
||||
CUEViews: []ElementFile{
|
||||
{
|
||||
Data: testCUEView,
|
||||
Name: "pod-view",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var testCueDef = `annotations: {
|
||||
type: "trait"
|
||||
annotations: {}
|
||||
@@ -638,125 +555,6 @@ spec:
|
||||
- containerPort: 80
|
||||
`
|
||||
|
||||
var testYAMLView = `
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata:
|
||||
name: "cloud-resource-view"
|
||||
namespace: "vela-system"
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
appName: string
|
||||
appNs: string
|
||||
}
|
||||
resources: ql.#ListResourcesInApp & {
|
||||
app: {
|
||||
name: parameter.appName
|
||||
namespace: parameter.appNs
|
||||
filter: {
|
||||
"apiVersion": "terraform.core.oam.dev/v1beta1"
|
||||
"kind": "Configuration"
|
||||
}
|
||||
withStatus: true
|
||||
}
|
||||
}
|
||||
status: {
|
||||
if resources.err == _|_ {
|
||||
"cloud-resources": [ for i, resource in resources.list {
|
||||
resource.object
|
||||
}]
|
||||
}
|
||||
if resources.err != _|_ {
|
||||
error: resources.err
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
`
|
||||
var testCUEView = `
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
name: string
|
||||
namespace: string
|
||||
cluster: *"" | string
|
||||
}
|
||||
pod: ql.#Read & {
|
||||
value: {
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
eventList: ql.#SearchEvents & {
|
||||
value: {
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: pod.value.metadata
|
||||
}
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
podMetrics: ql.#Read & {
|
||||
cluster: parameter.cluster
|
||||
value: {
|
||||
apiVersion: "metrics.k8s.io/v1beta1"
|
||||
kind: "PodMetrics"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
status: {
|
||||
if pod.err == _|_ {
|
||||
containers: [ for container in pod.value.spec.containers {
|
||||
name: container.name
|
||||
image: container.image
|
||||
resources: {
|
||||
if container.resources.limits != _|_ {
|
||||
limits: container.resources.limits
|
||||
}
|
||||
if container.resources.requests != _|_ {
|
||||
requests: container.resources.requests
|
||||
}
|
||||
if podMetrics.err == _|_ {
|
||||
usage: {for containerUsage in podMetrics.value.containers {
|
||||
if containerUsage.name == container.name {
|
||||
cpu: containerUsage.usage.cpu
|
||||
memory: containerUsage.usage.memory
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
if pod.value.status.containerStatuses != _|_ {
|
||||
status: {for containerStatus in pod.value.status.containerStatuses if containerStatus.name == container.name {
|
||||
state: containerStatus.state
|
||||
restartCount: containerStatus.restartCount
|
||||
}}
|
||||
}
|
||||
}]
|
||||
if eventList.err == _|_ {
|
||||
events: eventList.list
|
||||
}
|
||||
}
|
||||
if pod.err != _|_ {
|
||||
error: pod.err
|
||||
}
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
func TestRenderApp4Observability(t *testing.T) {
|
||||
k8sClient := fake.NewClientBuilder().Build()
|
||||
testcases := []struct {
|
||||
@@ -843,13 +641,6 @@ func TestGetPatternFromItem(t *testing.T) {
|
||||
gitItemName := "parameter.cue"
|
||||
gitItemType := FileType
|
||||
gitItemPath := "addons/terraform/resources/parameter.cue"
|
||||
|
||||
viewOSSR := localReader{
|
||||
dir: "./testdata/test-view",
|
||||
name: "test-view",
|
||||
}
|
||||
viewPath := filepath.Join("./testdata/test-view/views/pod-view.cue", "pod-view.cue")
|
||||
|
||||
testCases := []struct {
|
||||
caseName string
|
||||
item Item
|
||||
@@ -875,17 +666,6 @@ func TestGetPatternFromItem(t *testing.T) {
|
||||
meetPattern: "resources/parameter.cue",
|
||||
r: gitR,
|
||||
},
|
||||
{
|
||||
caseName: "views case",
|
||||
item: OSSItem{
|
||||
tp: FileType,
|
||||
path: viewPath,
|
||||
name: "pod-view.cue",
|
||||
},
|
||||
root: "test-view",
|
||||
meetPattern: "views",
|
||||
r: viewOSSR,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
res := GetPatternFromItem(tc.item, tc.r, tc.root)
|
||||
@@ -1166,36 +946,6 @@ func TestReadDefFile(t *testing.T) {
|
||||
assert.True(t, len(uiData.Definitions) == 1)
|
||||
}
|
||||
|
||||
// Test readDefFile only accept .cue
|
||||
func TestReadViewFile(t *testing.T) {
|
||||
|
||||
// setup test data
|
||||
testAddonName := "test-view"
|
||||
testAddonDir := fmt.Sprintf("./testdata/%s", testAddonName)
|
||||
reader := localReader{dir: testAddonDir, name: testAddonName}
|
||||
metas, err := reader.ListAddonMeta()
|
||||
testAddonMeta := metas[testAddonName]
|
||||
assert.NoError(t, err)
|
||||
|
||||
// run test
|
||||
var addon = &InstallPackage{}
|
||||
ptItems := ClassifyItemByPattern(&testAddonMeta, reader)
|
||||
items := ptItems[ViewDirName]
|
||||
|
||||
for _, it := range items {
|
||||
err := readViewFile(addon, reader, reader.RelativePath(it))
|
||||
if err != nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
}
|
||||
notExistErr := readViewFile(addon, reader, "not-exist.cue")
|
||||
assert.Error(t, notExistErr)
|
||||
|
||||
// verify
|
||||
assert.True(t, len(addon.CUEViews) == 1)
|
||||
assert.True(t, len(addon.YAMLViews) == 1)
|
||||
}
|
||||
|
||||
func TestRenderCUETemplate(t *testing.T) {
|
||||
fileDate, err := os.ReadFile("./testdata/example/resources/configmap.cue")
|
||||
assert.NoError(t, err)
|
||||
@@ -1228,10 +978,6 @@ func TestPackageAddon(t *testing.T) {
|
||||
archiver, err := PackageAddon(validAddonDict)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, filepath.Join(pwd, "example-1.0.1.tgz"), archiver)
|
||||
// Remove generated package after tests
|
||||
defer func() {
|
||||
_ = os.RemoveAll(filepath.Join(pwd, "example-1.0.1.tgz"))
|
||||
}()
|
||||
|
||||
invalidAddonDict := "./testdata"
|
||||
archiver, err = PackageAddon(invalidAddonDict)
|
||||
@@ -1244,19 +990,3 @@ func TestPackageAddon(t *testing.T) {
|
||||
assert.Equal(t, "", archiver)
|
||||
|
||||
}
|
||||
|
||||
func TestGenerateAnnotation(t *testing.T) {
|
||||
meta := Meta{SystemRequirements: &SystemRequirements{
|
||||
VelaVersion: ">1.4.0",
|
||||
KubernetesVersion: ">1.20.0",
|
||||
}}
|
||||
res := generateAnnotation(&meta)
|
||||
assert.Equal(t, res[velaSystemRequirement], ">1.4.0")
|
||||
assert.Equal(t, res[kubernetesSystemRequirement], ">1.20.0")
|
||||
|
||||
meta = Meta{}
|
||||
meta.SystemRequirements = &SystemRequirements{KubernetesVersion: ">=1.20.1"}
|
||||
res = generateAnnotation(&meta)
|
||||
assert.Equal(t, res[velaSystemRequirement], "")
|
||||
assert.Equal(t, res[kubernetesSystemRequirement], ">=1.20.1")
|
||||
}
|
||||
|
||||
@@ -1,378 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package addon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
|
||||
"cuelang.org/go/cue"
|
||||
"cuelang.org/go/cue/format"
|
||||
"cuelang.org/go/encoding/gocode/gocodec"
|
||||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1"
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
)
|
||||
|
||||
// CreateAddonFromHelmChart creates an addon scaffold from a Helm Chart, with a Helm component inside
|
||||
func CreateAddonFromHelmChart(addonName, addonPath, helmRepoURL, chartName, chartVersion string) error {
|
||||
if len(addonName) == 0 || len(helmRepoURL) == 0 || len(chartName) == 0 || len(chartVersion) == 0 {
|
||||
return fmt.Errorf("addon addonPath, helm URL, chart name, and chart verion should not be empty")
|
||||
}
|
||||
|
||||
// Currently, we do not check whether the Helm Chart actually exists, because it is just a scaffold.
|
||||
// The user can still edit it after creation.
|
||||
// Also, if the user is offline, we cannot check whether the Helm Chart exists.
|
||||
// TODO(charlie0129): check whether the Helm Chart exists (if the user wants)
|
||||
|
||||
// Make sure url is valid
|
||||
isValidURL := utils.IsValidURL(helmRepoURL)
|
||||
if !isValidURL {
|
||||
return fmt.Errorf("invalid helm repo url %s", helmRepoURL)
|
||||
}
|
||||
|
||||
err := preAddonCreation(addonName, addonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create files like template.yaml, README.md, and etc.
|
||||
err = createFilesFromHelmChart(addonName, addonPath, helmRepoURL, chartName, chartVersion)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create addon files: %w", err)
|
||||
}
|
||||
|
||||
postAddonCreation(addonPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateAddonSample creates an empty addon scaffold, with some required files
|
||||
func CreateAddonSample(addonName, addonPath string) error {
|
||||
if len(addonName) == 0 || len(addonPath) == 0 {
|
||||
return fmt.Errorf("addon name and addon path should not be empty")
|
||||
}
|
||||
|
||||
err := preAddonCreation(addonName, addonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = createSampleFiles(addonName, addonPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
postAddonCreation(addonPath)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// preAddonCreation is executed before creating an addon scaffold
|
||||
// It makes sure that user-provided info is valid.
|
||||
func preAddonCreation(addonName, addonPath string) error {
|
||||
if len(addonName) == 0 || len(addonPath) == 0 {
|
||||
return fmt.Errorf("addon name and addonPath should not be empty")
|
||||
}
|
||||
|
||||
// Make sure addon name is valid
|
||||
err := CheckAddonName(addonName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create dirs
|
||||
err = createAddonDirs(addonPath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot create addon structure: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// postAddonCreation is after before creating an addon scaffold
|
||||
// It prints some instructions to get started.
|
||||
func postAddonCreation(addonPath string) {
|
||||
fmt.Println("Scaffold created in directory " +
|
||||
color.New(color.Bold).Sprint(addonPath) + ". What to do next:\n" +
|
||||
"- Check out our guide on how to build your own addon: " +
|
||||
color.BlueString("https://kubevela.io/docs/platform-engineers/addon/intro") + "\n" +
|
||||
"- Review and edit what we have generated in " + color.New(color.Bold).Sprint(addonPath) + "\n" +
|
||||
"- To enable the addon, run: " +
|
||||
color.New(color.FgGreen).Sprint("vela") + color.GreenString(" addon enable ") + color.New(color.Bold, color.FgGreen).Sprint(addonPath))
|
||||
}
|
||||
|
||||
// CheckAddonName checks if an addon name is valid
|
||||
func CheckAddonName(addonName string) error {
|
||||
if len(addonName) == 0 {
|
||||
return fmt.Errorf("addon name should not be empty")
|
||||
}
|
||||
|
||||
// Make sure addonName only contains lowercase letters, dashes, and numbers, e.g. some-addon
|
||||
re := regexp.MustCompile(`^[a-z\d]+(-[a-z\d]+)*$`)
|
||||
if !re.MatchString(addonName) {
|
||||
return fmt.Errorf("addon name should only cocntain lowercase letters, dashes, and numbers, e.g. some-addon")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createFilesFromHelmChart creates the file structure for a Helm Chart addon,
|
||||
// including template.yaml, readme.md, metadata.yaml, and <addon-nam>.cue.
|
||||
func createFilesFromHelmChart(addonName, addonPath, helmRepoURL, chartName, chartVersion string) error {
|
||||
// Generate template.yaml with an empty Application
|
||||
applicationTemplate := v1beta1.Application{
|
||||
TypeMeta: v1.TypeMeta{
|
||||
APIVersion: v1beta1.SchemeGroupVersion.String(),
|
||||
Kind: "Application",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: addonName,
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
}
|
||||
|
||||
applicationTemplateBytes, err := yaml.Marshal(applicationTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate metadata.yaml with `fluxcd` as a dependency because we are using helm.
|
||||
// However, this may change in the future, possibly with `argocd`.
|
||||
metadataTemplate := Meta{
|
||||
Name: addonName,
|
||||
Version: chartVersion,
|
||||
Description: "An addon for KubeVela.",
|
||||
Tags: []string{chartVersion},
|
||||
Dependencies: []*Dependency{{Name: "fluxcd"}},
|
||||
}
|
||||
metadataTemplateBytes, err := yaml.Marshal(metadataTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write template.yaml, readme.md, and metadata.yaml
|
||||
err = writeRequiredFiles(addonPath,
|
||||
applicationTemplateBytes,
|
||||
[]byte(strings.ReplaceAll(readmeTemplate, "ADDON_NAME", addonName)),
|
||||
metadataTemplateBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Write addonName.cue, containing the helm chart
|
||||
addonResourcePath := path.Join(addonPath, ResourcesDirName, addonName+".cue")
|
||||
resourceTmpl := HelmCUETemplate{}
|
||||
resourceTmpl.Output.Type = "helm"
|
||||
resourceTmpl.Output.Properties.RepoType = "helm"
|
||||
resourceTmpl.Output.Properties.URL = helmRepoURL
|
||||
resourceTmpl.Output.Properties.Chart = chartName
|
||||
resourceTmpl.Output.Properties.Version = chartVersion
|
||||
err = writeHelmCUETemplate(resourceTmpl, addonResourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createSampleFiles creates the file structure for an empty addon
|
||||
func createSampleFiles(addonName, addonPath string) error {
|
||||
// Generate metadata.yaml
|
||||
metadataTemplate := Meta{
|
||||
Name: addonName,
|
||||
Version: "1.0.0",
|
||||
Description: "An addon for KubeVela.",
|
||||
Tags: []string{},
|
||||
Dependencies: []*Dependency{},
|
||||
}
|
||||
metadataTemplateBytes, err := yaml.Marshal(metadataTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Generate template.yaml
|
||||
applicationTemplate := v1beta1.Application{
|
||||
TypeMeta: v1.TypeMeta{
|
||||
APIVersion: v1beta1.SchemeGroupVersion.String(),
|
||||
Kind: "Application",
|
||||
},
|
||||
ObjectMeta: v1.ObjectMeta{
|
||||
Name: addonName,
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
},
|
||||
}
|
||||
applicationTemplateBytes, err := yaml.Marshal(applicationTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeRequiredFiles(addonPath,
|
||||
applicationTemplateBytes,
|
||||
[]byte(strings.ReplaceAll(readmeTemplate, "ADDON_NAME", addonName)),
|
||||
metadataTemplateBytes)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeRequiredFiles creates required files for an addon,
|
||||
// including template.yaml, readme.md, and metadata.yaml
|
||||
func writeRequiredFiles(addonPath string, tmplContent, readmeContent, metadataContent []byte) error {
|
||||
// Write template.yaml
|
||||
templateFilePath := path.Join(addonPath, TemplateFileName)
|
||||
err := os.WriteFile(templateFilePath,
|
||||
tmplContent,
|
||||
0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write %s: %w", templateFilePath, err)
|
||||
}
|
||||
|
||||
// Write README.md
|
||||
readmeFilePath := path.Join(addonPath, ReadmeFileName)
|
||||
err = os.WriteFile(readmeFilePath,
|
||||
readmeContent,
|
||||
0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write %s: %w", readmeFilePath, err)
|
||||
}
|
||||
|
||||
// Write metadata.yaml
|
||||
metadataFilePath := path.Join(addonPath, MetadataFileName)
|
||||
err = os.WriteFile(metadataFilePath,
|
||||
metadataContent,
|
||||
0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write %s: %w", metadataFilePath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// createAddonDirs creates the directory structure for an addon
|
||||
func createAddonDirs(addonDir string) error {
|
||||
// Make sure addonDir is pointing to an empty directory, or does not exist at all
|
||||
// so that we can create it later
|
||||
_, err := os.Stat(addonDir)
|
||||
if !os.IsNotExist(err) {
|
||||
emptyDir, err := utils.IsEmptyDir(addonDir)
|
||||
if err != nil {
|
||||
return fmt.Errorf("we can't create directory %s. Make sure the name has not already been taken and you have the proper rights to write to it", addonDir)
|
||||
}
|
||||
|
||||
if !emptyDir {
|
||||
return fmt.Errorf("directory %s is not empty. To avoid any data loss, please manually delete it first, then try again", addonDir)
|
||||
}
|
||||
|
||||
// Now we are sure addonPath is en empty dir, delete it
|
||||
err = os.Remove(addonDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// nolint:gosec
|
||||
err = os.MkdirAll(addonDir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dirs := []string{
|
||||
path.Join(addonDir, ResourcesDirName),
|
||||
path.Join(addonDir, DefinitionsDirName),
|
||||
path.Join(addonDir, DefSchemaName),
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
// nolint:gosec
|
||||
err = os.MkdirAll(dir, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// writeHelmCUETemplate writes a cue, with a helm component inside, intended as addon resource
|
||||
func writeHelmCUETemplate(tmpl HelmCUETemplate, filePath string) error {
|
||||
r := cue.Runtime{}
|
||||
v, err := gocodec.New(&r, nil).Decode(tmpl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use `output` value
|
||||
v = v.Lookup("output")
|
||||
// Format output
|
||||
bs, err := format.Node(v.Syntax())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Append "output: " to the beginning of the string, like "output: {}"
|
||||
bs = append([]byte("output: "), bs...)
|
||||
err = os.WriteFile(filePath, bs, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot write %s: %w", filePath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// HelmCUETemplate is a template for a helm component .cue in an addon
|
||||
type HelmCUETemplate struct {
|
||||
Output struct {
|
||||
Type string `json:"type"`
|
||||
Properties struct {
|
||||
RepoType string `json:"repoType"`
|
||||
URL string `json:"url"`
|
||||
Chart string `json:"chart"`
|
||||
Version string `json:"version"`
|
||||
} `json:"properties"`
|
||||
} `json:"output"`
|
||||
}
|
||||
|
||||
const (
|
||||
readmeTemplate = "# ADDON_NAME\n" +
|
||||
"\n" +
|
||||
"This is an addon template. Check how to build your own addon: https://kubevela.net/docs/platform-engineers/addon/intro\n" +
|
||||
"\n" +
|
||||
"## Directory Structure\n" +
|
||||
"\n" +
|
||||
"- `template.yaml`: contains the basic app, you can add some component and workflow to meet your requirements. Other files in `resources/` and `definitions/` will be rendered as Components and appended in `spec.components`\n" +
|
||||
"- `metadata.yaml`: contains addon metadata information.\n" +
|
||||
"- `definitions/`: contains the X-Definition yaml/cue files. These file will be rendered as KubeVela Component in `template.yaml`\n" +
|
||||
"- `resources/`:\n" +
|
||||
" - `parameter.cue` to expose parameters. It will be converted to JSON schema and rendered in UI forms.\n" +
|
||||
" - All other files will be rendered as KubeVela Components. It can be one of the two types:\n" +
|
||||
" - YAML file that contains only one resource. This will be rendered as a `raw` component\n" +
|
||||
" - CUE template file that can read user input as `parameter.XXX` as defined `parameter.cue`.\n" +
|
||||
" Basically the CUE template file will be combined with `parameter.cue` to render a resource.\n" +
|
||||
" **You can specify the type and trait in this format**\n" +
|
||||
""
|
||||
)
|
||||
@@ -1,171 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package addon
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"gotest.tools/assert"
|
||||
)
|
||||
|
||||
func TestCheckAddonName(t *testing.T) {
|
||||
var err error
|
||||
|
||||
err = CheckAddonName("")
|
||||
assert.ErrorContains(t, err, "should not be empty")
|
||||
|
||||
invalidNames := []string{
|
||||
"-addon",
|
||||
"addon-",
|
||||
"Caps",
|
||||
"=",
|
||||
".",
|
||||
}
|
||||
for _, name := range invalidNames {
|
||||
err = CheckAddonName(name)
|
||||
assert.ErrorContains(t, err, "should only")
|
||||
}
|
||||
|
||||
validNames := []string{
|
||||
"addon-name",
|
||||
"3-addon-name",
|
||||
"addon-name-3",
|
||||
"addon",
|
||||
}
|
||||
for _, name := range validNames {
|
||||
err = CheckAddonName(name)
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestWriteHelmCUETemplate(t *testing.T) {
|
||||
resourceTmpl := HelmCUETemplate{}
|
||||
resourceTmpl.Output.Type = "helm"
|
||||
resourceTmpl.Output.Properties.RepoType = "helm"
|
||||
resourceTmpl.Output.Properties.URL = "https://charts.bitnami.com/bitnami"
|
||||
resourceTmpl.Output.Properties.Chart = "bitnami/nginx"
|
||||
resourceTmpl.Output.Properties.Version = "12.0.4"
|
||||
err := writeHelmCUETemplate(resourceTmpl, "test.cue")
|
||||
assert.NilError(t, err)
|
||||
defer func() {
|
||||
_ = os.Remove("test.cue")
|
||||
}()
|
||||
data, err := os.ReadFile("test.cue")
|
||||
assert.NilError(t, err)
|
||||
expected := `output: {
|
||||
type: "helm"
|
||||
properties: {
|
||||
url: "https://charts.bitnami.com/bitnami"
|
||||
repoType: "helm"
|
||||
chart: "bitnami/nginx"
|
||||
version: "12.0.4"
|
||||
}
|
||||
}`
|
||||
assert.Equal(t, string(data), expected)
|
||||
}
|
||||
|
||||
func TestCreateAddonFromHelmChart(t *testing.T) {
|
||||
err := CreateAddonFromHelmChart("", "", "", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "should not be empty")
|
||||
|
||||
checkFiles := func(base string) {
|
||||
fileList := []string{
|
||||
"definitions",
|
||||
path.Join("resources", base+".cue"),
|
||||
"schemas",
|
||||
MetadataFileName,
|
||||
ReadmeFileName,
|
||||
TemplateFileName,
|
||||
}
|
||||
for _, file := range fileList {
|
||||
_, err = os.Stat(path.Join(base, file))
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Empty dir already exists
|
||||
_ = os.MkdirAll("test-addon", 0755)
|
||||
err = CreateAddonFromHelmChart("test-addon", "./test-addon", "https://charts.bitnami.com/bitnami", "bitnami/nginx", "12.0.4")
|
||||
checkFiles("test-addon")
|
||||
defer func() {
|
||||
_ = os.RemoveAll("test-addon")
|
||||
}()
|
||||
|
||||
// Non-empty dir already exists
|
||||
err = CreateAddonFromHelmChart("test-addon", "test-addon", "https://charts.bitnami.com/bitnami", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "not empty")
|
||||
|
||||
// Name already taken
|
||||
err = os.WriteFile("already-taken", []byte{}, 0644)
|
||||
assert.NilError(t, err)
|
||||
defer func() {
|
||||
_ = os.Remove("already-taken")
|
||||
}()
|
||||
err = CreateAddonFromHelmChart("already-taken", "already-taken", "https://charts.bitnami.com/bitnami", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "can't create")
|
||||
|
||||
// Invalid addon name
|
||||
err = CreateAddonFromHelmChart("/", "./a", "https://charts.bitnami.com/bitnami", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "should only")
|
||||
|
||||
// Invalid URL
|
||||
err = CreateAddonFromHelmChart("invalid-url", "invalid-url", "invalid-url", "bitnami/nginx", "12.0.4")
|
||||
assert.ErrorContains(t, err, "invalid helm repo url")
|
||||
}
|
||||
|
||||
func TestCreateAddonSample(t *testing.T) {
|
||||
checkFiles := func(base string) {
|
||||
fileList := []string{
|
||||
"definitions",
|
||||
"resources",
|
||||
"schemas",
|
||||
MetadataFileName,
|
||||
ReadmeFileName,
|
||||
TemplateFileName,
|
||||
}
|
||||
for _, file := range fileList {
|
||||
_, err := os.Stat(path.Join(base, file))
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Normal creation
|
||||
err := CreateAddonSample("test-addon", "test-addon")
|
||||
assert.NilError(t, err)
|
||||
checkFiles("test-addon")
|
||||
|
||||
// Non-empty dir already exists
|
||||
err = CreateAddonSample("test-addon", "test-addon")
|
||||
assert.ErrorContains(t, err, "directory")
|
||||
|
||||
defer func() {
|
||||
_ = os.RemoveAll("test-addon")
|
||||
}()
|
||||
|
||||
err = CreateAddonSample("", "")
|
||||
assert.ErrorContains(t, err, "empty")
|
||||
}
|
||||
|
||||
func TestPreAddonCreation(t *testing.T) {
|
||||
err := preAddonCreation("", "")
|
||||
assert.ErrorContains(t, err, "empty")
|
||||
|
||||
err = preAddonCreation("=", "a")
|
||||
assert.ErrorContains(t, err, "name")
|
||||
}
|
||||
@@ -55,24 +55,8 @@ func WrapErrRateLimit(err error) error {
|
||||
type VersionUnMatchError struct {
|
||||
err error
|
||||
addonName string
|
||||
// userSelectedAddonVersion is the version of the addon which is selected to install by user
|
||||
userSelectedAddonVersion string
|
||||
// availableVersion is the latest available addon's version which suits system requirements
|
||||
availableVersion string
|
||||
}
|
||||
|
||||
// GetAvailableVersion load addon's available version from the err
|
||||
func (v VersionUnMatchError) GetAvailableVersion() (string, error) {
|
||||
if v.availableVersion == "" {
|
||||
return "", fmt.Errorf("%s don't exist available version meet system requirement", v.addonName)
|
||||
}
|
||||
return v.availableVersion, nil
|
||||
}
|
||||
|
||||
func (v VersionUnMatchError) Error() string {
|
||||
if v.availableVersion != "" {
|
||||
return fmt.Sprintf("fail to install %s version of %s, because %s.\nInstall %s(v%s) which is the latest version that suits current version requirements", v.userSelectedAddonVersion, v.addonName, v.err, v.addonName, v.availableVersion)
|
||||
}
|
||||
return fmt.Sprintf("fail to install %s version of %s, because %s", v.userSelectedAddonVersion, v.addonName, v.err)
|
||||
|
||||
return fmt.Sprintf("addon %s system requirement miss match: %v", v.addonName, v.err)
|
||||
}
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package addon
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestError(t *testing.T) {
|
||||
err := &VersionUnMatchError{}
|
||||
assert.False(t, strings.Contains(err.Error(), "which is the latest version that suits current version requirements"))
|
||||
err = &VersionUnMatchError{availableVersion: "1.0.0"}
|
||||
assert.Contains(t, err.Error(), "which is the latest version that suits current version requirements")
|
||||
}
|
||||
|
||||
func TestGetAvailableVersion(t *testing.T) {
|
||||
unMatchErr := &VersionUnMatchError{availableVersion: "1.0.0"}
|
||||
version, err := unMatchErr.GetAvailableVersion()
|
||||
assert.Empty(t, err)
|
||||
assert.Equal(t, version, "1.0.0")
|
||||
|
||||
unMatchErr = &VersionUnMatchError{}
|
||||
version, err = unMatchErr.GetAvailableVersion()
|
||||
assert.NotEmpty(t, err)
|
||||
assert.Equal(t, version, "")
|
||||
}
|
||||
BIN
pkg/addon/example-1.0.1.tgz
Normal file
BIN
pkg/addon/example-1.0.1.tgz
Normal file
Binary file not shown.
@@ -36,7 +36,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
)
|
||||
@@ -163,7 +162,7 @@ func GetAddonStatus(ctx context.Context, cli client.Client, name string) (Status
|
||||
|
||||
// Get addon parameters
|
||||
var sec v1.Secret
|
||||
err = cli.Get(ctx, client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: addonutil.Addon2SecName(name)}, &sec)
|
||||
err = cli.Get(ctx, client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: Convert2SecName(name)}, &sec)
|
||||
if err != nil {
|
||||
// Not found error can be ignored. Others can't.
|
||||
if !apierrors.IsNotFound(err) {
|
||||
@@ -187,7 +186,7 @@ func GetAddonStatus(ctx context.Context, cli client.Client, name string) (Status
|
||||
sec v1.Secret
|
||||
domain string
|
||||
)
|
||||
if err = cli.Get(ctx, client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: addonutil.Addon2SecName(name)}, &sec); err != nil {
|
||||
if err = cli.Get(ctx, client.ObjectKey{Namespace: types.DefaultKubeVelaNS, Name: Convert2SecName(name)}, &sec); err != nil {
|
||||
klog.ErrorS(err, "failed to get observability secret")
|
||||
addonStatus.AddonPhase = enabling
|
||||
addonStatus.InstalledVersion = ""
|
||||
|
||||
@@ -1,299 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package addon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
cm "github.com/chartmuseum/helm-push/pkg/chartmuseum"
|
||||
cmhelm "github.com/chartmuseum/helm-push/pkg/helm"
|
||||
"github.com/fatih/color"
|
||||
helmrepo "helm.sh/helm/v3/pkg/repo"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
)
|
||||
|
||||
// PushCmd is the command object to initiate a push command to ChartMuseum
|
||||
type PushCmd struct {
|
||||
ChartName string
|
||||
AppVersion string
|
||||
ChartVersion string
|
||||
RepoName string
|
||||
Username string
|
||||
Password string
|
||||
AccessToken string
|
||||
AuthHeader string
|
||||
ContextPath string
|
||||
ForceUpload bool
|
||||
UseHTTP bool
|
||||
CaFile string
|
||||
CertFile string
|
||||
KeyFile string
|
||||
InsecureSkipVerify bool
|
||||
Out io.Writer
|
||||
Timeout int64
|
||||
KeepChartMetadata bool
|
||||
// We need it to search in addon registries.
|
||||
// If you use URL, instead of registry names, then it is not needed.
|
||||
Client client.Client
|
||||
}
|
||||
|
||||
// Push pushes addons (i.e. Helm Charts) to ChartMuseum.
|
||||
// It will package the addon into a Helm Chart if necessary.
|
||||
func (p *PushCmd) Push(ctx context.Context) error {
|
||||
var repo *cmhelm.Repo
|
||||
var err error
|
||||
|
||||
// Get the user specified Helm repo
|
||||
repo, err = GetHelmRepo(ctx, p.Client, p.RepoName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Make the addon dir a Helm Chart
|
||||
// The user can decide if they want Chart.yaml be in sync with addon metadata.yaml
|
||||
// By default, it will recreate Chart.yaml according to addon metadata.yaml
|
||||
err = MakeChartCompatible(p.ChartName, !p.KeepChartMetadata)
|
||||
// `Not a directory` errors are ignored, that's fine,
|
||||
// since .tgz files are also supported.
|
||||
if err != nil && !strings.Contains(err.Error(), "is not a directory") {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get chart from a directory or .tgz package
|
||||
chart, err := cmhelm.GetChartByName(p.ChartName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Override chart version using specified version
|
||||
if p.ChartVersion != "" {
|
||||
chart.SetVersion(p.ChartVersion)
|
||||
}
|
||||
|
||||
// Override app version using specified version
|
||||
if p.AppVersion != "" {
|
||||
chart.SetAppVersion(p.AppVersion)
|
||||
}
|
||||
|
||||
// Override username and password using specified values
|
||||
username := repo.Config.Username
|
||||
password := repo.Config.Password
|
||||
if p.Username != "" {
|
||||
username = p.Username
|
||||
}
|
||||
if p.Password != "" {
|
||||
password = p.Password
|
||||
}
|
||||
|
||||
// Unset accessToken if repo credentials are provided
|
||||
if username != "" && password != "" {
|
||||
p.AccessToken = ""
|
||||
}
|
||||
|
||||
// In case the repo is stored with cm:// protocol,
|
||||
// (if that's somehow possible with KubeVela addon registries)
|
||||
// use http instead,
|
||||
// otherwise keep as it-is.
|
||||
var url string
|
||||
if p.UseHTTP {
|
||||
url = strings.Replace(repo.Config.URL, "cm://", "http://", 1)
|
||||
} else {
|
||||
url = strings.Replace(repo.Config.URL, "cm://", "https://", 1)
|
||||
}
|
||||
|
||||
cmClient, err := cm.NewClient(
|
||||
cm.URL(url),
|
||||
cm.Username(username),
|
||||
cm.Password(password),
|
||||
cm.AccessToken(p.AccessToken),
|
||||
cm.AuthHeader(p.AuthHeader),
|
||||
cm.ContextPath(p.ContextPath),
|
||||
cm.CAFile(p.CaFile),
|
||||
cm.CertFile(p.CertFile),
|
||||
cm.KeyFile(p.KeyFile),
|
||||
cm.InsecureSkipVerify(p.InsecureSkipVerify),
|
||||
cm.Timeout(p.Timeout),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Use a temporary dir to hold packaged .tgz Charts
|
||||
tmp, err := ioutil.TempDir("", "helm-push-")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func(path string) {
|
||||
_ = os.RemoveAll(path)
|
||||
}(tmp)
|
||||
|
||||
// Package Chart into .tgz packages for uploading to ChartMuseum
|
||||
chartPackagePath, err := cmhelm.CreateChartPackage(chart, tmp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _ = fmt.Fprintf(os.Stderr, "Pushing %s to %s... ",
|
||||
color.New(color.Bold).Sprintf(filepath.Base(chartPackagePath)),
|
||||
formatRepoNameAndURL(p.RepoName, repo.Config.URL),
|
||||
)
|
||||
|
||||
// Push Chart to ChartMuseum
|
||||
resp, err := cmClient.UploadChartPackage(chartPackagePath, p.ForceUpload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return handlePushResponse(resp)
|
||||
}
|
||||
|
||||
// GetHelmRepo searches for a Helm repo by name.
|
||||
// By saying name, it can actually be a URL or a name.
|
||||
// If a URL is provided, a temp repo object is returned.
|
||||
// If a name is provided, we will try to find it in local addon registries (only Helm type).
|
||||
func GetHelmRepo(ctx context.Context, c client.Client, repoName string) (*cmhelm.Repo, error) {
|
||||
var repo *cmhelm.Repo
|
||||
var err error
|
||||
|
||||
// If RepoName looks like a URL (https / http), just create a temp repo object.
|
||||
// We do not look for it in local addon registries.
|
||||
if regexp.MustCompile(`^https?://`).MatchString(repoName) {
|
||||
repo, err = cmhelm.TempRepoFromURL(repoName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
// Otherwise, search for in it in the local addon registries.
|
||||
ds := NewRegistryDataStore(c)
|
||||
registries, err := ds.ListRegistries(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var matchedEntry *helmrepo.Entry
|
||||
|
||||
// Search for the target repo name in addon registries
|
||||
for _, reg := range registries {
|
||||
// We are only interested in Helm registries.
|
||||
if reg.Helm == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if reg.Name == repoName {
|
||||
matchedEntry = &helmrepo.Entry{
|
||||
Name: reg.Name,
|
||||
URL: reg.Helm.URL,
|
||||
Username: reg.Helm.Username,
|
||||
Password: reg.Helm.Password,
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if matchedEntry == nil {
|
||||
return nil, fmt.Errorf("we cannot find Helm repository %s. Make sure you hava added it using `vela addon registry add` and it is a Helm repository", repoName)
|
||||
}
|
||||
|
||||
// Use the repo found locally.
|
||||
repo = &cmhelm.Repo{ChartRepository: &helmrepo.ChartRepository{Config: matchedEntry}}
|
||||
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
// SetFieldsFromEnv sets fields in PushCmd from environment variables
|
||||
func (p *PushCmd) SetFieldsFromEnv() {
|
||||
if v, ok := os.LookupEnv("HELM_REPO_USERNAME"); ok && p.Username == "" {
|
||||
p.Username = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_PASSWORD"); ok && p.Password == "" {
|
||||
p.Password = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_ACCESS_TOKEN"); ok && p.AccessToken == "" {
|
||||
p.AccessToken = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_AUTH_HEADER"); ok && p.AuthHeader == "" {
|
||||
p.AuthHeader = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_CONTEXT_PATH"); ok && p.ContextPath == "" {
|
||||
p.ContextPath = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_USE_HTTP"); ok {
|
||||
p.UseHTTP, _ = strconv.ParseBool(v)
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_CA_FILE"); ok && p.CaFile == "" {
|
||||
p.CaFile = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_CERT_FILE"); ok && p.CertFile == "" {
|
||||
p.CertFile = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_KEY_FILE"); ok && p.KeyFile == "" {
|
||||
p.KeyFile = v
|
||||
}
|
||||
if v, ok := os.LookupEnv("HELM_REPO_INSECURE"); ok {
|
||||
p.InsecureSkipVerify, _ = strconv.ParseBool(v)
|
||||
}
|
||||
}
|
||||
|
||||
// handlePushResponse checks response from ChartMuseum
|
||||
func handlePushResponse(resp *http.Response) error {
|
||||
if resp.StatusCode != 201 && resp.StatusCode != 202 {
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%s\n", color.RedString("Failed"))
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return getChartMuseumError(b, resp.StatusCode)
|
||||
}
|
||||
_, _ = fmt.Fprintf(os.Stderr, "%s\n", color.GreenString("Done"))
|
||||
return nil
|
||||
}
|
||||
|
||||
// getChartMuseumError checks error messages from the response
|
||||
func getChartMuseumError(b []byte, code int) error {
|
||||
var er struct {
|
||||
Error string `json:"error"`
|
||||
}
|
||||
err := json.Unmarshal(b, &er)
|
||||
if err != nil || er.Error == "" {
|
||||
return fmt.Errorf("%d: could not properly parse response JSON: %s", code, string(b))
|
||||
}
|
||||
return fmt.Errorf("%d: %s", code, er.Error)
|
||||
}
|
||||
|
||||
func formatRepoNameAndURL(name, url string) string {
|
||||
if name == "" || regexp.MustCompile(`^https?://`).MatchString(name) {
|
||||
return color.BlueString(url)
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s(%s)",
|
||||
color.New(color.Bold).Sprintf(name),
|
||||
color.BlueString(url),
|
||||
)
|
||||
}
|
||||
@@ -1,203 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package addon
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/helm/pkg/tlsutil"
|
||||
)
|
||||
|
||||
var _ = Describe("Addon push command", func() {
|
||||
var (
|
||||
testTarballPath = "testdata/charts/sample-1.0.1.tgz"
|
||||
testServerCertPath = "testdata/tls/server.crt"
|
||||
testServerKeyPath = "testdata/tls/server.key"
|
||||
testServerCAPath = "testdata/tls/server_ca.crt"
|
||||
testClientCAPath = "testdata/tls/client_ca.crt"
|
||||
testClientCertPath = "testdata/tls/client.crt"
|
||||
testClientKeyPath = "testdata/tls/client.key"
|
||||
)
|
||||
var (
|
||||
statusCode int
|
||||
body string
|
||||
tmp string
|
||||
)
|
||||
var p *PushCmd
|
||||
var ts *httptest.Server
|
||||
var err error
|
||||
var ds RegistryDataStore
|
||||
|
||||
setArgsAndRun := func(args []string) error {
|
||||
p = &PushCmd{}
|
||||
p.Client = k8sClient
|
||||
p.Out = os.Stdout
|
||||
p.ChartName = args[0]
|
||||
p.RepoName = args[1]
|
||||
p.SetFieldsFromEnv()
|
||||
return p.Push(context.TODO())
|
||||
}
|
||||
|
||||
AfterEach(func() {
|
||||
ts.Close()
|
||||
_ = os.RemoveAll(tmp)
|
||||
err = ds.DeleteRegistry(context.TODO(), "helm-push-test")
|
||||
Expect(err).To(Succeed())
|
||||
})
|
||||
|
||||
Context("plain old HTTP Server", func() {
|
||||
BeforeEach(func() {
|
||||
statusCode = 201
|
||||
body = "{\"success\": true}"
|
||||
ts = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(statusCode)
|
||||
w.Write([]byte(body))
|
||||
}))
|
||||
|
||||
// Create new Helm home w/ test repo
|
||||
tmp, err = ioutil.TempDir("", "helm-push-test")
|
||||
Expect(err).To(Succeed())
|
||||
|
||||
// Add our helm repo to addon registry
|
||||
ds = NewRegistryDataStore(k8sClient)
|
||||
err = ds.AddRegistry(context.TODO(), Registry{
|
||||
Name: "helm-push-test",
|
||||
Helm: &HelmSource{
|
||||
URL: ts.URL,
|
||||
},
|
||||
})
|
||||
Expect(err).To(Succeed())
|
||||
|
||||
_ = os.Setenv("HELM_REPO_USERNAME", "myuser")
|
||||
_ = os.Setenv("HELM_REPO_PASSWORD", "mypass")
|
||||
_ = os.Setenv("HELM_REPO_CONTEXT_PATH", "/x/y/z")
|
||||
})
|
||||
|
||||
It("Not enough args", func() {
|
||||
err = setArgsAndRun([]string{"", ""})
|
||||
Expect(err).ShouldNot(Succeed(), "expecting error with missing args, instead got nil")
|
||||
})
|
||||
|
||||
It("Bad chart path", func() {
|
||||
args := []string{"/this/this/not/a/chart", "helm-push-test"}
|
||||
err = setArgsAndRun(args)
|
||||
Expect(err).ShouldNot(Succeed(), "expecting error with bad chart path, instead got nil")
|
||||
})
|
||||
|
||||
It("Bad repo name", func() {
|
||||
args := []string{testTarballPath, "this-is-not-a-valid-repo"}
|
||||
err = setArgsAndRun(args)
|
||||
Expect(err).ShouldNot(Succeed(), "expecting error with bad repo name, instead got nil")
|
||||
})
|
||||
|
||||
It("Valid tar, repo name", func() {
|
||||
args := []string{testTarballPath, "helm-push-test"}
|
||||
err = setArgsAndRun(args)
|
||||
Expect(err).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Valid tar, repo URL", func() {
|
||||
args := []string{testTarballPath, ts.URL}
|
||||
err = setArgsAndRun(args)
|
||||
Expect(err).Should(Succeed())
|
||||
})
|
||||
|
||||
It("Trigger 409, already exists", func() {
|
||||
statusCode = 409
|
||||
body = "{\"error\": \"package already exists\"}"
|
||||
args := []string{testTarballPath, "helm-push-test"}
|
||||
err = setArgsAndRun(args)
|
||||
Expect(err).ShouldNot(Succeed(), "expecting error with 409, instead got nil")
|
||||
})
|
||||
|
||||
It("Unable to parse JSON response body", func() {
|
||||
statusCode = 500
|
||||
body = "duiasnhioasd"
|
||||
args := []string{testTarballPath, "helm-push-test"}
|
||||
err = setArgsAndRun(args)
|
||||
Expect(err).ShouldNot(Succeed(), "expecting error with bad response body, instead got nil")
|
||||
})
|
||||
})
|
||||
|
||||
Context("TLS Enabled Server", func() {
|
||||
BeforeEach(func() {
|
||||
statusCode = 201
|
||||
body = "{\"success\": true}"
|
||||
ts = httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(statusCode)
|
||||
_, _ = w.Write([]byte(body))
|
||||
}))
|
||||
serverCert, err := tls.LoadX509KeyPair(testServerCertPath, testServerKeyPath)
|
||||
Expect(err).To(Succeed(), "failed to load certificate and key")
|
||||
|
||||
clientCaCertPool, err := tlsutil.CertPoolFromFile(testClientCAPath)
|
||||
Expect(err).To(Succeed(), "load server CA file failed")
|
||||
|
||||
ts.TLS = &tls.Config{
|
||||
ClientCAs: clientCaCertPool,
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
Certificates: []tls.Certificate{serverCert},
|
||||
Rand: rand.Reader,
|
||||
}
|
||||
ts.StartTLS()
|
||||
|
||||
// Create new Helm home w/ test repo
|
||||
tmp, err = ioutil.TempDir("", "helm-push-test")
|
||||
Expect(err).To(Succeed())
|
||||
|
||||
// Add our helm repo to addon registry
|
||||
ds = NewRegistryDataStore(k8sClient)
|
||||
err = ds.AddRegistry(context.TODO(), Registry{
|
||||
Name: "helm-push-test",
|
||||
Helm: &HelmSource{
|
||||
URL: ts.URL,
|
||||
},
|
||||
})
|
||||
Expect(err).To(Succeed())
|
||||
|
||||
_ = os.Setenv("HELM_REPO_USERNAME", "myuser")
|
||||
_ = os.Setenv("HELM_REPO_PASSWORD", "mypass")
|
||||
_ = os.Setenv("HELM_REPO_CONTEXT_PATH", "/x/y/z")
|
||||
})
|
||||
|
||||
It("no cert provided", func() {
|
||||
_ = os.Unsetenv("HELM_REPO_CA_FILE")
|
||||
_ = os.Unsetenv("HELM_REPO_CERT_FILE")
|
||||
_ = os.Unsetenv("HELM_REPO_KEY_FILE")
|
||||
args := []string{testTarballPath, "helm-push-test"}
|
||||
err = setArgsAndRun(args)
|
||||
Expect(err).ShouldNot(Succeed(), "expected non nil error but got nil when run cmd without certificate option")
|
||||
})
|
||||
|
||||
It("with cert", func() {
|
||||
_ = os.Setenv("HELM_REPO_CA_FILE", testServerCAPath)
|
||||
_ = os.Setenv("HELM_REPO_CERT_FILE", testClientCertPath)
|
||||
_ = os.Setenv("HELM_REPO_KEY_FILE", testClientKeyPath)
|
||||
args := []string{testTarballPath, "helm-push-test"}
|
||||
err = setArgsAndRun(args)
|
||||
Expect(err).Should(Succeed())
|
||||
})
|
||||
})
|
||||
})
|
||||
BIN
pkg/addon/testdata/charts/sample-1.0.1.tgz
vendored
BIN
pkg/addon/testdata/charts/sample-1.0.1.tgz
vendored
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,36 +0,0 @@
|
||||
apiVersion: v1
|
||||
entries:
|
||||
fluxcd:
|
||||
- apiVersion: v2
|
||||
appVersion: 1.16.0
|
||||
description: A Helm chart for Kubernetes
|
||||
name: fluxcd
|
||||
type: application
|
||||
urls:
|
||||
- http://127.0.0.1:18083/multi/fluxcd-1.0.0.tgz
|
||||
version: 1.0.0
|
||||
annotations:
|
||||
system.vela: ">=1.3.0"
|
||||
system.kubernetes: ">=1.10.0"
|
||||
- apiVersion: v2
|
||||
appVersion: 1.16.0
|
||||
description: A Helm chart for Kubernetes
|
||||
name: fluxcd
|
||||
type: application
|
||||
urls:
|
||||
- http://127.0.0.1:18083/multi/fluxcd-2.0.0.tgz
|
||||
version: 2.0.0
|
||||
annotations:
|
||||
system.vela: ">=1.4.0"
|
||||
system.kubernetes: ">=1.20.0"
|
||||
fluxcd-no-requirements:
|
||||
- apiVersion: v2
|
||||
appVersion: 1.16.0
|
||||
description: A Helm chart for Kubernetes
|
||||
name: fluxcd
|
||||
type: application
|
||||
urls:
|
||||
- http://127.0.0.1:18083/multi/fluxcd-1.0.0.tgz
|
||||
version: 1.0.0
|
||||
annotations:
|
||||
generated: "2022-06-15T13:17:04.733573+08:00"
|
||||
15
pkg/addon/testdata/test-view/metadata.yaml
vendored
15
pkg/addon/testdata/test-view/metadata.yaml
vendored
@@ -1,15 +0,0 @@
|
||||
name: test-view
|
||||
version: 1.0.0
|
||||
description: test
|
||||
icon: https://www.terraform.io/assets/images/logo-text-8c3ba8a6.svg
|
||||
url: https://terraform.io/
|
||||
|
||||
tags: []
|
||||
|
||||
deployTo:
|
||||
controlPlane: true
|
||||
runtimeCluster: false
|
||||
|
||||
dependencies: []
|
||||
|
||||
invisible: false
|
||||
@@ -1,37 +0,0 @@
|
||||
apiVersion: "v1"
|
||||
kind: "ConfigMap"
|
||||
metadata:
|
||||
name: "cloud-resource-view"
|
||||
namespace: "vela-system"
|
||||
data:
|
||||
template: |
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
appName: string
|
||||
appNs: string
|
||||
}
|
||||
resources: ql.#ListResourcesInApp & {
|
||||
app: {
|
||||
name: parameter.appName
|
||||
namespace: parameter.appNs
|
||||
filter: {
|
||||
"apiVersion": "terraform.core.oam.dev/v1beta1"
|
||||
"kind": "Configuration"
|
||||
}
|
||||
withStatus: true
|
||||
}
|
||||
}
|
||||
status: {
|
||||
if resources.err == _|_ {
|
||||
"cloud-resources": [ for i, resource in resources.list {
|
||||
resource.object
|
||||
}]
|
||||
}
|
||||
if resources.err != _|_ {
|
||||
error: resources.err
|
||||
}
|
||||
}
|
||||
|
||||
75
pkg/addon/testdata/test-view/views/pod-view.cue
vendored
75
pkg/addon/testdata/test-view/views/pod-view.cue
vendored
@@ -1,75 +0,0 @@
|
||||
import (
|
||||
"vela/ql"
|
||||
)
|
||||
|
||||
parameter: {
|
||||
name: string
|
||||
namespace: string
|
||||
cluster: *"" | string
|
||||
}
|
||||
pod: ql.#Read & {
|
||||
value: {
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
eventList: ql.#SearchEvents & {
|
||||
value: {
|
||||
apiVersion: "v1"
|
||||
kind: "Pod"
|
||||
metadata: pod.value.metadata
|
||||
}
|
||||
cluster: parameter.cluster
|
||||
}
|
||||
podMetrics: ql.#Read & {
|
||||
cluster: parameter.cluster
|
||||
value: {
|
||||
apiVersion: "metrics.k8s.io/v1beta1"
|
||||
kind: "PodMetrics"
|
||||
metadata: {
|
||||
name: parameter.name
|
||||
namespace: parameter.namespace
|
||||
}
|
||||
}
|
||||
}
|
||||
status: {
|
||||
if pod.err == _|_ {
|
||||
containers: [ for container in pod.value.spec.containers {
|
||||
name: container.name
|
||||
image: container.image
|
||||
resources: {
|
||||
if container.resources.limits != _|_ {
|
||||
limits: container.resources.limits
|
||||
}
|
||||
if container.resources.requests != _|_ {
|
||||
requests: container.resources.requests
|
||||
}
|
||||
if podMetrics.err == _|_ {
|
||||
usage: {for containerUsage in podMetrics.value.containers {
|
||||
if containerUsage.name == container.name {
|
||||
cpu: containerUsage.usage.cpu
|
||||
memory: containerUsage.usage.memory
|
||||
}
|
||||
}}
|
||||
}
|
||||
}
|
||||
if pod.value.status.containerStatuses != _|_ {
|
||||
status: {for containerStatus in pod.value.status.containerStatuses if containerStatus.name == container.name {
|
||||
state: containerStatus.state
|
||||
restartCount: containerStatus.restartCount
|
||||
}}
|
||||
}
|
||||
}]
|
||||
if eventList.err == _|_ {
|
||||
events: eventList.list
|
||||
}
|
||||
}
|
||||
if pod.err != _|_ {
|
||||
error: pod.err
|
||||
}
|
||||
}
|
||||
30
pkg/addon/testdata/tls/client.crt
vendored
30
pkg/addon/testdata/tls/client.crt
vendored
@@ -1,30 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFHjCCAwagAwIBAgIUVh0GhVN5oZJUfbbKiS9XIH722WowDQYJKoZIhvcNAQEL
|
||||
BQAwTDELMAkGA1UEBhMCICAxCjAIBgNVBAgMASAxCjAIBgNVBAcMASAxCjAIBgNV
|
||||
BAoMASAxGTAXBgNVBAMMEEhFTE1DTElFTlRDRVJUQ0EwHhcNMjEwMTAyMDkwNTQ1
|
||||
WhcNMzAxMjMxMDkwNTQ1WjBGMQswCQYDVQQGEwIgIDEKMAgGA1UECAwBIDEKMAgG
|
||||
A1UEBwwBIDEKMAgGA1UECgwBIDETMBEGA1UEAwwKSEVMTUNMSUVOVDCCAiIwDQYJ
|
||||
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMYC80vkz8mK/cvzvr5x3Ua//2kAV2pd
|
||||
sJyA4ujFr6KRvqd1Hk9N6V5WbbE7VnYWQ51P5Gx40iv0lzHhzC93t5wHxjIOXYLE
|
||||
uZqpeJMJBSTJnHz12A6b9lAnhW3psFBfAU4lsi+u4zimLXJTQw+ONKWsyW2C2ZXs
|
||||
IVpNusg75exMUwFaklCxB0Ib+AH3nH0fs56J7GZwJNokftcB3Op1qx9XAIQAk0dJ
|
||||
PRnrzZBQ9xp/WHtNdRgTnvJcDab8noI4oeTrLAU3yAFEAHUUxMMPgdpEe61cLbHT
|
||||
xxATH70zf6v95KpCQN2LvdNsjgcUmPRjNy7pjL+0sSBhmBYHPVvpXnkZdbF2C804
|
||||
EYGIYrmNRXcSEOQxQOCSiYr9BSQUWK1wC0xRZGrAMQQ/fzda0lfYlkr3guq7DPG1
|
||||
2ZCNEc80vZ1YjRjApWQoA+xOOwujJYJLI3XFG+t0/w/sB5f4slXrKwBHP0BxSw4p
|
||||
I0ab0PeY9GmI5l704QmBgQF5u/mh7tdSR0najj6IkwEyG85UMufyUyaggQHvwTeN
|
||||
DLP2ItLyshyCA9JB/mnHoEbarUgsgV5/sPQqgMdqYUnPcInuQyz/sTVD7x8YOxI6
|
||||
xo0o+pnNuN9jMaT2pDQ2+IYzBQihdDNxgxPtS9aZyXE2yUcpiGFtBn4qWMKlOs5y
|
||||
1Mu0bXunR6hnAgMBAAEwDQYJKoZIhvcNAQELBQADggIBAKGvPoNmC0d3UwcRdS+x
|
||||
6MY4S2nryyclVmen5s9aSEkVqPoDSxH6O5L/1eOblj0BlS8K6budcgseAkJrvw8+
|
||||
ZYFXdKBpFninbHv4IySjWupE9rH+rSquNVQrZYK6ZHzfpW5dBfeHEJgyzJNRcu6i
|
||||
7ySUbBYraL7CHgJKNR2b38WrIGBKeYkkmb3gEIteq79XhZpSWLxc4OUArVNtzTed
|
||||
v+5oqZImmAvaCrlRRd7/aCkQFsNzbQ7AJfZnPNrZz7A4mkV1yVRFBRMrllJFc6mH
|
||||
kCv5Hm77GmVtXaZuYnQE0AqpkX8TLACDER+MfP8KwURje14nBqsng1kr4YOUUMyb
|
||||
SyVPKtM5b/CCGt3BhX80kyy7unfwK/avDuuFaRcq59zEvfD1XuWtMwc/xaw5gXDi
|
||||
vqo7jLEpFnEC7PdnU8hK8POZnJESdAG8aZGXDy+tPvYQ2DqEXjLc/7FXMhverbLV
|
||||
b6LuSOOrTff4HM5eQ517TVJNB+MmSosEOC2mH62lu7gEXpM45UI4UelmJTTP+7cy
|
||||
LbUaxjs/ff6kA1RhbQVWR0cZyw89Pj73mrbjg6knVKzIw8lU3pTQXhwaVbp8HIzT
|
||||
zN+i8h7W3WuSjwjx4tzmUcCobzjJFKZJbM54EaAXdgSj/x541o6BSFm/IsZ9a81j
|
||||
waDb9wYoG3nZtVb/OYDUFU7Z
|
||||
-----END CERTIFICATE-----
|
||||
52
pkg/addon/testdata/tls/client.key
vendored
52
pkg/addon/testdata/tls/client.key
vendored
@@ -1,52 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDGAvNL5M/Jiv3L
|
||||
876+cd1Gv/9pAFdqXbCcgOLoxa+ikb6ndR5PTeleVm2xO1Z2FkOdT+RseNIr9Jcx
|
||||
4cwvd7ecB8YyDl2CxLmaqXiTCQUkyZx89dgOm/ZQJ4Vt6bBQXwFOJbIvruM4pi1y
|
||||
U0MPjjSlrMltgtmV7CFaTbrIO+XsTFMBWpJQsQdCG/gB95x9H7OeiexmcCTaJH7X
|
||||
AdzqdasfVwCEAJNHST0Z682QUPcaf1h7TXUYE57yXA2m/J6COKHk6ywFN8gBRAB1
|
||||
FMTDD4HaRHutXC2x08cQEx+9M3+r/eSqQkDdi73TbI4HFJj0Yzcu6Yy/tLEgYZgW
|
||||
Bz1b6V55GXWxdgvNOBGBiGK5jUV3EhDkMUDgkomK/QUkFFitcAtMUWRqwDEEP383
|
||||
WtJX2JZK94LquwzxtdmQjRHPNL2dWI0YwKVkKAPsTjsLoyWCSyN1xRvrdP8P7AeX
|
||||
+LJV6ysARz9AcUsOKSNGm9D3mPRpiOZe9OEJgYEBebv5oe7XUkdJ2o4+iJMBMhvO
|
||||
VDLn8lMmoIEB78E3jQyz9iLS8rIcggPSQf5px6BG2q1ILIFef7D0KoDHamFJz3CJ
|
||||
7kMs/7E1Q+8fGDsSOsaNKPqZzbjfYzGk9qQ0NviGMwUIoXQzcYMT7UvWmclxNslH
|
||||
KYhhbQZ+KljCpTrOctTLtG17p0eoZwIDAQABAoICAHSyiHDSCSPepnTs0h2rPZ3U
|
||||
ydI4QUyOqueRjilhWIGXI6XNgG98m2zdwwgQ0IQH2xF7ZEQJcNQ28mSTjqLrC2sJ
|
||||
qeUWUkYfasOb3VPKnR1xNKjwusThZekXYavFbgPv+fT0gm9XwtJAHcijCYLBbIW3
|
||||
r366/0E8SOvPo6UeqAL7eG/z0Qd9TanIkgGWzMNxS4rD/m7g6NcnaxmMH4aOkquF
|
||||
uugQ7ru0ji4Yqq3DCd6z7pG8tKXb6nErj2A6wbA9cCxZ7TemCFm2mg5mjw/ms8DP
|
||||
W5RwHv4OseLnYm0/TJ8wovM02MW49ccE0y+ZFAvz7THYsvrIoxtSaS+SVLc2clYh
|
||||
2L+mOo7KpBX9zL2JY8l2wMUcmukr5zKs7gvqN/lAZvR6bafYiBN5pTzWvMWUFwCU
|
||||
p1EaSIVeccduhTf72tRzpo2W5IDH2XY9209P1ZBzuGgKl+McPcwnx2KnAh91NdtP
|
||||
ZfN+6cbRDrQY3JsJe8MeYyvpIkHaRXl3sf6rO0VFT4brymWhejzMBko7Qu1EXfVj
|
||||
8pyAgepE9DqybS0HG5GYm1Mj6VotHNDQXwvLWZgjFsCmaXuwpRZIEUrqzoZaATS4
|
||||
qJOTIwdfahruz+3qD+2jiaFPScaLIXInijAnkRco0Xkp49+/FlObkN/VghCAb1XI
|
||||
wL/38/Ecei2sJGzCT5UBAoIBAQD4scFUejzhOUPafImJRWSMM73QkZU/hE49na6l
|
||||
XMvFOC+6cRQeN3wMezguAjnetqEBrmTBkax/gL0nsuXYmEQmd4r+GAx5FUHXQIE2
|
||||
LzDulvMjVeVSA6vpCtbjC7UoAs5J8B18pr5EfoFTfCU5d0BsU0XBBPwdeRUyP4pB
|
||||
e9JXvPWOYzpzBC8d5eMsuRuj1M78BUJJmaxDLdGcBLER3UrTnaaurY+kD+/ryxLx
|
||||
sT9sWHW0i8jZB9PaDVY8Nvvu0gZsD/gH2U56o6UFotZjQ0P90v7HLTTCvncZGNCH
|
||||
PB70mEd7IVGW/FoDRKa2gQ+19Q41VspMOho2wum7EGVbxSqDAoIBAQDL1AwidJRV
|
||||
qLoqzkBpleY7I2GR5BFgfHHZswMqPS8iBXPAgdoXXtWaWs6huGMB9LyMJ2ot6Vm9
|
||||
THw49XTpfUKeEwAYwVx6y3h3tfJHY4ugXGR+kOi75bOCwHMmX/UFnSmu00DUNY9Y
|
||||
F+eXi2kiCsHcDkIOOYONIQgVJLDuzlLQaFAWLktFEXu23izkylaLgLd/UEQVF1p1
|
||||
/yAHIs1UXeGqtTRGxbrP2HdL44GD805lHbf1JcM4Q5Gn7BcWn+ivQewS2jF8MGH1
|
||||
QbK8ncbZZmQfOUnCKXAmi/IyVojLGVWkT1GsTNC1qfiKcqELFsMrgoykeVKJcNfC
|
||||
Ci4THpDXhHVNAoIBABvdVssPUyjtEKQ3VfWyd7yZw4fN+AoA2f9fXoUaq54yWG6s
|
||||
YtOr5dNELxxAlZlVnx6gGpvxpYE3vHnpOoWVMfWZaVJlAWjDr/fdO10F1pa1BRMN
|
||||
eb9BuA5Jb6BK3IZaIiD4rWUdDa6A+h6Ph2Az81zvy53/3/uxaGWT5vrFU+EOw/ir
|
||||
N45RhrHz4wtMxkMKAhMMx8uVU07HoHe5stlMkSi6vkVOHw0D2B70RvAbqv6Jvs52
|
||||
5w8iKGODIQloI7wzfhK3i1PdzkRBd6j1AM5oaALVlERe1U2Ip7GBLUQpwVIoicHL
|
||||
Dug66B77ny5NsaPyjB//1HTMAcnm9udFxAWPRt8CggEBAKt5QpQh+0Bs5+FnDm1F
|
||||
PCD4TPcNJUlEqAr7PGhmfKZka9LB6xXKJGzsg/UtR623lH9cEUl6jJJiLAdHCAn9
|
||||
5PNTDLvGv+RWFIyxNpe0ORy5XZnUktawEWqoOLdJ9rm4U/7NnjZosKTtx1mIYPPQ
|
||||
lPJp1ExfOjqaVVBkQ61DSgwmFWnznEMIyEk5dA8t4c0OhlDG19/ee63U6b7XGmIl
|
||||
cNnKA6aeZeDBPOtNBAJbx9HtRHsqP6evwHPCfFH+SSRXkyDxCrxtf5tyn8lp+oWe
|
||||
TBCwg0qizcS/6wtKHV6ve4r1Z8JKBTMvQPZIJQ9NIPgTpfogTr1tfzWwlr5i8ns8
|
||||
5ekCggEBAIKMkEtdRWR1dlWByh82Dro5fL/mTMGgF4BJJyiuuKpdzInmhWaMhhSV
|
||||
BL7gnFuxWkIn1h7RhgiVNiyMF1toQOdvF5ipuMWaCa3cZRIUAAgKkJxl1PfqDkMr
|
||||
koEHbLz726gry3iQqyraDFrLpF4aLy4QaofUDU5HIsqbm5EecmQJ2tRzltGT5idL
|
||||
aFVcOXBIqd/isRSGyGdvKiTBnI8/qCXHBmWSuC/2wUBsqfcsktLGOSLvmG+FSJzF
|
||||
wDH7U1GFYnTG34IlZnjaJEoh+5xy6rHVDEW7aX8Jy+kr/Zc8qSWH+73y2Hs2/T5i
|
||||
vLWbseIYBACDyFxccjU78/a70FZmSmQ=
|
||||
-----END PRIVATE KEY-----
|
||||
32
pkg/addon/testdata/tls/client_ca.crt
vendored
32
pkg/addon/testdata/tls/client_ca.crt
vendored
@@ -1,32 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFeTCCA2GgAwIBAgIUR/7hT0+Kju66vSp9UuBk/c0vdoAwDQYJKoZIhvcNAQEL
|
||||
BQAwTDELMAkGA1UEBhMCICAxCjAIBgNVBAgMASAxCjAIBgNVBAcMASAxCjAIBgNV
|
||||
BAoMASAxGTAXBgNVBAMMEEhFTE1DTElFTlRDRVJUQ0EwHhcNMjEwMTAyMDkwNTQ1
|
||||
WhcNMzAxMjMxMDkwNTQ1WjBMMQswCQYDVQQGEwIgIDEKMAgGA1UECAwBIDEKMAgG
|
||||
A1UEBwwBIDEKMAgGA1UECgwBIDEZMBcGA1UEAwwQSEVMTUNMSUVOVENFUlRDQTCC
|
||||
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMzrmoo1onmXMzRCbAzt0j1I
|
||||
HFWQfW8T7kuBwoo5tO5fHKoWOg6ztnsX4TjXA2q3NXPCUFcuzp3L1xmgwVUm6iBc
|
||||
TDMAUmbOVFXQWQWUSi9YGMkTvQrjqyO+eY1tfnh6ZxiF29T92XDVAH8O9mHwsfMQ
|
||||
8g3Bn6of86o8cchQ2kM1n9kKs58MdWaKlFQAOnKDdDX8C9E39GcWrtcAASDOHAOm
|
||||
UYMhIAY3fw/yuuSgxDRcuYuN8jp6cNYgNoiMidFrgDdkeky+Y2n1RQMWsT2GoC2S
|
||||
6ZV1//7Awnbny8MCdT74LTQ9bN2j/4KfwLTwE5EwCOmf0MrnYeVSK6fIWFGPzJhs
|
||||
eeGwykTgPazkcCJkSIQGQkgSQON7U1XdsiCj5r4tUDfSXSteAPad0dYvEIwBUkpd
|
||||
i+MaPE1oC4D6I3ye7LkhfBbzwzx7vYRjDh/fxA6ZH/hRkE+JW7tLEUDM6EXeMhKL
|
||||
JoUMYVKn5gypbpwItmbVyfhjlh31e+11dz0xk+2iBRbL3t2b67mjvao9LJl+PLP/
|
||||
Pk9NbX8bAGtsMFKSyHAumUzy5CDYhK7dVPPdUvKTiH57kExScsIZe0+zuzcT/sx1
|
||||
z57yb8xPh+IoN8HPJYz6wpFEn00rmUprELUjZTtHgZE7st+GIP+oEj31BgRmrFIy
|
||||
mLIjgblZxoFTCWFe6trtAgMBAAGjUzBRMB0GA1UdDgQWBBQT8nXy1NvG/E8KvGD/
|
||||
aoadNdL+BjAfBgNVHSMEGDAWgBQT8nXy1NvG/E8KvGD/aoadNdL+BjAPBgNVHRMB
|
||||
Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQB8nYSII0pXbhld3pOIarYOiYTo
|
||||
5aOIOZaUHxgJk9EqNMkZUDX0EeKnFSwigtERfUza4APCM36+m3m58Rq7hzFCdoit
|
||||
/sTuH0ez3Cne8H3tnr8aaXZRU+As857PS5xE6v29NwwRBGdSensCEk+IgZxkxjnS
|
||||
6p0oSZza0+yrCwQOJJbdSQ/qJHwPdN+oTuW0yMbt83AR1ycUkic5LcXneieaTdUr
|
||||
PGbzXD5tTC7thl+0h/EtoqfFdAiFDSR4B0lPdOJw64xhDMk952FB2MSFd0HLZNbc
|
||||
dwYEjCYMqiDXCpXeL4vvPyxN8bzQrCpeSc2hdV+55ejMdaJMBGXNCfdROx8LhoSi
|
||||
0G63F1Bex0R5vpUHlCALvldg0B5ZhLJ3t+O8O7rj2fTlhfNqSa6b7tSn5UlkWp9F
|
||||
/AZxzENo25LVi8/7A8x/Defdl2Dq4JHaEtdHpROfLPPYe0H8zSHTTOnUlrKjNSSK
|
||||
NIZOETD4hvxKg2ZcZZUyt5tSo31yzFJS8tF8HqE6RK/dt407fM53rTOuY5PEa1f0
|
||||
/RwVf7b2hjgkTf7+uFeslbBZxdkO1CzE44XBmWaFf4kZFVdl06eQ8uE70MfIkmb5
|
||||
VDcLz6zf6YE4jm7nUMowZ93/C+OrdUAq6qZOFgcwfrdMr1MJ/z82hCIfTRRSyM57
|
||||
RfQSytf5T17r5K+yWg==
|
||||
-----END CERTIFICATE-----
|
||||
30
pkg/addon/testdata/tls/server.crt
vendored
30
pkg/addon/testdata/tls/server.crt
vendored
@@ -1,30 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFMzCCAxugAwIBAgIUQGMSwNP26VEf81fG96Gw+p8XDHkwDQYJKoZIhvcNAQEL
|
||||
BQAwTDELMAkGA1UEBhMCICAxCjAIBgNVBAgMASAxCjAIBgNVBAcMASAxCjAIBgNV
|
||||
BAoMASAxGTAXBgNVBAMMEEhFTE1TRVJWRVJDRVJUQ0EwHhcNMjEwMTAyMDkwNTQz
|
||||
WhcNMzAxMjMxMDkwNTQzWjBGMQswCQYDVQQGEwIgIDEKMAgGA1UECAwBIDEKMAgG
|
||||
A1UEBwwBIDEKMAgGA1UECgwBIDETMBEGA1UEAwwKSEVMTVNFUlZFUjCCAiIwDQYJ
|
||||
KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPz8Vr/uPHsmAevay7q/myV4tDrjuIj
|
||||
xjaIwLTlyngq6tWCFr7zXczYJXYY83rvkTVN0oBMkqev7ZlRy1Q5A8FuTEeKnMuv
|
||||
kRYEn5I8EF2pUP7rY+Gbn6dS63Jh7+wj2g3HwJ+9RzAnzpvNfh6ZbGxZ2I7ALTWU
|
||||
KUVpJljkDJO6+HyON7geh6R/mFDsq3v6n+giywr3pp37hqDueKYoyBt7WJ+2D2IH
|
||||
tlxS5eRDoygpZAiiXhSRoGGZ2oS2jevVhnTkHqzS21zNd11WiXtpe0Yu78+cwiqB
|
||||
iON7Zy5oWVVF+Og1buLkPslVgxg5BJSbfcs5D6cbVreoJFFM9uaJGhjE1PTlci8C
|
||||
wYJGgdKULP1bcHpbdnz2G8ZIz0xuOwhlThWHdEzh++Vst/UlpRGRkuLxEC34jsJw
|
||||
XoRt0WMNeakYQzIbWJtkHCA1CCMrfm+Rzuxh+KfwVHMz9J8fv6thdXQcV/tqMKbN
|
||||
zzEHi3/2lUJeMvS2bibXeWHfiEOlXzIwTPJs4cwwi9PkhfGXWz6XwgIaMfsS8fOS
|
||||
l5m5s8vFbEHTh3HUQ1J7njc6AFslv5c/5IYeG+sa5ObWsllYt1pTWVTW9sZsHn8s
|
||||
kGcjxA3SeH/8tjeAMXbnHIEca7Q9UmTlDilb2BL3TreVdckZUIbIvwmftB+Xh5Mt
|
||||
XQQhBTZZhnAzAgMBAAGjEzARMA8GA1UdEQQIMAaHBH8AAAEwDQYJKoZIhvcNAQEL
|
||||
BQADggIBAE1sejJ6SWRzL8udWxfITdqgqlw+Ci8+K2BYwgBd5vJun+us0oommzl6
|
||||
ogkJyeytdRx1RdnqQi2Gucz4+HS2FJsXsWjNc7S7TCKj7QGt8O6WQQGPxYD6Ypn8
|
||||
2q8HHjuPS3aa3w1sID1DxDBjWnDFnz27bF1Fhb7eq51oRJVyXIb8+ip8uoxF0lkR
|
||||
1ges0h3SSYRz7gvu3t4dDeUiTyttV0yWDk7yWOEZyUxRqYgKJXmu2nFkeOnyiof5
|
||||
IyjhdQR4XrR6mWZChJT3WtDNGvTTX1uUfMP35fc4YiENzNUzqGcbBVjaJNl1HzlE
|
||||
Xzi6tkZFnF+T0I7Av/sIlsCL7L/nqqRDXb7yEGG+bY2N9K1Wwkn2WrdrApwbE32N
|
||||
jV/3wY6oOtgmDaWoc4FOgzI250Y0SyVaAQlN+LvR7EPLJrGA+/6LaCiOMkaDT/JZ
|
||||
0YtIynvjHVL9gThtrWU/BBe8OzN3tXaxJNMdY2OxSyJEYBEyHDBNluIk1pmJcsRA
|
||||
KQ5p5vS3sBj9kZAeka0W59emv3n08/IS1svAGxlJa+gSFJTBe9XQJcD8f0kSy+8x
|
||||
4OAMfFVYrKsQryyS7fRepCTy/niAETp8w/n21cXMCkwMRAFPI9DXx8vEMubDt9dx
|
||||
NWKOk0Juc2XKIL3Z+IUqUiRopJ7iXyfwsb+8ctcyNcnYT8iaF7f/
|
||||
-----END CERTIFICATE-----
|
||||
52
pkg/addon/testdata/tls/server.key
vendored
52
pkg/addon/testdata/tls/server.key
vendored
@@ -1,52 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDD8/Fa/7jx7JgH
|
||||
r2su6v5sleLQ647iI8Y2iMC05cp4KurVgha+813M2CV2GPN675E1TdKATJKnr+2Z
|
||||
UctUOQPBbkxHipzLr5EWBJ+SPBBdqVD+62Phm5+nUutyYe/sI9oNx8CfvUcwJ86b
|
||||
zX4emWxsWdiOwC01lClFaSZY5AyTuvh8jje4Hoekf5hQ7Kt7+p/oIssK96ad+4ag
|
||||
7nimKMgbe1iftg9iB7ZcUuXkQ6MoKWQIol4UkaBhmdqEto3r1YZ05B6s0ttczXdd
|
||||
Vol7aXtGLu/PnMIqgYjje2cuaFlVRfjoNW7i5D7JVYMYOQSUm33LOQ+nG1a3qCRR
|
||||
TPbmiRoYxNT05XIvAsGCRoHSlCz9W3B6W3Z89hvGSM9MbjsIZU4Vh3RM4fvlbLf1
|
||||
JaURkZLi8RAt+I7CcF6EbdFjDXmpGEMyG1ibZBwgNQgjK35vkc7sYfin8FRzM/Sf
|
||||
H7+rYXV0HFf7ajCmzc8xB4t/9pVCXjL0tm4m13lh34hDpV8yMEzybOHMMIvT5IXx
|
||||
l1s+l8ICGjH7EvHzkpeZubPLxWxB04dx1ENSe543OgBbJb+XP+SGHhvrGuTm1rJZ
|
||||
WLdaU1lU1vbGbB5/LJBnI8QN0nh//LY3gDF25xyBHGu0PVJk5Q4pW9gS9063lXXJ
|
||||
GVCGyL8Jn7Qfl4eTLV0EIQU2WYZwMwIDAQABAoICAHcpa8a46BFGnZVe2cFoalxC
|
||||
MfJ2rSdcNfeH5hib/Spifvhj6c0pVgtyDiXpOneyJA3US4R2DGEpHUY1dX68RUpl
|
||||
9sEyy/MZyxMmsJtPJ2ytwHGlV9Ikv0wTotamNC7YBoyGwt7hTd889enNZzrYdhTV
|
||||
9lmpCFUiyo5JSWaZGATmmKG2IrA28KnaZhggNJBqcr/KGMuMmqhMAyzumDQDbN05
|
||||
f0Vwg55LrlwqlV7guuF7eje99ZRwkqWH2FkIYvndmayP5Q+YEoo28LW0IFsKZErj
|
||||
1DXe0DzlFQexTaftERZIPPuJMuuLfZsWA2jBk8WDYVYqVxh6CZwaBivir+q1yUXi
|
||||
SzQB8XBfttpHpfXS6jQ9N18NbC/QvfyP67qDpK4f29sOLhfshIldxrPqPLQRwD6q
|
||||
oQJ0UhhAjEcjeGITFScfGrt5HYqBR8R8DhcuoklseqBewOKYhOaV6ibiHz+G39Df
|
||||
3hJAfFZLqXybvOxrx1d7Dr69Gr/9tws7rmK8hTPoIXE+7+jqLZ1fRY+3CorASbXW
|
||||
JNZeR9VLAruFwfIc6NphftdsUf2MjwuafkLptafAWUFqhm9lpomNwBC3EgBCYg9b
|
||||
4U57ASFO3kA858d6OKMqxh8+Ja6gFTEtiXxu2e+TAn4nz+HV442URMgU88wH1Fv/
|
||||
pa29LdmJ+F9q4B2YPq+BAoIBAQDjtCz4CIILmjXghQ/m0lzPrgfc7uF4/dwBGkP+
|
||||
HW+UQlyvvSgBHcsOG8DH4J1pF5yN3Q/Hh2pvz/7NcIu+5+gEpgkNA5sJtYIkF2tI
|
||||
QnKp7zzfoODLcRI5sQKZxWUenLLaJ5UlRNyjtGGuZQnZ5fmuT7yzE4gZJwe8dMqS
|
||||
Qp/gVdFB8GcXo1tEhOsKJYNxqHfeiB73fUOoGX3ovuNtumiw6/6M5rAx4hQXrpR+
|
||||
p4jiida+cXPqYxrazRLpjvZOuQXwB6+6aSqMAj0Xmyq2HVPkxZjRz5yBmH99Lgr6
|
||||
vGkNjcgKyzdWP8wTG/CUyzAX4+NEgrfdMZcrSIz2DflTRaohAoIBAQDcTbEXUqoy
|
||||
Kgw2TFMb8JtvxMidXf0EMLo7u2OuPEomz8+lSLLbudL6NhYriDZzm69alNzrt1et
|
||||
R587YQytI+l3MOvuc8+HmC6ouP5PRGpEND0FikU25xwz9GsFw8sFJbWbw6zsbYnN
|
||||
MolTJ1wRH8AYqlWF/AV6H62IzNnU5P4+ThgbtkL5sxhiHVIqHsMbyykIz6o3MOJP
|
||||
FWcvkIkg9fRAsxu+1DAdOr4IMJISEP5opy1M4nqA4KnSfhX+f7CLZqCYibYl1Xiz
|
||||
hSoQ1fvUA7o1qMrzKJbtGlhsfcsFAiOVga7bxU2R1rFJyKXgfhYwYnec3k12nBXU
|
||||
308abAbFClfTAoIBAQCXKX6M7oD+mNJZiZxD3LUWfe7kYYU3YDfUV455vSrcnq2P
|
||||
USCklRW++Pei+V8mbDFXEEEwcZpcPhVmZueuxZ+Grn7lr9YVvPR3Z0CmSM58N8EO
|
||||
qGtzQ04ZFISodp2pk9c78fkWM7/RwabzMko26HA3ouGfdEDuibWeC16LeEVQlUgE
|
||||
4UZfL+gf9alfJAY9xtxE09LS88qdZsbqYwbySkTD5vcmrOKdSvuRuSkFZ8z8rwrr
|
||||
hL+yAzbJuEhs2qZzHmttrHyhYL2JEtdhu3XATnnqLq9D4fKBKi7AeHd7eua2w7/g
|
||||
QoYq8NFWgj7VWIpF4dh3G9xZsFktt800b5RsDpxhAoIBAAqvrhZuiRjz1zHPE/z3
|
||||
9+I9Dmorw/kvD+mT1mr+O66USANBeoOUCPrgIsUrz1BeTew76ld4xkT+g2fS9lVz
|
||||
t4BznA4uCfQO2ryOdK+NpwX17rvVEDRwk3qlsYdPDwsJ4DxVCo9RZOzSNb0V3K5r
|
||||
9tp7cLiWGAHrhXRsU2izTu3gxeSaO7d3C4i+2Vx3r4kqmqv1vtD8iw3BAQdaoHw7
|
||||
0gRNa9we2NKiJdOp33wG3QBgk572IXEc9L/kI9b7hKnOaZ3cmDxPlZJHtFmqt5N6
|
||||
Ns8hh+6xmliX/ZANrgppJya6aqv4byHS4zisBffUxejE7f5q/iDxw1FXH7QtZ0qp
|
||||
jMcCggEBAIgJy5OX5leqQpOqx8lzRq1t0nJhIeLcDFkooWrMyyfrZAFaaqgP7jkX
|
||||
iR31M+h9w57aYNwK3nXLg1b9GxCxs6WIgJpnM8UW1uQy8TBn6TMEEAyhnmjhMg6K
|
||||
pz3o1gTJ+2SVQ6uNRrk9SL8DGDvUhgY+VuuuCpbLI1S5e/ryUpvsNG7ucs2K19nT
|
||||
7l0fT30KspD1yTzQvBH9uh/opZWEYowFziaBsAVcYis+TP8bBLA8MurEECw3ztcV
|
||||
/sQa5pD7wQfRs0MUL10wgcj+FbDiFTcxgCpfu2WHnstY2CGleBegrqJ/Ky4c4JQa
|
||||
EzEE4ZKHWvLxZ2aFpwgVVBgVv0q7xbk=
|
||||
-----END PRIVATE KEY-----
|
||||
32
pkg/addon/testdata/tls/server_ca.crt
vendored
32
pkg/addon/testdata/tls/server_ca.crt
vendored
@@ -1,32 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFeTCCA2GgAwIBAgIUEUxeJXnV2hjeuSvl99tONAWFtPEwDQYJKoZIhvcNAQEL
|
||||
BQAwTDELMAkGA1UEBhMCICAxCjAIBgNVBAgMASAxCjAIBgNVBAcMASAxCjAIBgNV
|
||||
BAoMASAxGTAXBgNVBAMMEEhFTE1TRVJWRVJDRVJUQ0EwHhcNMjEwMTAyMDkwNTQw
|
||||
WhcNMzAxMjMxMDkwNTQwWjBMMQswCQYDVQQGEwIgIDEKMAgGA1UECAwBIDEKMAgG
|
||||
A1UEBwwBIDEKMAgGA1UECgwBIDEZMBcGA1UEAwwQSEVMTVNFUlZFUkNFUlRDQTCC
|
||||
AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMD+TGmj+RveoUTh3Kjym+Fe
|
||||
aI5gJIRHj76/bSL0n6oApXeHV7c576NtihDWLq9CPiGAoYo38I4AKO8nH35ifDl5
|
||||
uPeaqoczbXc7Jr1liLfq7uQ/ZpPK4LvnmkeWJwb/iFZc1lPC1KGR76Sf5NVXDHfp
|
||||
xuGau6ExCah+ng3NbpvUcQ+fLPJ2OuS/hVkQNO+GqALYxiFObv0VyMSpg+WKh7p7
|
||||
AioidJPTLQa3a1NK09SYZD4kjAxErIxoX2xTFcsPcS4fuoTgbvLHubT7mOamTD6+
|
||||
E1c/1EzcyzLuh2BHqcjkzQhWVMa8VX2mjPGqTdykZYrbsp9sTInqytWxp47dcZhw
|
||||
fUE7RikEPj33Oj5AJ9DSxaka24tZstraaaxF0VSgegzIPu37c762n2x3luX3Iwsg
|
||||
6yodhAYtnl+pVvjmqbOJ7eEfAIPU44cHDvyHmPIBFspmBIP/NqgrD548rgEC5Jrl
|
||||
X/DKsOJYln7Czf5RumRTlFGea2A3oYBizhcLOMxv0BalpWmpNS14iKwN3h1KXDFK
|
||||
inPvnknQTveKQ/ZkvayDJoc5l49W2Igz5uM0jwCV7/n8yI/l9N1DRUrMiOdpLWPA
|
||||
n6G6PC91JG6BoHFOKAzxJru19gq1wi7knZF/3EinqRrUZqt2AUT5EM0MPhx7G7Dl
|
||||
7uAsZAMXVNDHbjrEpiZPAgMBAAGjUzBRMB0GA1UdDgQWBBRJ/z9FE6IUNCxTsjCZ
|
||||
vmM36ruK4TAfBgNVHSMEGDAWgBRJ/z9FE6IUNCxTsjCZvmM36ruK4TAPBgNVHRMB
|
||||
Af8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4ICAQCQzHHn8LAGIRHEng/zFrL39Izv
|
||||
8/LOWmPpAX9uJU1sxyafw7MmappBaK6nRdDble9zC66UQKYXOvuXS7O6aIh9MWv6
|
||||
42ThvFaNWhNRa2bZyMWRlGzT3bOKw1G8TM4TYRA73jm6gfGADPi0po3vGI9PUlsT
|
||||
lQ5yuR5Vno7VorZ0kGOAu0skH/7X8UIhhIZONCpWnPMoBsQS+iHgjHjqBF1IkY+3
|
||||
pPBCe+WPj4NqE3Roz60dabO29PiPEjITrFWyuSFPtyvA9XReJIc758SznheOn0X9
|
||||
pfzvU9MQeqNwtVx7s7mkcB60TX+w3Ey2auKLulG44gEt1rvbjs/n/isJ8CfAAI23
|
||||
S0wJvPcvc1iZ5QiftXiYIP7t8TqVKVItt6h+vyHsAkUZv/CGC3SGXhxva//3sbbT
|
||||
gRiBxci6dNzGO5a0Br1z7MNvaRSMRGqog2szX2Jkx2WhxLtuv+jd8IzJcrmb5X7v
|
||||
VmSFGdklIxeGG/y95d+VgOl9WURvQi+VuiOIouvG0TG7KNnZkp6jF7vMwp206CjB
|
||||
f38ReS5TANI1QTZbY5HC/HDl1KIHE9II7KKQJBxLsOlUgoZnGtWJviUeq8JH0pCM
|
||||
YYGU0aKWrTRqexl/kA8P8R+nmnGys3iVdOUMSp38nOrkJ8GLnDOYVB5Z7E5J8cis
|
||||
6IJa1euccl1ArgxBbg==
|
||||
-----END CERTIFICATE-----
|
||||
@@ -48,9 +48,6 @@ type InstallPackage struct {
|
||||
// Definitions and CUEDefinitions are converted as OAM X-Definitions, they will only in control plane cluster
|
||||
Definitions []ElementFile `json:"definitions"`
|
||||
CUEDefinitions []ElementFile `json:"CUEDefinitions"`
|
||||
// YAMLViews and CUEViews are the instances of velaql, they will only in control plane cluster
|
||||
YAMLViews []ElementFile `json:"YAMLViews"`
|
||||
CUEViews []ElementFile `json:"CUEViews"`
|
||||
// DefSchemas are UI schemas read by VelaUX, it will only be installed in control plane clusters
|
||||
DefSchemas []ElementFile `json:"defSchemas,omitempty"`
|
||||
|
||||
|
||||
@@ -19,15 +19,8 @@ package addon
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
errors "github.com/pkg/errors"
|
||||
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
@@ -243,144 +236,3 @@ type InstallOption func(installer *Installer)
|
||||
func SkipValidateVersion(installer *Installer) {
|
||||
installer.skipVersionValidate = true
|
||||
}
|
||||
|
||||
// IsAddonDir validates an addon directory.
|
||||
// It checks required files like metadata.yaml and template.yaml
|
||||
func IsAddonDir(dirName string) (bool, error) {
|
||||
if fi, err := os.Stat(dirName); err != nil {
|
||||
return false, err
|
||||
} else if !fi.IsDir() {
|
||||
return false, errors.Errorf("%q is not a directory", dirName)
|
||||
}
|
||||
|
||||
// Load metadata.yaml
|
||||
metadataYaml := filepath.Join(dirName, MetadataFileName)
|
||||
if _, err := os.Stat(metadataYaml); os.IsNotExist(err) {
|
||||
return false, errors.Errorf("no %s exists in directory %q", MetadataFileName, dirName)
|
||||
}
|
||||
metadataYamlContent, err := ioutil.ReadFile(filepath.Clean(metadataYaml))
|
||||
if err != nil {
|
||||
return false, errors.Errorf("cannot read %s in directory %q", MetadataFileName, dirName)
|
||||
}
|
||||
|
||||
// Check metadata.yaml contents
|
||||
metadataContent := new(Meta)
|
||||
if err := yaml.Unmarshal(metadataYamlContent, &metadataContent); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if metadataContent == nil {
|
||||
return false, errors.Errorf("metadata (%s) missing", MetadataFileName)
|
||||
}
|
||||
if metadataContent.Name == "" {
|
||||
return false, errors.Errorf("addon name is empty")
|
||||
}
|
||||
if metadataContent.Version == "" {
|
||||
return false, errors.Errorf("addon version is empty")
|
||||
}
|
||||
|
||||
// Load template.yaml
|
||||
templateYaml := filepath.Join(dirName, TemplateFileName)
|
||||
if _, err := os.Stat(templateYaml); os.IsNotExist(err) {
|
||||
return false, errors.Errorf("no %s exists in directory %q", TemplateFileName, dirName)
|
||||
}
|
||||
templateYamlContent, err := ioutil.ReadFile(filepath.Clean(templateYaml))
|
||||
if err != nil {
|
||||
return false, errors.Errorf("cannot read %s in directory %q", TemplateFileName, dirName)
|
||||
}
|
||||
|
||||
// Check template.yaml contents
|
||||
templateContent := new(v1beta1.Application)
|
||||
if err := yaml.Unmarshal(templateYamlContent, &templateContent); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if templateContent == nil {
|
||||
return false, errors.Errorf("chart metadata (%s) missing", TemplateFileName)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// MakeChartCompatible makes an addon directory compatible with Helm Charts.
|
||||
// It essentially creates a Chart.yaml file in it (if it doesn't already have one).
|
||||
// If overwrite is true, a Chart.yaml will always be created.
|
||||
func MakeChartCompatible(addonDir string, overwrite bool) error {
|
||||
// Check if it is an addon dir
|
||||
isAddonDir, err := IsAddonDir(addonDir)
|
||||
if !isAddonDir {
|
||||
return fmt.Errorf("%s is not an addon dir: %w", addonDir, err)
|
||||
}
|
||||
|
||||
// Check if the addon dir has valid Chart.yaml in it.
|
||||
// No need to handle error here.
|
||||
// If it doesn't contain a valid Chart.yaml (thus errors), we will create it later.
|
||||
isChartDir, _ := chartutil.IsChartDir(addonDir)
|
||||
|
||||
// Only when it is already a Helm Chart, and we don't want to overwrite Chart.yaml,
|
||||
// we do nothing.
|
||||
if isChartDir && !overwrite {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creating Chart.yaml.
|
||||
chartMeta, err := generateChartMetadata(addonDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = chartutil.SaveChartfile(filepath.Join(addonDir, chartutil.ChartfileName), chartMeta)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// generateChartMetadata generates a Chart.yaml file (chart.Metadata) from an addon metadata file (metadata.yaml).
|
||||
// It is mostly used to package an addon into a Helm Chart.
|
||||
func generateChartMetadata(addonDirPath string) (*chart.Metadata, error) {
|
||||
// Load addon metadata.yaml
|
||||
meta := &Meta{}
|
||||
metaData, err := ioutil.ReadFile(filepath.Clean(filepath.Join(addonDirPath, MetadataFileName)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = yaml.Unmarshal(metaData, meta)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Generate Chart.yaml from metadata.yaml
|
||||
chartMeta := &chart.Metadata{
|
||||
Name: meta.Name,
|
||||
Description: meta.Description,
|
||||
// Define Vela addon's type to be library in order to prevent installation of a common chart.
|
||||
// Please refer to https://helm.sh/docs/topics/library_charts/
|
||||
Type: "library",
|
||||
Version: meta.Version,
|
||||
AppVersion: meta.Version,
|
||||
APIVersion: chart.APIVersionV2,
|
||||
Icon: meta.Icon,
|
||||
Home: meta.URL,
|
||||
Keywords: meta.Tags,
|
||||
}
|
||||
annotation := generateAnnotation(meta)
|
||||
if len(annotation) != 0 {
|
||||
chartMeta.Annotations = annotation
|
||||
}
|
||||
return chartMeta, nil
|
||||
}
|
||||
|
||||
// generateAnnotation generate addon annotation info for chart.yaml, will recorded in index.yaml in helm repo
|
||||
func generateAnnotation(meta *Meta) map[string]string {
|
||||
res := map[string]string{}
|
||||
if meta.SystemRequirements != nil {
|
||||
if len(meta.SystemRequirements.VelaVersion) != 0 {
|
||||
res[velaSystemRequirement] = meta.SystemRequirements.VelaVersion
|
||||
}
|
||||
if len(meta.SystemRequirements.KubernetesVersion) != 0 {
|
||||
res[kubernetesSystemRequirement] = meta.SystemRequirements.KubernetesVersion
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -18,13 +18,9 @@ package addon
|
||||
|
||||
import (
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"helm.sh/helm/v3/pkg/chartutil"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
@@ -158,119 +154,6 @@ func TestUsingAddonInfo(t *testing.T) {
|
||||
assert.Equal(t, true, strings.Contains(res, "Please delete them before disabling the addon"))
|
||||
}
|
||||
|
||||
func TestIsAddonDir(t *testing.T) {
|
||||
var isAddonDir bool
|
||||
var err error
|
||||
var meta *Meta
|
||||
var metaYaml []byte
|
||||
|
||||
// Non-existent dir
|
||||
isAddonDir, err = IsAddonDir("non-existent-dir")
|
||||
assert.Equal(t, isAddonDir, false)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Not a directory (a file)
|
||||
isAddonDir, err = IsAddonDir(filepath.Join("testdata", "local", "metadata.yaml"))
|
||||
assert.Equal(t, isAddonDir, false)
|
||||
assert.Contains(t, err.Error(), "not a directory")
|
||||
|
||||
// No metadata.yaml
|
||||
isAddonDir, err = IsAddonDir(".")
|
||||
assert.Equal(t, isAddonDir, false)
|
||||
assert.Contains(t, err.Error(), "exists in directory")
|
||||
|
||||
// Empty metadata.yaml
|
||||
err = os.MkdirAll(filepath.Join("testdata", "testaddon"), 0700)
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
os.RemoveAll(filepath.Join("testdata", "testaddon"))
|
||||
}()
|
||||
err = os.WriteFile(filepath.Join("testdata", "testaddon", MetadataFileName), []byte{}, 0644)
|
||||
assert.NoError(t, err)
|
||||
isAddonDir, err = IsAddonDir(filepath.Join("testdata", "testaddon"))
|
||||
assert.Equal(t, isAddonDir, false)
|
||||
assert.Contains(t, err.Error(), "missing")
|
||||
|
||||
// Empty addon name
|
||||
meta = &Meta{}
|
||||
metaYaml, err = yaml.Marshal(meta)
|
||||
assert.NoError(t, err)
|
||||
err = os.WriteFile(filepath.Join("testdata", "testaddon", MetadataFileName), metaYaml, 0644)
|
||||
assert.NoError(t, err)
|
||||
isAddonDir, err = IsAddonDir(filepath.Join("testdata", "testaddon"))
|
||||
assert.Equal(t, isAddonDir, false)
|
||||
assert.Contains(t, err.Error(), "addon name is empty")
|
||||
|
||||
// Empty addon version
|
||||
meta = &Meta{
|
||||
Name: "name",
|
||||
}
|
||||
metaYaml, err = yaml.Marshal(meta)
|
||||
assert.NoError(t, err)
|
||||
err = os.WriteFile(filepath.Join("testdata", "testaddon", MetadataFileName), metaYaml, 0644)
|
||||
assert.NoError(t, err)
|
||||
isAddonDir, err = IsAddonDir(filepath.Join("testdata", "testaddon"))
|
||||
assert.Equal(t, isAddonDir, false)
|
||||
assert.Contains(t, err.Error(), "addon version is empty")
|
||||
|
||||
// No template.yaml
|
||||
meta = &Meta{
|
||||
Name: "name",
|
||||
Version: "1.0.0",
|
||||
}
|
||||
metaYaml, err = yaml.Marshal(meta)
|
||||
assert.NoError(t, err)
|
||||
err = os.WriteFile(filepath.Join("testdata", "testaddon", MetadataFileName), metaYaml, 0644)
|
||||
assert.NoError(t, err)
|
||||
isAddonDir, err = IsAddonDir(filepath.Join("testdata", "testaddon"))
|
||||
assert.Equal(t, isAddonDir, false)
|
||||
assert.Contains(t, err.Error(), "exists in directory")
|
||||
|
||||
// Empty template.yaml
|
||||
err = os.WriteFile(filepath.Join("testdata", "testaddon", TemplateFileName), []byte{}, 0644)
|
||||
assert.NoError(t, err)
|
||||
isAddonDir, err = IsAddonDir(filepath.Join("testdata", "testaddon"))
|
||||
assert.Equal(t, isAddonDir, false)
|
||||
assert.Contains(t, err.Error(), "missing")
|
||||
|
||||
// Pass all checks
|
||||
err = CreateAddonSample("testaddon2", filepath.Join("testdata", "testaddon2"))
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(filepath.Join("testdata", "testaddon2"))
|
||||
}()
|
||||
isAddonDir, err = IsAddonDir(filepath.Join("testdata", "testaddon2"))
|
||||
assert.Equal(t, isAddonDir, true)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestMakeChart(t *testing.T) {
|
||||
var err error
|
||||
|
||||
// Not a addon dir
|
||||
err = MakeChartCompatible(".", true)
|
||||
assert.Contains(t, err.Error(), "not an addon dir")
|
||||
|
||||
// Valid addon dir
|
||||
err = CreateAddonSample("testaddon2", filepath.Join("testdata", "testaddon"))
|
||||
assert.NoError(t, err)
|
||||
defer func() {
|
||||
_ = os.RemoveAll(filepath.Join("testdata", "testaddon"))
|
||||
}()
|
||||
err = MakeChartCompatible(filepath.Join("testdata", "testaddon"), true)
|
||||
assert.NoError(t, err)
|
||||
isChartDir, err := chartutil.IsChartDir(filepath.Join("testdata", "testaddon"))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, isChartDir, true)
|
||||
|
||||
// Already a chart dir
|
||||
err = MakeChartCompatible(filepath.Join("testdata", "testaddon"), false)
|
||||
assert.NoError(t, err)
|
||||
isChartDir, err = chartutil.IsChartDir(filepath.Join("testdata", "testaddon"))
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, isChartDir, true)
|
||||
}
|
||||
|
||||
const (
|
||||
compDefYaml = `
|
||||
apiVersion: core.oam.dev/v1beta1
|
||||
|
||||
@@ -20,23 +20,18 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"sort"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/helm"
|
||||
)
|
||||
|
||||
const (
|
||||
// velaSystemRequirement is the vela version requirement annotation key
|
||||
velaSystemRequirement = `system.vela`
|
||||
// kubernetesSystemRequirement is the kubernetes requirement annotation key
|
||||
kubernetesSystemRequirement = `system.kubernetes`
|
||||
"helm.sh/helm/v3/pkg/chart/loader"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
)
|
||||
|
||||
// VersionedRegistry is the interface of support version registry
|
||||
@@ -45,7 +40,6 @@ type VersionedRegistry interface {
|
||||
GetAddonUIData(ctx context.Context, addonName, version string) (*UIData, error)
|
||||
GetAddonInstallPackage(ctx context.Context, addonName, version string) (*InstallPackage, error)
|
||||
GetDetailedAddon(ctx context.Context, addonName, version string) (*WholeAddonPackage, error)
|
||||
GetAddonAvailableVersion(addonName string) ([]*repo.ChartVersion, error)
|
||||
}
|
||||
|
||||
// BuildVersionedRegistry is build versioned addon registry
|
||||
@@ -105,11 +99,6 @@ func (i *versionedRegistry) GetDetailedAddon(ctx context.Context, addonName, ver
|
||||
return wholePackage, nil
|
||||
}
|
||||
|
||||
// GetAddonAvailableVersion will return all available versions of the addon which is loaded from the registry, and the version are sorted from last to first
|
||||
func (i versionedRegistry) GetAddonAvailableVersion(addonName string) ([]*repo.ChartVersion, error) {
|
||||
return i.loadAddonVersions(addonName)
|
||||
}
|
||||
|
||||
func (i *versionedRegistry) resolveAddonListFromIndex(repoName string, index *repo.IndexFile) []*UIData {
|
||||
var res []*UIData
|
||||
for addonName, versions := range index.Entries {
|
||||
@@ -168,25 +157,11 @@ func (i versionedRegistry) loadAddon(ctx context.Context, name, version string)
|
||||
}
|
||||
addonPkg.AvailableVersions = availableVersions
|
||||
addonPkg.RegistryName = i.name
|
||||
addonPkg.Meta.SystemRequirements = LoadSystemRequirements(addonVersion.Annotations)
|
||||
return addonPkg, nil
|
||||
}
|
||||
return nil, fmt.Errorf("cannot fetch addon package")
|
||||
}
|
||||
|
||||
// loadAddonVersions Load all available versions of the addon
|
||||
func (i versionedRegistry) loadAddonVersions(addonName string) ([]*repo.ChartVersion, error) {
|
||||
versions, err := i.h.ListVersions(i.url, addonName, false, i.Opts)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(versions) == 0 {
|
||||
return nil, ErrNotExist
|
||||
}
|
||||
sort.Sort(sort.Reverse(versions))
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
func loadAddonPackage(addonName string, files []*loader.BufferedFile) (*WholeAddonPackage, error) {
|
||||
mr := MemoryReader{Name: addonName, Files: files}
|
||||
metas, err := mr.ListAddonMeta()
|
||||
@@ -237,18 +212,3 @@ func chooseVersion(specifiedVersion string, versions []*repo.ChartVersion) (*rep
|
||||
}
|
||||
return addonVersion, availableVersions
|
||||
}
|
||||
|
||||
// LoadSystemRequirements load the system version requirements from the addon's meta file
|
||||
func LoadSystemRequirements(anno map[string]string) *SystemRequirements {
|
||||
if len(anno) == 0 {
|
||||
return nil
|
||||
}
|
||||
req := &SystemRequirements{}
|
||||
if _, ok := anno[velaSystemRequirement]; ok {
|
||||
req.VelaVersion = anno[velaSystemRequirement]
|
||||
}
|
||||
if _, ok := anno[kubernetesSystemRequirement]; ok {
|
||||
req.KubernetesVersion = anno[kubernetesSystemRequirement]
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -31,17 +30,15 @@ import (
|
||||
"helm.sh/helm/v3/pkg/chart"
|
||||
"helm.sh/helm/v3/pkg/repo"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/utils/common"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/helm"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestVersionRegistry(t *testing.T) {
|
||||
go func() {
|
||||
http.HandleFunc("/", versionedHandler)
|
||||
http.HandleFunc("/authReg", basicAuthVersionedHandler)
|
||||
http.HandleFunc("/multi/", multiVersionHandler)
|
||||
err := http.ListenAndServe(fmt.Sprintf(":%d", 18083), nil)
|
||||
if err != nil {
|
||||
log.Fatal("Setup server error:", err)
|
||||
@@ -101,38 +98,6 @@ func TestVersionRegistry(t *testing.T) {
|
||||
assert.NotEmpty(t, addonWholePackage.RegistryName)
|
||||
|
||||
testListUIData(t)
|
||||
mr := BuildVersionedRegistry("multiversion-helm-repo", "http://127.0.0.1:18083/multi", nil)
|
||||
addons, err = mr.ListAddon()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(addons), 2)
|
||||
|
||||
addonUIData, err = mr.GetAddonUIData(context.Background(), "fluxcd", "2.0.0")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, addonUIData.Definitions)
|
||||
assert.NotEmpty(t, addonUIData.Icon)
|
||||
assert.Equal(t, addonUIData.Version, "2.0.0")
|
||||
|
||||
addonsInstallPackage, err = mr.GetAddonInstallPackage(context.Background(), "fluxcd", "1.0.0")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, addonsInstallPackage)
|
||||
assert.NotEmpty(t, addonsInstallPackage.YAMLTemplates)
|
||||
assert.NotEmpty(t, addonsInstallPackage.DefSchemas)
|
||||
assert.NotEmpty(t, addonsInstallPackage.SystemRequirements.VelaVersion, "1.3.0")
|
||||
assert.NotEmpty(t, addonsInstallPackage.SystemRequirements.KubernetesVersion, "1.10.0")
|
||||
|
||||
addonWholePackage, err = mr.GetDetailedAddon(context.Background(), "fluxcd", "1.0.0")
|
||||
assert.NoError(t, err)
|
||||
assert.NotEmpty(t, addonWholePackage)
|
||||
assert.NotEmpty(t, addonWholePackage.YAMLTemplates)
|
||||
assert.NotEmpty(t, addonWholePackage.DefSchemas)
|
||||
assert.NotEmpty(t, addonWholePackage.RegistryName)
|
||||
assert.Equal(t, addonWholePackage.RegistryName, "multiversion-helm-repo")
|
||||
|
||||
version, err := mr.GetAddonAvailableVersion("fluxcd")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, len(version), 2)
|
||||
assert.Equal(t, addonWholePackage.SystemRequirements.VelaVersion, ">=1.3.0")
|
||||
assert.Equal(t, addonWholePackage.SystemRequirements.KubernetesVersion, ">=1.10.0")
|
||||
|
||||
}
|
||||
|
||||
@@ -207,66 +172,3 @@ var basicAuthVersionedHandler http.HandlerFunc = func(writer http.ResponseWriter
|
||||
writer.Write(files)
|
||||
}
|
||||
}
|
||||
|
||||
var multiVersionHandler http.HandlerFunc = func(writer http.ResponseWriter, request *http.Request) {
|
||||
switch {
|
||||
case strings.Contains(request.URL.Path, "index.yaml"):
|
||||
files, err := ioutil.ReadFile("./testdata/multiversion-helm-repo/index.yaml")
|
||||
if err != nil {
|
||||
_, _ = writer.Write([]byte(err.Error()))
|
||||
}
|
||||
writer.Write(files)
|
||||
case strings.Contains(request.URL.Path, "fluxcd-1.0.0.tgz"):
|
||||
files, err := ioutil.ReadFile("./testdata/multiversion-helm-repo/fluxcd-1.0.0.tgz")
|
||||
if err != nil {
|
||||
_, _ = writer.Write([]byte(err.Error()))
|
||||
}
|
||||
writer.Write(files)
|
||||
case strings.Contains(request.URL.Path, "fluxcd-2.0.0.tgz"):
|
||||
files, err := ioutil.ReadFile("./testdata/multiversion-helm-repo/fluxcd-2.0.0.tgz")
|
||||
if err != nil {
|
||||
_, _ = writer.Write([]byte(err.Error()))
|
||||
}
|
||||
writer.Write(files)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadSystemRequirements(t *testing.T) {
|
||||
req := LoadSystemRequirements(map[string]string{velaSystemRequirement: ">=1.3.0", kubernetesSystemRequirement: ">=1.10.0"})
|
||||
assert.Equal(t, req.VelaVersion, ">=1.3.0")
|
||||
assert.Equal(t, req.KubernetesVersion, ">=1.10.0")
|
||||
|
||||
req = LoadSystemRequirements(nil)
|
||||
assert.Empty(t, req)
|
||||
|
||||
req = LoadSystemRequirements(map[string]string{kubernetesSystemRequirement: ">=1.10.0"})
|
||||
assert.Equal(t, req.KubernetesVersion, ">=1.10.0")
|
||||
|
||||
req = LoadSystemRequirements(map[string]string{velaSystemRequirement: ">=1.4.0"})
|
||||
assert.Equal(t, req.VelaVersion, ">=1.4.0")
|
||||
}
|
||||
|
||||
func TestLoadAddonVersions(t *testing.T) {
|
||||
server := httptest.NewServer(multiVersionHandler)
|
||||
defer server.Close()
|
||||
mr := &versionedRegistry{
|
||||
name: "multiversion-helm-repo",
|
||||
url: server.URL,
|
||||
h: helm.NewHelperWithCache(),
|
||||
Opts: nil,
|
||||
}
|
||||
versions, err := mr.loadAddonVersions("not-exist")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, err, ErrNotExist)
|
||||
assert.Equal(t, len(versions), 0)
|
||||
|
||||
mr = &versionedRegistry{
|
||||
name: "multiversion-helm-repo",
|
||||
url: server.URL,
|
||||
h: helm.NewHelperWithCache(),
|
||||
Opts: nil,
|
||||
}
|
||||
versions, err = mr.loadAddonVersions("not-exist")
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, len(versions), 0)
|
||||
}
|
||||
|
||||
@@ -101,16 +101,6 @@ func (a *Application) IsSynced() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// IsReadOnly is readonly app
|
||||
// Only the source is inner, the app is readonly
|
||||
func (a *Application) IsReadOnly() bool {
|
||||
if a.Labels == nil {
|
||||
return false
|
||||
}
|
||||
sot := a.Labels[LabelSourceOfTruth]
|
||||
return sot == FromInner
|
||||
}
|
||||
|
||||
// ClusterSelector cluster selector
|
||||
type ClusterSelector struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
@@ -50,9 +50,7 @@ const (
|
||||
FromCR = "from-k8s-resource"
|
||||
// FromUX means the data source of truth is from velaux data store
|
||||
FromUX = "from-velaux"
|
||||
// FromInner means the data source of truth is from KubeVela inner usage
|
||||
// the configuration that don't want to be synced
|
||||
// the addon application should be synced, but set to readonly mode
|
||||
// FromInner means the data source of truth is from KubeVela inner usage, such as addon or configuration that don't want to be synced
|
||||
FromInner = "from-inner-system"
|
||||
)
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ import (
|
||||
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
)
|
||||
|
||||
@@ -96,26 +95,3 @@ func DeleteApplicationEnvPolicies(ctx context.Context, store datastore.DataStore
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetApplicationRevision get the application revision
|
||||
// If the version is empty, will query the latest revision of the application
|
||||
func GetApplicationRevision(ctx context.Context, store datastore.DataStore, appName, version string) (*model.ApplicationRevision, error) {
|
||||
ar := &model.ApplicationRevision{AppPrimaryKey: appName}
|
||||
if version != "" {
|
||||
ar.Version = version
|
||||
}
|
||||
revisions, err := store.List(ctx, ar, &datastore.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 1,
|
||||
SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}},
|
||||
})
|
||||
if err != nil || len(revisions) == 0 {
|
||||
return nil, bcode.ErrApplicationRevisionNotExist
|
||||
}
|
||||
latestRevisionRaw := revisions[0]
|
||||
latestRevision, ok := latestRevisionRaw.(*model.ApplicationRevision)
|
||||
if !ok {
|
||||
return nil, errors.New("convert application revision error")
|
||||
}
|
||||
return latestRevision, nil
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ import (
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/multicluster"
|
||||
"github.com/oam-dev/kubevela/pkg/oam"
|
||||
addonutil "github.com/oam-dev/kubevela/pkg/utils/addon"
|
||||
"github.com/oam-dev/kubevela/pkg/utils/apply"
|
||||
velaerr "github.com/oam-dev/kubevela/pkg/utils/errors"
|
||||
)
|
||||
@@ -221,7 +220,7 @@ func (u *addonServiceImpl) StatusAddon(ctx context.Context, name string) (*apis.
|
||||
var sec v1.Secret
|
||||
err = u.kubeClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Name: addonutil.Addon2SecName(name),
|
||||
Name: pkgaddon.Convert2SecName(name),
|
||||
}, &sec)
|
||||
if err != nil && !errors2.IsNotFound(err) {
|
||||
return nil, bcode.ErrAddonSecretGet
|
||||
@@ -446,7 +445,7 @@ func (u *addonServiceImpl) UpdateAddon(ctx context.Context, name string, args ap
|
||||
// check addon application whether exist
|
||||
err := u.kubeClient.Get(ctx, client.ObjectKey{
|
||||
Namespace: types.DefaultKubeVelaNS,
|
||||
Name: addonutil.Addon2AppName(name),
|
||||
Name: pkgaddon.Convert2AppName(name),
|
||||
}, &app)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/selection"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
@@ -93,7 +94,7 @@ type ApplicationService interface {
|
||||
DetailRevision(ctx context.Context, appName, revisionName string) (*apisv1.DetailRevisionResponse, error)
|
||||
Statistics(ctx context.Context, app *model.Application) (*apisv1.ApplicationStatisticsResponse, error)
|
||||
ListRecords(ctx context.Context, appName string) (*apisv1.ListWorkflowRecordsResponse, error)
|
||||
CompareApp(ctx context.Context, app *model.Application, compareReq apisv1.AppCompareReq) (*apisv1.AppCompareResponse, error)
|
||||
CompareAppWithLatestRevision(ctx context.Context, app *model.Application, compareReq apisv1.AppCompareReq) (*apisv1.AppCompareResponse, error)
|
||||
ResetAppToLatestRevision(ctx context.Context, appName string) (*apisv1.AppResetResponse, error)
|
||||
DryRunAppOrRevision(ctx context.Context, app *model.Application, dryRunReq apisv1.AppDryRunReq) (*apisv1.AppDryRunResponse, error)
|
||||
CreateApplicationTrigger(ctx context.Context, app *model.Application, req apisv1.CreateApplicationTriggerRequest) (*apisv1.ApplicationTriggerBase, error)
|
||||
@@ -295,23 +296,6 @@ func (c *applicationServiceImpl) GetApplicationStatus(ctx context.Context, appmo
|
||||
return &app.Status, nil
|
||||
}
|
||||
|
||||
// GetApplicationStatus get application CR from controller cluster
|
||||
func (c *applicationServiceImpl) GetApplicationCRInEnv(ctx context.Context, appmodel *model.Application, envName string) (*v1beta1.Application, error) {
|
||||
var app v1beta1.Application
|
||||
env, err := c.EnvService.GetEnv(ctx, envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = c.KubeClient.Get(ctx, types.NamespacedName{Namespace: env.Namespace, Name: appmodel.GetAppNameForSynced()}, &app)
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return &app, nil
|
||||
}
|
||||
|
||||
// GetApplicationCR get application CR in cluster
|
||||
func (c *applicationServiceImpl) GetApplicationCR(ctx context.Context, appModel *model.Application) (*v1beta1.ApplicationList, error) {
|
||||
var apps v1beta1.ApplicationList
|
||||
@@ -646,7 +630,7 @@ func (c *applicationServiceImpl) Deploy(ctx context.Context, app *model.Applicat
|
||||
// TODO: rollback to handle all the error case
|
||||
// step1: Render oam application
|
||||
version := utils.GenerateVersion("")
|
||||
oamApp, err := c.renderOAMApplication(ctx, app, req.WorkflowName, "", version)
|
||||
oamApp, err := c.renderOAMApplication(ctx, app, req.WorkflowName, version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -787,7 +771,7 @@ func (c *applicationServiceImpl) syncConfigs4Application(ctx context.Context, ap
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appModel *model.Application, reqWorkflowName, envName, version string) (*v1beta1.Application, error) {
|
||||
func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appModel *model.Application, reqWorkflowName, version string) (*v1beta1.Application, error) {
|
||||
// Priority 1 uses the requested workflow as release .
|
||||
// Priority 2 uses the default workflow as release .
|
||||
var workflow *model.Workflow
|
||||
@@ -803,15 +787,10 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if workflow != nil {
|
||||
envName = workflow.EnvName
|
||||
if workflow == nil || workflow.EnvName == "" {
|
||||
return nil, bcode.ErrWorkflowNotExist
|
||||
}
|
||||
|
||||
envbinding, err := c.EnvBindingService.GetEnvBinding(ctx, appModel, envName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
env, err := c.EnvService.GetEnv(ctx, envName)
|
||||
env, err := c.EnvService.GetEnv(ctx, workflow.EnvName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -820,20 +799,14 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
labels[key] = value
|
||||
}
|
||||
labels[oam.AnnotationAppName] = appModel.Name
|
||||
// To take over the application
|
||||
labels[model.LabelSourceOfTruth] = model.FromUX
|
||||
|
||||
deployAppName := envbinding.AppDeployName
|
||||
if deployAppName == "" {
|
||||
deployAppName = appModel.Name
|
||||
}
|
||||
var app = &v1beta1.Application{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
Kind: "Application",
|
||||
APIVersion: "core.oam.dev/v1beta1",
|
||||
},
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: deployAppName,
|
||||
Name: appModel.Name,
|
||||
Namespace: env.Namespace,
|
||||
Labels: labels,
|
||||
Annotations: map[string]string{
|
||||
@@ -914,25 +887,25 @@ func (c *applicationServiceImpl) renderOAMApplication(ctx context.Context, appMo
|
||||
}
|
||||
app.Spec.Policies = append(app.Spec.Policies, appPolicy)
|
||||
}
|
||||
if workflow != nil {
|
||||
app.Annotations[oam.AnnotationWorkflowName] = workflow.Name
|
||||
var steps []v1beta1.WorkflowStep
|
||||
for _, step := range workflow.Steps {
|
||||
var workflowStep = v1beta1.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
}
|
||||
if step.Properties != nil {
|
||||
workflowStep.Properties = step.Properties.RawExtension()
|
||||
}
|
||||
steps = append(steps, workflowStep)
|
||||
|
||||
app.Annotations[oam.AnnotationWorkflowName] = workflow.Name
|
||||
var steps []v1beta1.WorkflowStep
|
||||
for _, step := range workflow.Steps {
|
||||
var workflowStep = v1beta1.WorkflowStep{
|
||||
Name: step.Name,
|
||||
Type: step.Type,
|
||||
Inputs: step.Inputs,
|
||||
Outputs: step.Outputs,
|
||||
}
|
||||
app.Spec.Workflow = &v1beta1.Workflow{
|
||||
Steps: steps,
|
||||
if step.Properties != nil {
|
||||
workflowStep.Properties = step.Properties.RawExtension()
|
||||
}
|
||||
steps = append(steps, workflowStep)
|
||||
}
|
||||
app.Spec.Workflow = &v1beta1.Workflow{
|
||||
Steps: steps,
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
@@ -1396,101 +1369,50 @@ func (c *applicationServiceImpl) Statistics(ctx context.Context, app *model.Appl
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CompareApp compare application
|
||||
func (c *applicationServiceImpl) CompareApp(ctx context.Context, appModel *model.Application, compareReq apisv1.AppCompareReq) (*apisv1.AppCompareResponse, error) {
|
||||
var base, compareTarget *v1beta1.Application
|
||||
var err error
|
||||
var envNameByRevision string
|
||||
switch {
|
||||
case compareReq.CompareLatestWithRunning != nil:
|
||||
base, err = c.renderOAMApplication(ctx, appModel, "", compareReq.CompareLatestWithRunning.Env, "")
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to build the latest application %s", err.Error())
|
||||
break
|
||||
}
|
||||
case compareReq.CompareRevisionWithRunning != nil || compareReq.CompareRevisionWithLatest != nil:
|
||||
var revision = ""
|
||||
if compareReq.CompareRevisionWithRunning != nil {
|
||||
revision = compareReq.CompareRevisionWithRunning.Revision
|
||||
}
|
||||
if compareReq.CompareRevisionWithLatest != nil {
|
||||
revision = compareReq.CompareRevisionWithLatest.Revision
|
||||
}
|
||||
base, envNameByRevision, err = c.getAppModelFromRevision(ctx, appModel.Name, revision)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to get the app model from the revision %s", err.Error())
|
||||
break
|
||||
}
|
||||
// CompareAppWithLatestRevision compare application with last revision
|
||||
func (c *applicationServiceImpl) CompareAppWithLatestRevision(ctx context.Context, appModel *model.Application, compareReq apisv1.AppCompareReq) (*apisv1.AppCompareResponse, error) {
|
||||
var reqWorkflowName string
|
||||
if compareReq.Env != "" {
|
||||
reqWorkflowName = repository.ConvertWorkflowName(compareReq.Env)
|
||||
}
|
||||
newApp, err := c.renderOAMApplication(ctx, appModel, reqWorkflowName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ignoreSomeParams(newApp)
|
||||
newAppBytes, err := yaml.Marshal(newApp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch {
|
||||
case compareReq.CompareLatestWithRunning != nil || compareReq.CompareRevisionWithRunning != nil:
|
||||
var envName string
|
||||
if compareReq.CompareLatestWithRunning != nil {
|
||||
envName = compareReq.CompareLatestWithRunning.Env
|
||||
}
|
||||
if compareReq.CompareRevisionWithRunning != nil {
|
||||
envName = envNameByRevision
|
||||
}
|
||||
if envName == "" {
|
||||
break
|
||||
}
|
||||
compareTarget, err = c.GetApplicationCRInEnv(ctx, appModel, envName)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to query the application CR %s", err.Error())
|
||||
break
|
||||
}
|
||||
case compareReq.CompareRevisionWithLatest != nil:
|
||||
compareTarget, err = c.renderOAMApplication(ctx, appModel, "", envNameByRevision, "")
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to build the latest application %s", err.Error())
|
||||
break
|
||||
oldApp, err := c.getAppFromLatestRevision(ctx, appModel.Name, compareReq.Env, "")
|
||||
if err != nil {
|
||||
if errors.Is(err, bcode.ErrApplicationRevisionNotExist) {
|
||||
return &apisv1.AppCompareResponse{IsDiff: false, NewAppYAML: string(newAppBytes)}, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var baseAppBytes, targetAppBytes []byte
|
||||
|
||||
if base != nil {
|
||||
ignoreSomeParams(base)
|
||||
baseAppBytes, err = yaml.Marshal(base)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ignoreSomeParams(oldApp)
|
||||
oldAppBytes, err := yaml.Marshal(oldApp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if compareTarget != nil {
|
||||
ignoreSomeParams(compareTarget)
|
||||
targetAppBytes, err = yaml.Marshal(compareTarget)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
compareResponse := &apisv1.AppCompareResponse{IsDiff: true, BaseAppYAML: string(baseAppBytes), TargetAppYAML: string(targetAppBytes)}
|
||||
|
||||
if base == nil || compareTarget == nil {
|
||||
return compareResponse, nil
|
||||
}
|
||||
|
||||
args := common2.Args{
|
||||
Schema: common2.Scheme,
|
||||
}
|
||||
_ = args.SetConfig(c.KubeConfig)
|
||||
args.SetClient(c.KubeClient)
|
||||
diffResult, buff, err := compare(ctx, args, compareTarget, base)
|
||||
diffResult, buff, err := compare(ctx, args, newApp, oldApp)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("fail to compare the app %s", err.Error())
|
||||
compareResponse.IsDiff = false
|
||||
return compareResponse, nil
|
||||
return &apisv1.AppCompareResponse{IsDiff: false, NewAppYAML: string(newAppBytes), OldAppYAML: string(oldAppBytes)}, err
|
||||
}
|
||||
compareResponse.IsDiff = diffResult.DiffType != ""
|
||||
compareResponse.DiffReport = buff.String()
|
||||
return compareResponse, nil
|
||||
return &apisv1.AppCompareResponse{IsDiff: diffResult.DiffType != "", DiffReport: buff.String(), NewAppYAML: string(newAppBytes), OldAppYAML: string(oldAppBytes)}, nil
|
||||
}
|
||||
|
||||
// ResetAppToLatestRevision reset app's component to last revision
|
||||
func (c *applicationServiceImpl) ResetAppToLatestRevision(ctx context.Context, appName string) (*apisv1.AppResetResponse, error) {
|
||||
targetApp, _, err := c.getAppModelFromRevision(ctx, appName, "")
|
||||
targetApp, err := c.getAppFromLatestRevision(ctx, appName, "", "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1502,12 +1424,16 @@ func (c *applicationServiceImpl) DryRunAppOrRevision(ctx context.Context, appMod
|
||||
var app *v1beta1.Application
|
||||
var err error
|
||||
if dryRunReq.DryRunType == "APP" {
|
||||
app, err = c.renderOAMApplication(ctx, appModel, dryRunReq.Workflow, dryRunReq.Env, "")
|
||||
var reqWorkflowName string
|
||||
if dryRunReq.Env != "" {
|
||||
reqWorkflowName = repository.ConvertWorkflowName(dryRunReq.Env)
|
||||
}
|
||||
app, err = c.renderOAMApplication(ctx, appModel, reqWorkflowName, "")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
app, _, err = c.getAppModelFromRevision(ctx, dryRunReq.AppName, dryRunReq.Version)
|
||||
app, err = c.getAppFromLatestRevision(ctx, dryRunReq.AppName, dryRunReq.Env, dryRunReq.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1535,16 +1461,33 @@ func genWebhookToken() string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func (c *applicationServiceImpl) getAppModelFromRevision(ctx context.Context, appName string, version string) (*v1beta1.Application, string, error) {
|
||||
latestRevision, err := repository.GetApplicationRevision(ctx, c.Store, appName, version)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
func (c *applicationServiceImpl) getAppFromLatestRevision(ctx context.Context, appName string, envName string, version string) (*v1beta1.Application, error) {
|
||||
|
||||
ar := &model.ApplicationRevision{AppPrimaryKey: appName}
|
||||
if envName != "" {
|
||||
ar.EnvName = envName
|
||||
}
|
||||
if version != "" {
|
||||
ar.Version = version
|
||||
}
|
||||
revisions, err := c.Store.List(ctx, ar, &datastore.ListOptions{
|
||||
Page: 1,
|
||||
PageSize: 1,
|
||||
SortBy: []datastore.SortOption{{Key: "createTime", Order: datastore.SortOrderDescending}},
|
||||
})
|
||||
if err != nil || len(revisions) == 0 {
|
||||
return nil, bcode.ErrApplicationRevisionNotExist
|
||||
}
|
||||
latestRevisionRaw := revisions[0]
|
||||
latestRevision, ok := latestRevisionRaw.(*model.ApplicationRevision)
|
||||
if !ok {
|
||||
return nil, errors.New("convert application revision error")
|
||||
}
|
||||
oldApp := &v1beta1.Application{}
|
||||
if err := yaml.Unmarshal([]byte(latestRevision.ApplyAppConfig), oldApp); err != nil {
|
||||
return nil, "", err
|
||||
return nil, err
|
||||
}
|
||||
return oldApp, latestRevision.EnvName, nil
|
||||
return oldApp, nil
|
||||
}
|
||||
|
||||
func (c *applicationServiceImpl) resetApp(ctx context.Context, targetApp *v1beta1.Application) (*apisv1.AppResetResponse, error) {
|
||||
@@ -1631,21 +1574,38 @@ func dryRunApplication(ctx context.Context, c common2.Args, app *v1beta1.Applica
|
||||
return buff, err
|
||||
}
|
||||
dryRunOpt := dryrun.NewDryRunOption(newClient, config, dm, pd, objects)
|
||||
comps, policies, err := dryRunOpt.ExecuteDryRun(ctx, app)
|
||||
comps, err := dryRunOpt.ExecuteDryRun(ctx, app)
|
||||
if err != nil {
|
||||
return buff, fmt.Errorf("generate OAM objects %w", err)
|
||||
}
|
||||
if _, err = fmt.Fprintf(&buff, "---\n# Application(%s) \n---\n\n", app.Name); err != nil {
|
||||
return buff, fmt.Errorf("fail to write to buff %w", err)
|
||||
var components = make(map[string]*unstructured.Unstructured)
|
||||
for _, comp := range comps {
|
||||
components[comp.Name] = comp.StandardWorkload
|
||||
}
|
||||
buff.Write([]byte(fmt.Sprintf("---\n# Application(%s) \n---\n\n", app.Name)))
|
||||
result, err := yaml.Marshal(app)
|
||||
if err != nil {
|
||||
return buff, fmt.Errorf("marshal app: %w", err)
|
||||
return buff, errors.New("marshal app error")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.WriteString("\n---\n")
|
||||
if err = dryRunOpt.PrintDryRun(&buff, app.Name, comps, policies); err != nil {
|
||||
return buff, err
|
||||
buff.Write([]byte("\n---\n"))
|
||||
for _, c := range comps {
|
||||
buff.Write([]byte(fmt.Sprintf("---\n# Application(%s) -- Component(%s) \n---\n\n", app.Name, c.Name)))
|
||||
result, err := yaml.Marshal(components[c.Name])
|
||||
if err != nil {
|
||||
return buff, errors.New("marshal result for component " + c.Name + " object in yaml format")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.Write([]byte("\n---\n"))
|
||||
for _, t := range c.Traits {
|
||||
result, err := yaml.Marshal(t)
|
||||
if err != nil {
|
||||
return buff, errors.New("marshal result for component " + c.Name + " object in yaml format")
|
||||
}
|
||||
buff.Write(result)
|
||||
buff.Write([]byte("\n---\n"))
|
||||
}
|
||||
buff.Write([]byte("\n"))
|
||||
}
|
||||
return buff, nil
|
||||
}
|
||||
@@ -1653,23 +1613,21 @@ func dryRunApplication(ctx context.Context, c common2.Args, app *v1beta1.Applica
|
||||
// ignoreSomeParams ignore some parameters before comparing the app changes.
|
||||
// ignore the workflow spec
|
||||
func ignoreSomeParams(o *v1beta1.Application) {
|
||||
var defaultApplication = v1beta1.Application{}
|
||||
// only compare the spec without the workflow
|
||||
defaultApplication.Spec = o.Spec
|
||||
defaultApplication.Spec.Workflow = nil
|
||||
defaultApplication.Name = o.Name
|
||||
defaultApplication.Namespace = o.Namespace
|
||||
|
||||
sort.Slice(defaultApplication.Spec.Policies, func(i, j int) bool {
|
||||
return defaultApplication.Spec.Policies[i].Name < defaultApplication.Spec.Policies[j].Name
|
||||
})
|
||||
sort.Slice(defaultApplication.Spec.Components, func(i, j int) bool {
|
||||
return defaultApplication.Spec.Components[i].Name < defaultApplication.Spec.Components[j].Name
|
||||
})
|
||||
*o = defaultApplication
|
||||
// set default
|
||||
o.ResourceVersion = ""
|
||||
o.Spec.Workflow = nil
|
||||
newAnnotations := map[string]string{}
|
||||
annotations := o.GetAnnotations()
|
||||
for k, v := range annotations {
|
||||
if k == oam.AnnotationDeployVersion || k == oam.AnnotationPublishVersion || k == "kubectl.kubernetes.io/last-applied-configuration" {
|
||||
continue
|
||||
}
|
||||
newAnnotations[k] = v
|
||||
}
|
||||
o.SetAnnotations(newAnnotations)
|
||||
}
|
||||
|
||||
func compare(ctx context.Context, c common2.Args, targetApp *v1beta1.Application, baseApp *v1beta1.Application) (*dryrun.DiffEntry, bytes.Buffer, error) {
|
||||
func compare(ctx context.Context, c common2.Args, newApp *v1beta1.Application, oldApp *v1beta1.Application) (*dryrun.DiffEntry, bytes.Buffer, error) {
|
||||
var buff = bytes.Buffer{}
|
||||
_, err := c.GetClient()
|
||||
if err != nil {
|
||||
@@ -1693,7 +1651,7 @@ func compare(ctx context.Context, c common2.Args, targetApp *v1beta1.Application
|
||||
return nil, buff, err
|
||||
}
|
||||
liveDiffOption := dryrun.NewLiveDiffOption(client, config, dm, pd, objs)
|
||||
diffResult, err := liveDiffOption.DiffApps(ctx, baseApp, targetApp)
|
||||
diffResult, err := liveDiffOption.DiffApps(ctx, newApp, oldApp)
|
||||
if err != nil {
|
||||
return nil, buff, err
|
||||
}
|
||||
@@ -1701,55 +1659,3 @@ func compare(ctx context.Context, c common2.Args, targetApp *v1beta1.Application
|
||||
reportDiffOpt.PrintDiffReport(diffResult)
|
||||
return diffResult, buff, nil
|
||||
}
|
||||
|
||||
// NewTestApplicationService create the application service instance for testing
|
||||
func NewTestApplicationService(ds datastore.DataStore, c client.Client, cfg *rest.Config) ApplicationService {
|
||||
targetImpl := &targetServiceImpl{K8sClient: c, Store: ds}
|
||||
envImpl := &envServiceImpl{KubeClient: c, Store: ds}
|
||||
rbacService := &rbacServiceImpl{Store: ds}
|
||||
userService := &userServiceImpl{Store: ds, RbacService: rbacService, SysService: systemInfoServiceImpl{Store: ds}}
|
||||
projectService := &projectServiceImpl{
|
||||
K8sClient: c,
|
||||
Store: ds,
|
||||
RbacService: rbacService,
|
||||
TargetService: targetImpl,
|
||||
UserService: userService,
|
||||
EnvService: envImpl,
|
||||
}
|
||||
userService.ProjectService = projectService
|
||||
envImpl.ProjectService = projectService
|
||||
workflowService := &workflowServiceImpl{
|
||||
Store: ds,
|
||||
KubeClient: c,
|
||||
Apply: apply.NewAPIApplicator(c),
|
||||
EnvService: envImpl,
|
||||
}
|
||||
def := &definitionServiceImpl{KubeClient: c}
|
||||
envbinding := &envBindingServiceImpl{
|
||||
Store: ds,
|
||||
WorkflowService: workflowService,
|
||||
EnvService: envImpl,
|
||||
DefinitionService: def,
|
||||
KubeClient: c,
|
||||
}
|
||||
workflowService.EnvBindingService = envbinding
|
||||
return &applicationServiceImpl{
|
||||
Store: ds,
|
||||
KubeClient: c,
|
||||
KubeConfig: cfg,
|
||||
Apply: apply.NewAPIApplicator(c),
|
||||
WorkflowService: &workflowServiceImpl{
|
||||
Store: ds,
|
||||
KubeClient: c,
|
||||
Apply: apply.NewAPIApplicator(c),
|
||||
EnvService: envImpl,
|
||||
EnvBindingService: envbinding,
|
||||
},
|
||||
EnvService: envImpl,
|
||||
EnvBindingService: envbinding,
|
||||
TargetService: targetImpl,
|
||||
DefinitionService: def,
|
||||
ProjectService: projectService,
|
||||
UserService: userService,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,12 +478,8 @@ var _ = Describe("Test application service function", func() {
|
||||
Expect(resp.Total).Should(Equal(int64(3)))
|
||||
})
|
||||
|
||||
It("Test CompareApp function", func() {
|
||||
check := func(compareResponse *v1.AppCompareResponse, isDiff bool) {
|
||||
Expect(cmp.Diff(compareResponse.BaseAppYAML, "")).ShouldNot(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.TargetAppYAML, "")).ShouldNot(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, isDiff)).Should(BeEmpty())
|
||||
}
|
||||
It("Test CompareAppWithLatestRevision function", func() {
|
||||
|
||||
appModel, err := appService.GetApplication(context.TODO(), testApp)
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = appService.Deploy(context.TODO(), appModel, v1.ApplicationDeployRequest{WorkflowName: repository.ConvertWorkflowName("app-dev")})
|
||||
@@ -492,40 +488,23 @@ var _ = Describe("Test application service function", func() {
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("compare when app not change, should return false")
|
||||
compareResponse, err := appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithRunning: &v1.CompareRevisionWithRunningOption{},
|
||||
})
|
||||
compareResponse, err := appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, false)
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, false)).Should(BeEmpty())
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithLatest: &v1.CompareRevisionWithLatestOption{},
|
||||
})
|
||||
By("compare when app not change and env not empty, should return false")
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{Env: "app-dev"})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, false)
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, false)
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, false)).Should(BeEmpty())
|
||||
|
||||
By("compare when app add env, not change, should return false")
|
||||
_, err = envService.CreateEnv(context.TODO(), v1.CreateEnvRequest{Name: "app-prod", Namespace: "envnsprod", Targets: []string{defaultTarget}, Project: "app-prod"})
|
||||
Expect(err).Should(BeNil())
|
||||
_, err = envBindingService.CreateEnvBinding(context.TODO(), appModel, v1.CreateApplicationEnvbindingRequest{EnvBinding: v1.EnvBinding{Name: "app-prod"}})
|
||||
Expect(err).Should(BeNil())
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-prod",
|
||||
},
|
||||
})
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.TargetAppYAML, "")).Should(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.BaseAppYAML, "")).ShouldNot(BeEmpty())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, false)).Should(BeEmpty())
|
||||
|
||||
By("compare when app's env add target, should return true")
|
||||
_, err = targetService.CreateTarget(context.TODO(), v1.CreateTargetRequest{Name: "dev-target1", Project: appModel.Project, Cluster: &v1.ClusterTarget{ClusterName: "local", Namespace: "dev-target1"}})
|
||||
@@ -536,13 +515,9 @@ var _ = Describe("Test application service function", func() {
|
||||
Targets: []string{defaultTarget, "dev-target1"},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, true)
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
|
||||
By("compare when update app's trait, should return true")
|
||||
// reset app config
|
||||
@@ -554,21 +529,11 @@ var _ = Describe("Test application service function", func() {
|
||||
Description: "description",
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithLatest: &v1.CompareRevisionWithLatestOption{},
|
||||
})
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
|
||||
By("compare when update component's target after app deployed ,should return true")
|
||||
By("compare when update component's target after app deployed ,should return ture")
|
||||
// reset app config
|
||||
_, err = appService.ResetAppToLatestRevision(context.TODO(), testApp)
|
||||
Expect(err).Should(BeNil())
|
||||
@@ -580,49 +545,9 @@ var _ = Describe("Test application service function", func() {
|
||||
Properties: &newProperties,
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithLatest: &v1.CompareRevisionWithLatestOption{},
|
||||
})
|
||||
compareResponse, err = appService.CompareAppWithLatestRevision(context.TODO(), appModel, v1.AppCompareReq{})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, true)
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, true)
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithRunning: &v1.CompareRevisionWithRunningOption{},
|
||||
})
|
||||
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, false)
|
||||
|
||||
By("compare when changed the application CR, should return true")
|
||||
|
||||
appCR, err := appService.GetApplicationCRInEnv(context.TODO(), appModel, "app-dev")
|
||||
Expect(err).Should(BeNil())
|
||||
appCR.Spec.Components[0].Properties = &runtime.RawExtension{Raw: []byte("{\"exposeType\":\"NodePort\",\"image\":\"nginx:222\",\"imagePullPolicy\":\"Always\"}")}
|
||||
err = k8sClient.Update(context.TODO(), appCR)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareRevisionWithRunning: &v1.CompareRevisionWithRunningOption{},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, true)
|
||||
|
||||
compareResponse, err = appService.CompareApp(context.TODO(), appModel, v1.AppCompareReq{
|
||||
CompareLatestWithRunning: &v1.CompareLatestWithRunningOption{
|
||||
Env: "app-dev",
|
||||
},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
check(compareResponse, true)
|
||||
|
||||
Expect(cmp.Diff(compareResponse.IsDiff, true)).Should(BeEmpty())
|
||||
err = envBindingService.ApplicationEnvRecycle(context.TODO(), &model.Application{Name: testApp}, &model.EnvBinding{Name: "app-dev"})
|
||||
Expect(err).Should(BeNil())
|
||||
})
|
||||
|
||||
@@ -1,373 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
v1alpha1 "github.com/cloudtty/cloudtty/pkg/apis/cloudshell/v1alpha1"
|
||||
"github.com/ghodss/yaml"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
"k8s.io/client-go/tools/clientcmd/api"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
|
||||
kubevelatypes "github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/log"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultCloudShellPathPrefix the default prefix
|
||||
DefaultCloudShellPathPrefix = "/view/cloudshell"
|
||||
// DefaultCloudShellCommand the init command when open the TTY connection
|
||||
DefaultCloudShellCommand = "bash"
|
||||
// DefaultLabelKey the default label key for the cloud shell
|
||||
DefaultLabelKey = "oam.dev/cloudshell"
|
||||
|
||||
// StatusFailed means there is an error when creating the required resources, should retry.
|
||||
StatusFailed = "Failed"
|
||||
|
||||
// StatusPreparing means the required resource is created, waiting until the environment is ready.
|
||||
StatusPreparing = "Preparing"
|
||||
|
||||
// StatusCompleted means the environment is ready.
|
||||
StatusCompleted = "Completed"
|
||||
|
||||
// CAFilePathInCluster the CA file path when the server running in cluster.
|
||||
CAFilePathInCluster = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
|
||||
|
||||
// ServerAddressInCluster the kubernetes server address in cluster.
|
||||
ServerAddressInCluster = "https://kubernetes.default:443"
|
||||
)
|
||||
|
||||
// CloudShellService provide the cloud shell feature
|
||||
type CloudShellService interface {
|
||||
Prepare(ctx context.Context) (*apisv1.CloudShellPrepareResponse, error)
|
||||
GetCloudShellEndpoint(ctx context.Context) (string, error)
|
||||
}
|
||||
|
||||
// GenerateKubeConfig generate the kubeconfig for the cloudshell
|
||||
type GenerateKubeConfig func(ctx context.Context, cli kubernetes.Interface, cfg *api.Config, writer io.Writer, options ...auth.KubeConfigGenerateOption) (*api.Config, error)
|
||||
|
||||
type cloudShellServiceImpl struct {
|
||||
KubeClient client.Client `inject:"kubeClient"`
|
||||
KubeConfig *rest.Config `inject:"kubeConfig"`
|
||||
UserService UserService `inject:""`
|
||||
ProjectService ProjectService `inject:""`
|
||||
RBACService RBACService `inject:""`
|
||||
TargetService TargetService `inject:""`
|
||||
EnvService EnvService `inject:""`
|
||||
GenerateKubeConfig GenerateKubeConfig
|
||||
}
|
||||
|
||||
// NewCloudShellService create the instance of the cloud shell service
|
||||
func NewCloudShellService() CloudShellService {
|
||||
return &cloudShellServiceImpl{
|
||||
GenerateKubeConfig: auth.GenerateKubeConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// Prepare prepare the cloud shell environment for the user
|
||||
func (c *cloudShellServiceImpl) Prepare(ctx context.Context) (*apisv1.CloudShellPrepareResponse, error) {
|
||||
res := &apisv1.CloudShellPrepareResponse{}
|
||||
var userName string
|
||||
if user := ctx.Value(&apisv1.CtxKeyUser); user != nil {
|
||||
if u, ok := user.(string); ok {
|
||||
userName = u
|
||||
}
|
||||
}
|
||||
if userName == "" {
|
||||
return nil, bcode.ErrUnauthorized
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*20)
|
||||
defer cancel()
|
||||
var cloudShell v1alpha1.CloudShell
|
||||
var shouldCreate bool
|
||||
if err := c.KubeClient.Get(ctx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: makeUserCloudShellName(userName)}, &cloudShell); err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
shouldCreate = true
|
||||
} else {
|
||||
if meta.IsNoMatchError(err) {
|
||||
return nil, bcode.ErrCloudShellAddonNotEnabled
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
if shouldCreate {
|
||||
if err := c.prepareKubeConfig(ctx); err != nil {
|
||||
return res, fmt.Errorf("failed to prepare the kubeconfig for the user: %w", err)
|
||||
}
|
||||
new, err := c.newCloudShell(ctx)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
if err := c.KubeClient.Create(ctx, new); err != nil {
|
||||
if meta.IsNoMatchError(err) {
|
||||
return nil, bcode.ErrCloudShellAddonNotEnabled
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
res.Status = StatusPreparing
|
||||
} else {
|
||||
if cloudShell.Status.Phase == v1alpha1.PhaseFailed {
|
||||
if err := c.KubeClient.Delete(ctx, &cloudShell); err != nil {
|
||||
log.Logger.Errorf("failed to clear the failed cloud shell:%s", err.Error())
|
||||
}
|
||||
res.Status = StatusFailed
|
||||
}
|
||||
if cloudShell.Status.Phase == v1alpha1.PhaseReady {
|
||||
res.Status = StatusCompleted
|
||||
} else {
|
||||
res.Status = StatusPreparing
|
||||
res.Message = fmt.Sprintf("The phase is %s", cloudShell.Status.Phase)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (c *cloudShellServiceImpl) GetCloudShellEndpoint(ctx context.Context) (string, error) {
|
||||
var userName string
|
||||
if user := ctx.Value(&apisv1.CtxKeyUser); user != nil {
|
||||
if u, ok := user.(string); ok {
|
||||
userName = u
|
||||
}
|
||||
}
|
||||
if userName == "" {
|
||||
return "", bcode.ErrUnauthorized
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Second*10)
|
||||
defer cancel()
|
||||
var cloudShell v1alpha1.CloudShell
|
||||
if err := c.KubeClient.Get(ctx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: makeUserCloudShellName(userName)}, &cloudShell); err != nil {
|
||||
if meta.IsNoMatchError(err) {
|
||||
return "", bcode.ErrCloudShellAddonNotEnabled
|
||||
}
|
||||
if apierrors.IsNotFound(err) {
|
||||
return "", bcode.ErrCloudShellNotInit
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
return cloudShell.Status.AccessURL, nil
|
||||
}
|
||||
|
||||
// prepareKubeConfig prepare the user's kubeconfig
|
||||
func (c *cloudShellServiceImpl) prepareKubeConfig(ctx context.Context) error {
|
||||
var userName string
|
||||
if user := ctx.Value(&apisv1.CtxKeyUser); user != nil {
|
||||
if u, ok := user.(string); ok {
|
||||
userName = u
|
||||
}
|
||||
}
|
||||
if userName == "" {
|
||||
return bcode.ErrUnauthorized
|
||||
}
|
||||
user, _ := c.UserService.GetUser(ctx, userName)
|
||||
if user == nil {
|
||||
return bcode.ErrUnauthorized
|
||||
}
|
||||
projects, err := c.ProjectService.ListUserProjects(ctx, userName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var groups []string
|
||||
for _, p := range projects {
|
||||
permissions, err := c.RBACService.GetUserPermissions(ctx, user, p.Name, false)
|
||||
var readOnly bool
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to get the user permissions %s", err.Error())
|
||||
readOnly = true
|
||||
} else {
|
||||
readOnly = checkReadOnly(p.Name, permissions)
|
||||
}
|
||||
if readOnly {
|
||||
// TODO:(@barnettZQG) there needs a method to revoke the privileges
|
||||
if err := c.managePrivilegesForUser(ctx, p.Name, true, userName, false); err != nil {
|
||||
log.Logger.Errorf("failed to privileges the user %s", err.Error())
|
||||
}
|
||||
} else {
|
||||
groups = append(groups, utils.KubeVelaProjectGroupPrefix+p.Name)
|
||||
}
|
||||
}
|
||||
|
||||
if utils.StringsContain(user.UserRoles, "admin") {
|
||||
groups = append(groups, utils.KubeVelaAdminGroupPrefix+"admin")
|
||||
}
|
||||
|
||||
cli, err := kubernetes.NewForConfig(c.KubeConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cfg, err := clientcmd.NewDefaultPathOptions().GetStartingConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(cfg.Clusters) == 0 {
|
||||
caFromServiceAccount, err := os.ReadFile(CAFilePathInCluster)
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to read the ca file from the service account dir,%s", err.Error())
|
||||
return err
|
||||
}
|
||||
cfg.Clusters = map[string]*api.Cluster{
|
||||
"local": {
|
||||
CertificateAuthorityData: caFromServiceAccount,
|
||||
Server: ServerAddressInCluster,
|
||||
},
|
||||
}
|
||||
}
|
||||
for k := range cfg.Clusters {
|
||||
cfg.Clusters[k].Server = ServerAddressInCluster
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
cfg, err = c.GenerateKubeConfig(ctx, cli, cfg, buffer, auth.KubeConfigWithIdentityGenerateOption(auth.Identity{
|
||||
User: userName,
|
||||
Groups: groups,
|
||||
}))
|
||||
if err != nil {
|
||||
log.Logger.Errorf("failed to generate the kube config:%s Message: %s", err.Error(), strings.ReplaceAll(buffer.String(), "\n", "\t"))
|
||||
return err
|
||||
}
|
||||
bs, err := clientcmd.Write(*cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cm := corev1.ConfigMap{}
|
||||
cm.Name = makeUserConfigName(userName)
|
||||
cm.Namespace = kubevelatypes.DefaultKubeVelaNS
|
||||
cm.Labels = map[string]string{
|
||||
DefaultLabelKey: "kubeconfig",
|
||||
}
|
||||
identityByte, _ := yaml.Marshal(auth.Identity{
|
||||
User: userName,
|
||||
Groups: groups,
|
||||
})
|
||||
cm.Data = map[string]string{
|
||||
"config": string(bs),
|
||||
"identity": string(identityByte),
|
||||
}
|
||||
|
||||
// mount the token for requesting the API
|
||||
if tokenV := ctx.Value(&apisv1.CtxKeyToken); tokenV != nil {
|
||||
if u, ok := tokenV.(string); ok {
|
||||
cm.Data["token"] = u
|
||||
}
|
||||
}
|
||||
|
||||
var exist = &corev1.ConfigMap{}
|
||||
if c.KubeClient.Get(ctx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: cm.Name}, exist) == nil {
|
||||
if exist.Data == nil {
|
||||
cm.Data = map[string]string{}
|
||||
}
|
||||
exist.Data["config"] = string(bs)
|
||||
return c.KubeClient.Update(ctx, &cm)
|
||||
}
|
||||
return c.KubeClient.Create(ctx, &cm)
|
||||
}
|
||||
|
||||
func makeUserConfigName(userName string) string {
|
||||
return fmt.Sprintf("users-%s-kubeconfig", userName)
|
||||
}
|
||||
|
||||
func makeUserCloudShellName(userName string) string {
|
||||
return fmt.Sprintf("users-%s", userName)
|
||||
}
|
||||
|
||||
func (c *cloudShellServiceImpl) newCloudShell(ctx context.Context) (*v1alpha1.CloudShell, error) {
|
||||
var userName string
|
||||
if user := ctx.Value(&apisv1.CtxKeyUser); user != nil {
|
||||
if u, ok := user.(string); ok {
|
||||
userName = u
|
||||
}
|
||||
}
|
||||
if userName == "" {
|
||||
return nil, bcode.ErrUnauthorized
|
||||
}
|
||||
var cs v1alpha1.CloudShell
|
||||
cs.Name = fmt.Sprintf("users-%s", userName)
|
||||
cs.Namespace = kubevelatypes.DefaultKubeVelaNS
|
||||
cs.Labels = map[string]string{
|
||||
DefaultLabelKey: "cloudshell",
|
||||
}
|
||||
cs.Spec.ConfigmapName = makeUserConfigName(userName)
|
||||
cs.Spec.RunAsUser = userName
|
||||
// only one client and exit on disconnection
|
||||
once, _ := strconv.ParseBool(os.Getenv("CLOUDSHELL_ONCE"))
|
||||
cs.Spec.Once = once
|
||||
cs.Spec.Cleanup = true
|
||||
// A cloudshell instance can live for a maximum of 60 minutes.
|
||||
cs.Spec.Ttl = 60 * 60
|
||||
cs.Spec.CommandAction = DefaultCloudShellCommand
|
||||
cs.Spec.ExposeMode = v1alpha1.ExposureServiceClusterIP
|
||||
cs.Spec.PathPrefix = DefaultCloudShellPathPrefix
|
||||
return &cs, nil
|
||||
}
|
||||
|
||||
func checkReadOnly(projectName string, permissions []*model.Permission) bool {
|
||||
ra := &RequestResourceAction{}
|
||||
ra.SetResourceWithName("project:{projectName}/application:*", func(name string) string {
|
||||
return projectName
|
||||
})
|
||||
ra.SetActions([]string{"deploy"})
|
||||
return !ra.Match(permissions)
|
||||
}
|
||||
|
||||
// managePrivilegesForUser grant or revoke privileges for a user
|
||||
func (c *cloudShellServiceImpl) managePrivilegesForUser(ctx context.Context, projectName string, readOnly bool, userName string, revoke bool) error {
|
||||
targets, err := c.TargetService.ListTargets(ctx, 0, 0, projectName)
|
||||
if err != nil {
|
||||
log.Logger.Infof("failed to list the targets by the project name %s :%s", projectName, err.Error())
|
||||
}
|
||||
var authPDs []auth.PrivilegeDescription
|
||||
for _, t := range targets.Targets {
|
||||
authPDs = append(authPDs, &auth.ScopedPrivilege{Cluster: t.Cluster.ClusterName, Namespace: t.Cluster.Namespace, ReadOnly: readOnly})
|
||||
}
|
||||
envs, err := c.EnvService.ListEnvs(ctx, 0, 0, apisv1.ListEnvOptions{Project: projectName})
|
||||
if err != nil {
|
||||
log.Logger.Infof("failed to list the envs by the project name %s :%s", projectName, err.Error())
|
||||
}
|
||||
for _, e := range envs.Envs {
|
||||
authPDs = append(authPDs, &auth.ApplicationPrivilege{Cluster: kubevelatypes.ClusterLocalName, Namespace: e.Namespace, ReadOnly: readOnly})
|
||||
}
|
||||
|
||||
identity := &auth.Identity{User: userName}
|
||||
writer := &bytes.Buffer{}
|
||||
f, msg := auth.GrantPrivileges, "GrantPrivileges"
|
||||
if revoke {
|
||||
f, msg = auth.RevokePrivileges, "RevokePrivileges"
|
||||
}
|
||||
if err := f(ctx, c.KubeClient, authPDs, identity, writer); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Logger.Debugf("%s: %s", msg, writer.String())
|
||||
return nil
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
Copyright 2022 The KubeVela Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"time"
|
||||
|
||||
v1alpha1 "github.com/cloudtty/cloudtty/pkg/apis/cloudshell/v1alpha1"
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbacv1 "k8s.io/api/rbac/v1"
|
||||
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
|
||||
"sigs.k8s.io/yaml"
|
||||
|
||||
kubevelatypes "github.com/oam-dev/kubevela/apis/types"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/domain/model"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/infrastructure/datastore"
|
||||
apisv1 "github.com/oam-dev/kubevela/pkg/apiserver/interfaces/api/dto/v1"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils"
|
||||
"github.com/oam-dev/kubevela/pkg/apiserver/utils/bcode"
|
||||
"github.com/oam-dev/kubevela/pkg/auth"
|
||||
)
|
||||
|
||||
var _ = Describe("Test cloudshell service function", func() {
|
||||
var (
|
||||
ds datastore.DataStore
|
||||
cloudShellService *cloudShellServiceImpl
|
||||
userService *userServiceImpl
|
||||
projectService *projectServiceImpl
|
||||
err error
|
||||
database string
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
database = "cloudshell-test-kubevela"
|
||||
ds, err = NewDatastore(datastore.Config{Type: "kubeapi", Database: database})
|
||||
Expect(err).Should(Succeed())
|
||||
envService := &envServiceImpl{
|
||||
Store: ds,
|
||||
KubeClient: k8sClient,
|
||||
}
|
||||
userService = &userServiceImpl{
|
||||
Store: ds,
|
||||
SysService: &systemInfoServiceImpl{Store: ds},
|
||||
ProjectService: projectService,
|
||||
}
|
||||
projectService = &projectServiceImpl{
|
||||
Store: ds,
|
||||
RbacService: &rbacServiceImpl{
|
||||
Store: ds,
|
||||
},
|
||||
TargetService: &targetServiceImpl{
|
||||
Store: ds,
|
||||
K8sClient: k8sClient,
|
||||
},
|
||||
EnvService: envService,
|
||||
UserService: userService,
|
||||
}
|
||||
userService.ProjectService = projectService
|
||||
userService.RbacService = projectService.RbacService
|
||||
envService.ProjectService = projectService
|
||||
|
||||
cloudShellService = &cloudShellServiceImpl{
|
||||
KubeClient: k8sClient,
|
||||
KubeConfig: cfg,
|
||||
ProjectService: projectService,
|
||||
TargetService: &targetServiceImpl{
|
||||
Store: ds,
|
||||
K8sClient: k8sClient,
|
||||
},
|
||||
EnvService: envService,
|
||||
UserService: userService,
|
||||
RBACService: projectService.RbacService,
|
||||
GenerateKubeConfig: func(ctx context.Context, cli kubernetes.Interface, cfg *clientcmdapi.Config, writer io.Writer, options ...auth.KubeConfigGenerateOption) (*clientcmdapi.Config, error) {
|
||||
return &clientcmdapi.Config{}, nil
|
||||
},
|
||||
}
|
||||
})
|
||||
|
||||
It("test prepareKubeConfig", func() {
|
||||
err = userService.Init(context.TODO())
|
||||
Expect(err).Should(BeNil())
|
||||
err = projectService.Init(context.TODO())
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("test the developer users")
|
||||
|
||||
_, err = userService.CreateUser(context.TODO(), apisv1.CreateUserRequest{Name: "test-dev", Password: "test"})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
_, err = projectService.AddProjectUser(context.TODO(), "default", apisv1.AddProjectUserRequest{
|
||||
UserName: "test-dev",
|
||||
UserRoles: []string{"app-developer"},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
permissions, err := projectService.RbacService.GetUserPermissions(context.TODO(), &model.User{Name: "test-dev"}, "default", false)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(checkReadOnly("default", permissions)).Should(BeFalse())
|
||||
|
||||
ctx := context.WithValue(context.TODO(), &apisv1.CtxKeyUser, "test-dev")
|
||||
|
||||
err = cloudShellService.prepareKubeConfig(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
var rb rbacv1.RoleBinding
|
||||
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "kubevela:writer:application:binding", Namespace: "default"}, &rb)
|
||||
Expect(err).Should(BeNil())
|
||||
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "kubevela:writer:binding", Namespace: "default"}, &rb)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("test the viewer users")
|
||||
|
||||
_, err = userService.CreateUser(context.TODO(), apisv1.CreateUserRequest{Name: "test-viewer", Password: "test"})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
_, err = projectService.AddProjectUser(context.TODO(), "default", apisv1.AddProjectUserRequest{
|
||||
UserName: "test-viewer",
|
||||
UserRoles: []string{"project-viewer"},
|
||||
})
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
permissions, err = projectService.RbacService.GetUserPermissions(ctx, &model.User{Name: "test-viewer"}, "default", false)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(checkReadOnly("default", permissions)).Should(BeTrue())
|
||||
|
||||
ctx = context.WithValue(context.TODO(), &apisv1.CtxKeyUser, "test-viewer")
|
||||
|
||||
err = cloudShellService.prepareKubeConfig(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "kubevela:reader:application:binding", Namespace: "default"}, &rb)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(rb.Subjects)).Should(Equal(1))
|
||||
Expect(rb.Subjects[0].Name).Should(Equal("test-viewer"))
|
||||
Expect(rb.Subjects[0].Kind).Should(Equal("User"))
|
||||
err = k8sClient.Get(context.Background(), types.NamespacedName{Name: "kubevela:reader:binding", Namespace: "default"}, &rb)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
By("test the administrator users")
|
||||
|
||||
_, err = userService.CreateUser(context.TODO(), apisv1.CreateUserRequest{Name: "admin-test", Password: "test", Roles: []string{"admin"}})
|
||||
Expect(err).Should(BeNil())
|
||||
ctx = context.WithValue(context.TODO(), &apisv1.CtxKeyUser, "admin-test")
|
||||
|
||||
err = cloudShellService.prepareKubeConfig(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
var cm corev1.ConfigMap
|
||||
err = k8sClient.Get(context.TODO(), types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: makeUserConfigName("admin-test")}, &cm)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(len(cm.Data["identity"]) > 0).Should(BeTrue())
|
||||
var identity auth.Identity
|
||||
err = yaml.Unmarshal([]byte(cm.Data["identity"]), &identity)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(utils.StringsContain(identity.Groups, utils.KubeVelaAdminGroupPrefix+"admin")).Should(BeTrue())
|
||||
})
|
||||
|
||||
It("test prepare", func() {
|
||||
By("With not CRD")
|
||||
_, err = userService.CreateUser(context.TODO(), apisv1.CreateUserRequest{Name: "test", Password: "test"})
|
||||
Expect(err).Should(BeNil())
|
||||
ctx := context.WithValue(context.TODO(), &apisv1.CtxKeyUser, "test")
|
||||
_, err := cloudShellService.Prepare(ctx)
|
||||
Expect(err).ShouldNot(BeNil())
|
||||
Expect(err.Error()).Should(Equal(bcode.ErrCloudShellAddonNotEnabled.Error()))
|
||||
|
||||
cloudshellCRDBytes, err := ioutil.ReadFile("./testdata/cloudshell-crd.yaml")
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
crd := apiextensionsv1.CustomResourceDefinition{}
|
||||
Expect(yaml.Unmarshal(cloudshellCRDBytes, &crd)).Should(BeNil())
|
||||
Expect(k8sClient.Create(context.TODO(), &crd)).Should(BeNil())
|
||||
|
||||
time.Sleep(2 * time.Second)
|
||||
re, err := cloudShellService.Prepare(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(re.Status).Should(Equal(StatusPreparing))
|
||||
|
||||
var cloudShell v1alpha1.CloudShell
|
||||
err = k8sClient.Get(ctx, types.NamespacedName{Namespace: kubevelatypes.DefaultKubeVelaNS, Name: makeUserCloudShellName("test")}, &cloudShell)
|
||||
Expect(err).Should(BeNil())
|
||||
cloudShell.Status.Phase = v1alpha1.PhaseReady
|
||||
cloudShell.Status.AccessURL = "10.10.1.1:8765"
|
||||
err = k8sClient.Status().Update(context.Background(), &cloudShell)
|
||||
Expect(err).Should(BeNil())
|
||||
|
||||
re, err = cloudShellService.Prepare(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(re.Status).Should(Equal(StatusCompleted))
|
||||
|
||||
endpoint, err := cloudShellService.GetCloudShellEndpoint(ctx)
|
||||
Expect(err).Should(BeNil())
|
||||
Expect(endpoint).Should(Equal("10.10.1.1:8765"))
|
||||
})
|
||||
})
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user