Compare commits

...

16 Commits

Author SHA1 Message Date
Jianbo Sun
52e3893bf3 Merge pull request #1114 from wonderflow/fix1
update CRD and fix workload not create first time
2021-03-01 17:58:11 +08:00
天元
419afd27b5 update CRD and fix workload not create first time 2021-03-01 15:05:19 +08:00
Jianbo Sun
52550bb7b5 parent override child when annotation/labels conflicts && one revision will apply once only in force mode && AC.status CRD updated (#1109)
* when annotation/labels passthrough from parent to child conflicts, the parent will override the child.
e.g. 1) AC will override its component/workload; 2) workload will override child-resource; 3) AC will override its trait

* apply once only force will block workload apply when revision not changed even ac generation updated
2021-02-28 22:38:18 -08:00
Jianbo Sun
d6f3f995cd Merge pull request #1111 from captainroy-hy/chp-1041
cherry-pick(1041&1036) fix unit test
2021-02-26 18:57:10 +08:00
roy wang
dc6ab6b8d6 fix unstable unit test
Signed-off-by: roywang <seiwy2010@gmail.com>
2021-02-26 19:18:15 +09:00
roywang
613f1f9b53 quick fix unstable unit test
Signed-off-by: roywang <seiwy2010@gmail.com>
2021-02-26 18:46:10 +09:00
Jianbo Sun
eefc72b0c6 Merge pull request #1099 from captainroy-hy/ut-apply-once
add unit test
2021-02-26 10:26:09 +08:00
Jianbo Sun
1ac66bb3e4 fix component custom revison loop infinitely create revision (#1101) 2021-02-24 23:50:45 -08:00
roywang
ac6d6d1a73 add unit test
Signed-off-by: roywang <seiwy2010@gmail.com>
2021-02-25 02:59:19 +09:00
Jianbo Sun
46f7472bd5 fix apply only once observedGeneration should mark after meet all dependency requirements && add log for apply only once (#1094) 2021-02-24 01:13:27 -08:00
Jianbo Sun
d872430b08 Merge pull request #1095 from wonderflow/cherryp
cherry-pick: remove go-header package dependency
2021-02-23 20:10:30 +08:00
天元
9d2cf16141 remove go-header package dependency 2021-02-23 19:14:57 +08:00
Jianbo Sun
8c9fab1aa1 Merge pull request #1096 from wonderflow/ci
enable CI for release-*
2021-02-23 19:12:44 +08:00
天元
e213779235 enable CI for release-* 2021-02-23 17:53:49 +08:00
Jianbo Sun
e4bf16b618 Merge pull request #1034 from oam-dev/master
merge master to release-0.3 align with v0.3.3
2021-02-07 17:49:09 +08:00
Jianbo Sun
9c64afa1f6 Merge pull request #982 from wonderflow/fix
bump #981 into release-0.3
2021-02-01 14:53:02 +08:00
28 changed files with 1271 additions and 298 deletions

View File

@@ -7,7 +7,9 @@ on:
- release-*
workflow_dispatch: {}
pull_request:
branches: [master]
branches:
- master
- release-*
env:
# Common versions

View File

@@ -412,6 +412,16 @@ type WorkloadTrait struct {
// Message will allow controller to leave some additional information for this trait
Message string `json:"message,omitempty"`
// AppliedGeneration indicates the generation observed by the appConfig controller.
// The same field is also recorded in the annotations of traits.
// A trait is possible to be deleted from cluster after created.
// This field is useful to track the observed generation of traits after they are
// deleted.
AppliedGeneration int64 `json:"appliedGeneration,omitempty"`
// DependencyUnsatisfied notify does the trait has dependency unsatisfied
DependencyUnsatisfied bool `json:"dependencyUnsatisfied,omitempty"`
}
// A ScopeStatus represents the state of a scope.
@@ -439,12 +449,11 @@ type WorkloadStatus struct {
// ComponentRevisionName of current component
ComponentRevisionName string `json:"componentRevisionName,omitempty"`
// ObservedGeneration indicates the generation observed by the appconfig controller.
// The same field is also recorded in the annotations of workloads.
// A workload is possible to be deleted from cluster after created.
// This field is useful to track the observed generation of workloads after they are
// deleted.
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
// DependencyUnsatisfied notify does the workload has dependency unsatisfied
DependencyUnsatisfied bool `json:"dependencyUnsatisfied,omitempty"`
// AppliedComponentRevision indicates the applied component revision name of this workload
AppliedComponentRevision string `json:"appliedComponentRevision,omitempty"`
// Reference to a workload created by an ApplicationConfiguration.
Reference runtimev1alpha1.TypedReference `json:"workloadRef,omitempty"`

View File

@@ -380,16 +380,18 @@ spec:
items:
description: A WorkloadStatus represents the status of a workload.
properties:
appliedComponentRevision:
description: AppliedComponentRevision indicates the applied component revision name of this workload
type: string
componentName:
description: ComponentName that produced this workload.
type: string
componentRevisionName:
description: ComponentRevisionName of current component
type: string
observedGeneration:
description: ObservedGeneration indicates the generation observed by the appconfig controller. The same field is also recorded in the annotations of workloads. A workload is possible to be deleted from cluster after created. This field is useful to track the observed generation of workloads after they are deleted.
format: int64
type: integer
dependencyUnsatisfied:
description: DependencyUnsatisfied notify does the workload has dependency unsatisfied
type: boolean
scopes:
description: Scopes associated with this workload.
items:
@@ -430,6 +432,13 @@ spec:
items:
description: A WorkloadTrait represents a trait associated with a workload and its status
properties:
appliedGeneration:
description: AppliedGeneration indicates the generation observed by the appConfig controller. The same field is also recorded in the annotations of traits. A trait is possible to be deleted from cluster after created. This field is useful to track the observed generation of traits after they are deleted.
format: int64
type: integer
dependencyUnsatisfied:
description: DependencyUnsatisfied notify does the trait has dependency unsatisfied
type: boolean
message:
description: Message will allow controller to leave some additional information for this trait
type: string

View File

@@ -127,7 +127,10 @@ func main() {
setupLog.Info(fmt.Sprintf("KubeVela Version: %s, GIT Revision: %s.", version.VelaVersion, version.GitRevision))
setupLog.Info(fmt.Sprintf("Disable Capabilities: %s.", disableCaps))
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
restConfig := ctrl.GetConfigOrDie()
restConfig.UserAgent = kubevelaName + "/" + version.GitRevision
mgr, err := ctrl.NewManager(restConfig, ctrl.Options{
Scheme: scheme,
MetricsBindAddress: metricsAddr,
LeaderElection: enableLeaderElection,

View File

@@ -130,8 +130,13 @@ The same mechanism also works for Trait as well as Workload.
### Apply Once Only Force
Based on the same mechanism as `apply-once-only`, `apply-once-only-force` allows to skip re-creating a workload or trait that has already been DELETED from the cluster if its spec is not changed.
It's regarded as a stronger case of `apply-once-only`.
Based on the same mechanism as `apply-once-only`, `apply-once-only-force` has a more strict method for apply only once.
It allows to skip re-creating a workload or trait that has already been DELETED from the cluster if its spec is not changed.
Besides the condition in `apply-once-only`, `apply-once-only-force` has one more condition:
- if the component revision not changed, the workload will not be applied.
## Usage

2
go.mod
View File

@@ -29,6 +29,7 @@ require (
github.com/google/go-github/v32 v32.1.0
github.com/gosuri/uitable v0.0.4
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174
github.com/klauspost/compress v1.10.5 // indirect
github.com/kyokomi/emoji v2.2.4+incompatible
github.com/mailru/easyjson v0.7.6 // indirect
github.com/mholt/archiver/v3 v3.3.0
@@ -38,7 +39,6 @@ require (
github.com/onsi/ginkgo v1.13.0
github.com/onsi/gomega v1.10.3
github.com/openkruise/kruise-api v0.7.0
github.com/openservicemesh/osm v0.3.0
github.com/pkg/errors v0.9.1
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b
github.com/spf13/cobra v1.1.1

74
go.sum
View File

@@ -81,7 +81,6 @@ git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGy
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/AlecAivazis/survey/v2 v2.1.1 h1:LEMbHE0pLj75faaVEKClEX1TM4AJmmnOh9eimREzLWI=
github.com/AlecAivazis/survey/v2 v2.1.1/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk=
github.com/AlekSi/gocov-xml v0.0.0-20190121064608-3a14fb1c4737/go.mod h1:w1KSuh2JgIL3nyRiZijboSUwbbxOrTzWwyWVFUHtXBQ=
github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU=
github.com/Azure/azure-pipeline-go v0.1.8/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
github.com/Azure/azure-pipeline-go v0.1.9/go.mod h1:XA1kFWRVhSK+KNFiOhfv83Fv8L9achrP7OxIzeTn1Yg=
@@ -95,7 +94,6 @@ github.com/Azure/azure-sdk-for-go v23.2.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
github.com/Azure/azure-sdk-for-go v28.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v29.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v30.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v34.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
@@ -127,9 +125,7 @@ github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMl
github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/adal v0.8.3 h1:O1AGG9Xig71FxdX9HO5pGNyZ7TbSyHaVg+5eJO/jSGw=
github.com/Azure/go-autorest/autorest/adal v0.8.3/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
github.com/Azure/go-autorest/autorest/azure/auth v0.1.0/go.mod h1:Gf7/i2FUpyb/sGBLIFxTBzrNzBo7aPXXE3ZVeDRwdpM=
github.com/Azure/go-autorest/autorest/azure/auth v0.4.2/go.mod h1:90gmfKdlmKgfjUpnCEpOJzsUEjrWDSLwHIG73tSXddM=
github.com/Azure/go-autorest/autorest/azure/cli v0.1.0/go.mod h1:Dk8CUAt/b/PzkfeRsWzVG9Yj3ps8mS8ECztu43rdU8U=
github.com/Azure/go-autorest/autorest/azure/cli v0.3.1/go.mod h1:ZG5p860J94/0kI9mNJVoIoLgXcirM2gF5i2kWloofxw=
github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSWlm5Ew6bxipnr/tbM=
@@ -161,7 +157,6 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3
github.com/DataDog/zstd v1.3.6-0.20190409195224-796139022798/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
github.com/Djarvur/go-err113 v0.0.0-20200410182137-af658d038157/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
github.com/Djarvur/go-err113 v0.0.0-20200511133814-5174e21577d5/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
github.com/Djarvur/go-err113 v0.1.0/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
github.com/GoogleCloudPlatform/cloud-builders/gcs-fetcher v0.0.0-20191203181535-308b93ad1f39/go.mod h1:yfGmCjKuUzk9WzubMlW2zwjhCraIc/J+M40cufdemRM=
github.com/GoogleCloudPlatform/cloudsql-proxy v0.0.0-20191009163259-e802c2cb94ae/go.mod h1:mjwGPas4yKduTyubHvD1Atl9r1rUq8DfVy+gkVvZ+oo=
@@ -284,7 +279,6 @@ github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU
github.com/aws/aws-sdk-go v1.31.12 h1:SxRRGyhlCagI0DYkhOg+FgdXGXzRTE3vEX/gsgFaiKQ=
github.com/aws/aws-sdk-go v1.31.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/axw/gocov v1.0.0/go.mod h1:LvQpEYiwwIb2nYkXY2fDWhg9/AsYqkhmrCshjlUJECE=
github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f/go.mod h1:AuiFmCCPBSrqvVMvuqFuk0qogytodnVFVSN5CeJB8Gc=
github.com/bazelbuild/buildtools v0.0.0-20190917191645-69366ca98f89/go.mod h1:5JP0TXzWDHXv8qvxRC4InIazwdyDseBDbzESUMKk1yU=
@@ -361,8 +355,6 @@ github.com/cloudevents/sdk-go v0.0.0-20190509003705-56931988abe3/go.mod h1:j1nZW
github.com/cloudevents/sdk-go v1.0.0/go.mod h1:3TkmM0cFqkhCHOq5JzzRU/RxRkwzoS8TZ+G448qVTog=
github.com/cloudevents/sdk-go/v2 v2.0.0/go.mod h1:3CTrpB4+u7Iaj6fd7E2Xvm5IxMdRoaAhqaRVnOr2rCU=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200313221541-5f7e5dd04533/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/cockroachdb/apd/v2 v2.0.1 h1:y1Rh3tEU89D+7Tgbw+lp52T6p/GJLpDmNvr10UWqLTE=
@@ -419,7 +411,6 @@ github.com/crossplane/crossplane-runtime v0.10.0 h1:H8YvMcrm1uzZYpwU/BpxjRQfceVu
github.com/crossplane/crossplane-runtime v0.10.0/go.mod h1:cJl5ZZONisre4v6wTmbrC8Jh3AI+erq/lNaxZzv9tnU=
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/daixiang0/gci v0.0.0-20200727065011-66f1df783cb2/go.mod h1:+AV8KmHTGxxwp/pY84TLQfFKp2vuKXXJVzF3kD/hfR4=
github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -430,7 +421,6 @@ github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9r
github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
github.com/deislabs/oras v0.8.1 h1:If674KraJVpujYR00rzdi0QAmW4BxzMJPVAZJKuhQ0c=
github.com/deislabs/oras v0.8.1/go.mod h1:Mx0rMSbBNaNfY9hjpccEnxkOqJL6KGjtxNHPLC4G4As=
github.com/denis-tingajkin/go-header v0.3.1/go.mod h1:sq/2IxMhaZX+RRcgHfCRx/m0M5na0fBt4/CRe7Lrji0=
github.com/denisenkom/go-mssqldb v0.0.0-20190111225525-2fea367d496d/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
github.com/denisenkom/go-mssqldb v0.0.0-20191001013358-cfbb681360f0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
@@ -504,7 +494,6 @@ github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4s
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.6/go.mod h1:GFqM7v0B62MraO4PWRedIbhThr/Rf7ev6aHOOPXeaDA=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -522,7 +511,6 @@ github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
@@ -569,7 +557,6 @@ github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1T
github.com/go-bindata/go-bindata/v3 v3.1.3/go.mod h1:1/zrpXsLD8YDIbhZRqXzm1Ghc7NhEvIN9+Z6R5/xH4I=
github.com/go-critic/go-critic v0.4.1/go.mod h1:7/14rZGnZbY6E38VEGk2kVhoq6itzc1E68facVDK23g=
github.com/go-critic/go-critic v0.4.3/go.mod h1:j4O3D4RoIwRqlZw5jJpx0BNfXWWbpcJoKu5cYSe4YmQ=
github.com/go-critic/go-critic v0.5.0/go.mod h1:4jeRh3ZAVnRYhuWdOEvwzVqLUpxMSoAT0xZ74JsTPlo=
github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
github.com/go-git/go-billy/v5 v5.0.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
github.com/go-git/go-git-fixtures/v4 v4.0.1/go.mod h1:m+ICp2rF3jDhFgEZ/8yziagdT1C+ZpZcrJjappBCDSw=
@@ -583,7 +570,6 @@ github.com/go-ini/ini v1.55.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3I
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc=
github.com/go-lintpack/lintpack v0.5.2/go.mod h1:NwZuYi2nUHho8XEIZ6SIxihrnPoqBTDqfpXvXAN0sXM=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
@@ -703,7 +689,6 @@ github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/go-toolsmith/astcast v1.0.0/go.mod h1:mt2OdQTeAQcY4DQgPSArJjHCcOwlX+Wl/kwN+LbLGQ4=
github.com/go-toolsmith/astcopy v1.0.0/go.mod h1:vrgyG+5Bxrnz4MZWPF+pI4R8h3qKRjjyvV/DSez4WVQ=
@@ -831,7 +816,6 @@ github.com/golangci/gocyclo v0.0.0-20180528144436-0a533e8fa43d/go.mod h1:ozx7R9S
github.com/golangci/gofmt v0.0.0-20190930125516-244bba706f1a/go.mod h1:9qCChq59u/eW8im404Q2WWTrnBUQKjpNYKMbU4M7EFU=
github.com/golangci/golangci-lint v1.23.7/go.mod h1:g/38bxfhp4rI7zeWSxcdIeHTQGS58TCak8FYcyCmavQ=
github.com/golangci/golangci-lint v1.27.0/go.mod h1:+eZALfxIuthdrHPtfM7w/R3POJLjHDfJJw8XZl9xOng=
github.com/golangci/golangci-lint v1.30.0/go.mod h1:5t0i3wHlqQc9deBBvZsP+a/4xz7cfjV+zhp5U0Mzp14=
github.com/golangci/ineffassign v0.0.0-20190609212857-42439a7714cc/go.mod h1:e5tpTHCfVze+7EpLEozzMB3eafxo2KT5veNg1k6byQU=
github.com/golangci/lint-1 v0.0.0-20191013205115-297bf364a8e0/go.mod h1:66R6K6P6VWk9I95jvqGxkqJxVWGFy9XlDwLwVz1RCFg=
github.com/golangci/maligned v0.0.0-20180506175553-b1d89398deca/go.mod h1:tvlJhZqDe4LMs4ZHD0oMUlt9G2LWuDGoisJTBzLMV9o=
@@ -932,14 +916,12 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
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=
github.com/googleapis/gnostic v0.2.0/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
github.com/googleapis/gnostic v0.3.1 h1:WeAefnSUHlBb0iJKwxFDZdbfGwkd7xRNuV+IpXMJhYk=
github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/googleapis/gnostic v0.4.0 h1:BXDUo8p/DaxC+4FJY/SSx3gvnx9C1VdHNgaUkiEL5mk=
github.com/googleapis/gnostic v0.4.0/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1awfrALZdbtU=
github.com/gookit/color v1.2.4/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
github.com/gookit/color v1.2.5/go.mod h1:AhIE+pS6D4Ql0SQWbBeXPHw7gY0/sjHoA4s/n1KB7xg=
github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gophercloud/gophercloud v0.3.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
@@ -1012,8 +994,6 @@ github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVo
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-getter v1.4.0 h1:ENHNi8494porjD0ZhIrjlAHnveSFhY7hvOJrV/fsKkw=
github.com/hashicorp/go-getter v1.4.0/go.mod h1:7qxyCd8rBfcShwsvxgIguu4KbS3l8bUCwg2Umn7RjeY=
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
github.com/hashicorp/go-hclog v0.8.0/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-hclog v0.12.2/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
@@ -1027,9 +1007,7 @@ github.com/hashicorp/go-multierror v0.0.0-20171204182908-b7773ae21874/go.mod h1:
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-plugin v1.0.1/go.mod h1:++UyYGoz3o5w9ZzAdZxtQKrWWP+iqPBn3cQptSMzBuY=
github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.5.4/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs=
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
@@ -1045,7 +1023,6 @@ github.com/hashicorp/go-sockaddr v1.0.2/go.mod h1:rB4wwRAUzs07qva3c5SdrY/NEtAUjG
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.0.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.1.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.2.0 h1:3vNe/fWF5CBgRIguda1meWhsZHy3m8gCJ5wx+dIzX/E=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
@@ -1069,12 +1046,6 @@ github.com/hashicorp/memberlist v0.2.0/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOn
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hashicorp/serf v0.8.5/go.mod h1:UpNcs7fFbpKIyZaUuSW6EPiH+eZC7OuyFD+wc1oal+k=
github.com/hashicorp/serf v0.9.0/go.mod h1:YL0HO+FifKOW2u1ke99DGVu1zhcpZzNwrLIqBC7vbYU=
github.com/hashicorp/vault/api v1.0.4 h1:j08Or/wryXT4AcHj1oCbMd7IijXcKzYUGw59LGu9onU=
github.com/hashicorp/vault/api v1.0.4/go.mod h1:gDcqh3WGcR1cpF5AJz/B1UFheUEneMoIospckxBxk6Q=
github.com/hashicorp/vault/sdk v0.1.13 h1:mOEPeOhT7jl0J4AMl1E705+BcmeRs1VmKNb9F0sMLy8=
github.com/hashicorp/vault/sdk v0.1.13/go.mod h1:B+hVj7TpuQY1Y/GPbCpffmgd+tSEwvhkWnjtSYCaS2M=
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174 h1:WlZsjVhE8Af9IcZDGgJGQpNflI3+MJSBhsgT5PCtzBQ=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
@@ -1118,7 +1089,6 @@ github.com/jenkins-x/go-scm v1.5.117/go.mod h1:PCT338UhP/pQ0IeEeMEf/hoLTYKcH7qjG
github.com/jessevdk/go-flags v0.0.0-20180331124232-1c38ed7ad0cc/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s=
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
github.com/jinzhu/gorm v0.0.0-20170316141641-572d0a0ab1eb/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
github.com/jinzhu/gorm v1.9.12/go.mod h1:vhTjlKSJUTWNtcbQtrMBFCxy7eXTzeCAzfL5fBZT/Qs=
github.com/jinzhu/inflection v0.0.0-20190603042836-f5c5f50e6090/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
@@ -1183,7 +1153,6 @@ github.com/klauspost/compress v1.9.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0
github.com/klauspost/compress v1.9.5 h1:U+CaK85mrNNb4k8BNOfgJtJ/gr6kswUCFj6miSzVC6M=
github.com/klauspost/compress v1.9.5/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.10.2/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.10.5 h1:7q6vHIqubShURwQz8cQK6yIe/xC3IF0Vm7TGfqjewrc=
github.com/klauspost/compress v1.10.5/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
@@ -1222,7 +1191,6 @@ github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LE
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/kyoh86/exportloopref v0.1.7/go.mod h1:h1rDl2Kdj97+Kwh4gdz3ujE7XHmH51Q0lUiZ1z4NLj8=
github.com/kyokomi/emoji v2.2.4+incompatible h1:np0woGKwx9LiHAQmwZx79Oc0rHpNw3o+3evou4BEPv4=
github.com/kyokomi/emoji v2.2.4+incompatible/go.mod h1:mZ6aGCD7yk8j6QY6KICwnZ2pxoszVseX1DNoGtU2tBA=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
@@ -1267,7 +1235,6 @@ github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzfe
github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
github.com/matm/gocov-html v0.0.0-20200509184451-71874e2e203b/go.mod h1:zha4ZSIA/qviBBKx3j6tJG/Lx6aIdjOXPWuKAcJchQM=
github.com/matoous/godox v0.0.0-20190911065817-5d6d842e92eb/go.mod h1:1BELzlh859Sh1c6+90blK8lbYy0kwQf1bYlBhBysy1s=
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -1340,16 +1307,12 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/gox v0.4.0 h1:lfGJxY7ToLJQjHHwi0EX6uYBdK78egf954SQl13PQJc=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/gox v1.0.1 h1:x0jD3dcHk9a9xPSDN6YEL4xL6Qz0dvNYm8yZqui5chI=
github.com/mitchellh/gox v1.0.1/go.mod h1:ED6BioOGXMswlXa2zxfh/xdd5QhwYliBFn9V18Ap4z4=
github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452 h1:hOY53G+kBFhbYFpRVxHl5eS7laP6B1+Cq+Z9Dry1iMU=
github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
github.com/mitchellh/hashstructure/v2 v2.0.1 h1:L60q1+q7cXE4JeEJJKMnh2brFIe3rZxCihYAB61ypAY=
@@ -1408,7 +1371,6 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96d
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nishanths/exhaustive v0.0.0-20200708172631-8866003e3856/go.mod h1:wBEpHwM2OdmeNpdCvRPUlkEbBuaFmcK4Wv8Q7FuGW3c=
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
@@ -1474,8 +1436,6 @@ github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.m
github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mod h1:r3f7wjNzSs2extwzU3Y+6pKfobzPh+kKFJ3ofN+3nfs=
github.com/openkruise/kruise-api v0.7.0 h1:BBQotEfeZ2l1+R0uvlsVK2FN8C4RTlG+JT86ba2hOR4=
github.com/openkruise/kruise-api v0.7.0/go.mod h1:nCf5vVOjQJX5OaV7Qi0Z51/Rn9cd7s5kVrg8YLgFp1I=
github.com/openservicemesh/osm v0.3.0 h1:U88Nv1xm+7M+xYNkwjYVU6WSMp3MHIObTcO+gH20nOw=
github.com/openservicemesh/osm v0.3.0/go.mod h1:gyK0vN5ENnP26Y8huqgeTR52fOotZhnEorie215FnpU=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing-contrib/go-stdlib v0.0.0-20190519235532-cf7a6c988dc9/go.mod h1:PLldrQSroqzH70Xl+1DQcGnefIbqsKR7UDaiux3zV+w=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
@@ -1516,7 +1476,6 @@ github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4 v2.2.6+incompatible h1:6aCX4/YZ9v8q69hTyiR7dNLnTA3fgtKHVVW5BCd5Znw=
github.com/pierrec/lz4 v2.2.6+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/browser v0.0.0-20180916011732-0a3d74bf9ce4/go.mod h1:4OwLy04Bl9Ef3GJJCoec+30X3LQs/0/m4HFRt/2LUSA=
github.com/pkg/errors v0.0.0-20180311214515-816c9085562c/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -1606,7 +1565,6 @@ github.com/prometheus/statsd_exporter v0.15.0/go.mod h1:Dv8HnkoLQkeEjkIE4/2ndAA7
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/quasilyte/go-consistent v0.0.0-20190521200055-c6f3937de18c/go.mod h1:5STLWrekHfjyYwxBRVRXNOSewLJ3PWfDJd1VyTS21fI=
github.com/quasilyte/go-ruleguard v0.1.2-0.20200318202121-b00d7a75d3d8/go.mod h1:CGFX09Ci3pq9QZdj86B+VGIdNj4VyCo2iPOGS9esB/k=
github.com/quasilyte/regex/syntax v0.0.0-20200407221936-30656e2c4a95/go.mod h1:rlzQ04UMyJXu/aOvhd8qT+hvDrFpiwqp8MRXDY9szc0=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20190706150252-9beb055b7962/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
@@ -1624,9 +1582,6 @@ github.com/rogpeppe/go-internal v1.5.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
github.com/rogpeppe/go-internal v1.6.0 h1:IZRgg4sfrDH7nsAD1Y/Nwj+GzIfEwpJSLjCaNC3SbsI=
github.com/rogpeppe/go-internal v1.6.0/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1 h1:mhH9Nq+C1fY2l1XIpgxIiUOfNpRBYH1kKcr+qfKgjRc=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.18.0/go.mod h1:9nvC1axdVrAHcu/s9taAVfBuIdTZLVQmKQyvrUjF5+I=
github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3 h1:xkBtI5JktwbW/vf4vopBbhYsRFTGfQWHYXzC0/qYwxI=
github.com/rubenv/sql-migrate v0.0.0-20200212082348-64f95ea68aa3/go.mod h1:rtQlpHw+eR6UrqaS3kX1VYeaCxzCVdimDS7g5Ln4pPc=
github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
@@ -1636,11 +1591,8 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryancurrah/gomodguard v1.0.4/go.mod h1:9T/Cfuxs5StfsocWr4WzDL36HqnX0fVb9d5fSEaLhoE=
github.com/ryancurrah/gomodguard v1.1.0/go.mod h1:4O8tr7hBODaGE6VIhfJDHcwzh5GUccKSJBU0UMXJFVM=
github.com/ryanrolds/sqlclosecheck v0.3.0/go.mod h1:1gREqxyTGR3lVtpngyFo3hZAgk0KCtEdgEkHwDbigdA=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/ryanuber/go-glob v1.0.0 h1:iQh3xXAumdQ+4Ufa5b25cRpC5TYKlno6hsv6Cb3pkBk=
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
github.com/samuel/go-zookeeper v0.0.0-20190810000440-0ceca61e4d75/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
@@ -1657,13 +1609,10 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
github.com/securego/gosec v0.0.0-20200103095621-79fbf3af8d83/go.mod h1:vvbZ2Ae7AzSq3/kywjUDxSNq2SJ27RxCz2un0H3ePqE=
github.com/securego/gosec v0.0.0-20200401082031-e946c8c39989/go.mod h1:i9l/TNj+yDFh9SZXUTvspXTjbFXgZGP/UvhU1S65A4A=
github.com/securego/gosec/v2 v2.3.0/go.mod h1:UzeVyUXbxukhLeHKV3VVqo7HdoQR9MrRfFmZYotn8ME=
github.com/securego/gosec/v2 v2.4.0/go.mod h1:0/Q4cjmlFDfDUj1+Fib61sc+U5IQb2w+Iv9/C3wPVko=
github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/servicemeshinterface/smi-sdk-go v0.4.1/go.mod h1:9rsLPBNcqfDNmEgyYwpopn93aE9yz46d2EHFBNOYj/w=
github.com/shazow/go-diff v0.0.0-20160112020656-b6b7b6733b8c/go.mod h1:/PevMnwAxekIXwN8qQyfc5gl2NlkB3CQlkizAbOkeBs=
github.com/shirou/gopsutil v0.0.0-20190901111213-e4ec7b275ada/go.mod h1:WWnYX4lzhCH5h/3YBfyVA3VbLYjlMZZAQcW9ojMexNc=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shurcooL/githubv4 v0.0.0-20180925043049-51d7b505e2e9/go.mod h1:hAF0iLZy4td2EX+/8Tw+4nodhlMrwN3HupfaXj3zkGo=
@@ -1699,7 +1648,6 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9
github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
github.com/soheilhy/cmux v0.1.3/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sonatard/noctx v0.0.1/go.mod h1:9D2D/EoULe8Yy2joDHJj7bv3sZoq9AaSb8B4lqBjiZI=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/sourcegraph/go-diff v0.5.1/go.mod h1:j2dHj3m8aZgQO8lMTcTnBcXkRRRqi34cd2MNlA9u1mE=
github.com/sourcegraph/go-diff v0.5.3/go.mod h1:v9JDtjCE4HHHCZGId75rg8gkKKa98RVjBcBGsVmMmak=
@@ -1737,7 +1685,6 @@ github.com/spf13/viper v1.6.1/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfD
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jWoI=
github.com/ssgreg/nlreturn/v2 v2.0.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
@@ -1754,8 +1701,6 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
@@ -1780,7 +1725,6 @@ github.com/tektoncd/plumbing v0.0.0-20200430135134-e53521e1d887/go.mod h1:cZPJIe
github.com/tektoncd/plumbing/pipelinerun-logs v0.0.0-20191206114338-712d544c2c21/go.mod h1:S62EUWtqmejjJgUMOGB1CCCHRp6C706laH06BoALkzU=
github.com/tetafro/godot v0.3.7/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0=
github.com/tetafro/godot v0.4.2/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0=
github.com/tetafro/godot v0.4.8/go.mod h1:/7NLHhv08H1+8DNj0MElpAACw1ajsCuf3TKNQxA5S+0=
github.com/thanos-io/thanos v0.11.0/go.mod h1:N/Yes7J68KqvmY+xM6J5CJqEvWIvKSR5sqGtmuD6wDc=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/timakin/bodyclose v0.0.0-20190930140734-f7f2e9bca95e/go.mod h1:Qimiffbc6q9tBWlVV6x0P9sat/ao1xEkREYPPj9hphk=
@@ -1836,9 +1780,7 @@ github.com/uudashr/gocognit v1.0.1/go.mod h1:j44Ayx2KW4+oB6SWMv8KsmHzZrOInQav7D3
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.2.0/go.mod h1:4vX61m6KN+xDduDNwXrhIAVZaZaZiQ1luJk8LWSxF3s=
github.com/valyala/fasthttp v1.12.0/go.mod h1:229t1eWu9UXTPmoUkbpN/fctKPBY4IJoFXQnxHGXy6E=
github.com/valyala/quicktemplate v1.2.0/go.mod h1:EH+4AkTd43SvgIbQHYu59/cJyxDoOVRUAfrukLPuGJ4=
github.com/valyala/quicktemplate v1.5.1/go.mod h1:v7yYWpBEiutDyNfVaph6oC/yKwejzVyTX/2cwwHxyok=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo=
github.com/vdemeester/k8s-pkg-credentialprovider v1.13.12-1/go.mod h1:Fko0rTxEtDW2kju5Ky7yFJNS3IcNvW8IPsp4/e9oev0=
@@ -1882,7 +1824,6 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMzt
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs=
github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0=
go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk=
@@ -1959,7 +1900,6 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20190320223903-b7391e95e576/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190404164418-38d8ce5564a5/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190418165655-df01cb2cc480/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -2204,7 +2144,6 @@ golang.org/x/tools v0.0.0-20190729092621-ff9f1409240a/go.mod h1:jcCCGcm9btYwXyDq
golang.org/x/tools v0.0.0-20190807223507-b346f7fd45de/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190813034749-528a2984e271/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190910044552-dd2b5c81c578/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -2238,7 +2177,6 @@ golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200115165105-de0b1760071a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117220505-0cba7a3a9ee9/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
@@ -2253,7 +2191,6 @@ golang.org/x/tools v0.0.0-20200303214625-2b0b585e22fe/go.mod h1:o4KQGtdN14AW+yjs
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200317043434-63da46f3035e/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200321224714-0d839f3cf2ed/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200324003944-a576cf524670/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200329025819-fd4102a86c65/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
@@ -2266,20 +2203,15 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200502202811-ed308ab3e770/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200519015757-0d0afa43d58a/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200527183253-8e7acdbce89d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200601175630-2caf76543d99/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200603131246-cc40288be839/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200612220849-54c614fe050c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200701000337-a32c0cb1d5b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200701041122-1837592efa10/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200709181711-e327e1019dfe/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305 h1:yaM5S0KcY0lIoZo7Fl+oi91b/DdlU2zuWpfHrpWbCS0=
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200725200936-102e7d357031/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
@@ -2356,7 +2288,6 @@ google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoA
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181016170114-94acd270e44e/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
@@ -2456,7 +2387,6 @@ google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -2503,8 +2433,6 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/robfig/cron.v2 v2.0.0-20150107220207-be2e0b0deed5/go.mod h1:hiOFpYm0ZJbusNj2ywpbrXowU3G8U6GIQzqn2mw1UIE=
gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.3.1 h1:SK5KegNXmKmqE342YYN2qPHEnUYeoMiXXl1poUlI+o4=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
@@ -2538,7 +2466,6 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C
gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
helm.sh/helm/v3 v3.1.1/go.mod h1:WYsFJuMASa/4XUqLyv54s0U/f3mlAaRErGmyy4z921g=
helm.sh/helm/v3 v3.2.0/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0=
helm.sh/helm/v3 v3.2.4 h1:lz/0ZRkSgyIF+pCo6pjFzap1udCARB1IN6CRfqkpcOg=
helm.sh/helm/v3 v3.2.4/go.mod h1:ZaXz/vzktgwjyGGFbUWtIQkscfE7WYoRGP2szqAFHR0=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -2753,7 +2680,6 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
mvdan.cc/gofumpt v0.0.0-20200709182408-4fd085cb6d5f/go.mod h1:9VQ397fNXEnF84t90W4r4TRCQK+pg9f8ugVfyj+S26w=
mvdan.cc/interfacer v0.0.0-20180901003855-c20040233aed/go.mod h1:Xkxe497xwlCKkIaQYRfC7CSLworTXY9RMqwhhCm+8Nc=
mvdan.cc/lint v0.0.0-20170908181259-adc824a0674b/go.mod h1:2odslEg/xrtNQqCYg2/jCoyKnw3vv5biOc3JnIcYfL4=
mvdan.cc/unparam v0.0.0-20190720180237-d51796306d8f/go.mod h1:4G1h5nDURzA3bwVMZIVpwbkw+04kSxk3rAtzlimaUJw=

View File

@@ -8,14 +8,12 @@ import (
"path/filepath"
"github.com/oam-dev/kubevela/hack/utils"
"github.com/openservicemesh/osm/pkg/cli"
)
func main() {
// Path relative to the Makefile where this is invoked.
chartPath := filepath.Join("charts", "vela-core")
source, err := cli.GetChartSource(chartPath)
source, err := utils.GetChartSource(chartPath)
if err != nil {
fmt.Fprintln(os.Stderr, "error getting chart source:", err)
os.Exit(1)

View File

@@ -2,7 +2,16 @@ package utils
import (
"bytes"
"encoding/base64"
"fmt"
"io"
"io/ioutil"
"os"
"strings"
helm "helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
)
// FprintZipData converts zip binary contents to a string literal.
@@ -28,3 +37,36 @@ func FprintZipData(dest *bytes.Buffer, zipData []byte) {
fmt.Fprintf(dest, "\\x%02x", b)
}
}
// GetChartSource is a helper to convert a filepath to a chart to a
// base64-encoded, gzipped tarball.
func GetChartSource(path string) (string, error) {
pack := helm.NewPackage()
packagedPath, err := pack.Run(path, nil)
if err != nil {
return "", err
}
defer os.Remove(packagedPath)
packaged, err := ioutil.ReadFile(packagedPath)
if err != nil {
return "", err
}
b64Encoded := bytes.NewBuffer(nil)
enc := base64.NewEncoder(base64.StdEncoding, b64Encoded)
_, err = io.Copy(enc, bytes.NewReader(packaged))
if err != nil {
return "", err
}
return b64Encoded.String(), nil
}
// LoadChart is a helper to turn a base64-encoded, gzipped tarball into a chart.
func LoadChart(source string) (*chart.Chart, error) {
dec := base64.NewDecoder(base64.StdEncoding, strings.NewReader(source))
tgz := bytes.NewBuffer(nil)
_, err := io.Copy(tgz, dec)
if err != nil {
return nil, err
}
return loader.LoadArchive(tgz)
}

View File

@@ -380,16 +380,18 @@ spec:
items:
description: A WorkloadStatus represents the status of a workload.
properties:
appliedComponentRevision:
description: AppliedComponentRevision indicates the applied component revision name of this workload
type: string
componentName:
description: ComponentName that produced this workload.
type: string
componentRevisionName:
description: ComponentRevisionName of current component
type: string
observedGeneration:
description: ObservedGeneration indicates the generation observed by the appconfig controller. The same field is also recorded in the annotations of workloads. A workload is possible to be deleted from cluster after created. This field is useful to track the observed generation of workloads after they are deleted.
format: int64
type: integer
dependencyUnsatisfied:
description: DependencyUnsatisfied notify does the workload has dependency unsatisfied
type: boolean
scopes:
description: Scopes associated with this workload.
items:
@@ -430,6 +432,13 @@ spec:
items:
description: A WorkloadTrait represents a trait associated with a workload and its status
properties:
appliedGeneration:
description: AppliedGeneration indicates the generation observed by the appConfig controller. The same field is also recorded in the annotations of traits. A trait is possible to be deleted from cluster after created. This field is useful to track the observed generation of traits after they are deleted.
format: int64
type: integer
dependencyUnsatisfied:
description: DependencyUnsatisfied notify does the trait has dependency unsatisfied
type: boolean
message:
description: Message will allow controller to leave some additional information for this trait
type: string

View File

@@ -34,7 +34,6 @@ import (
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
"github.com/oam-dev/kubevela/pkg/oam/util"
@@ -426,37 +425,33 @@ var _ = Describe("Test appFile parser", func() {
Name: "myweb",
Namespace: "default",
Labels: map[string]string{"application.oam.dev": "test"},
}, Spec: v1alpha2.ComponentSpec{
Workload: runtime.RawExtension{
Object: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"workload.oam.dev/type": "worker",
"app.oam.dev/component": "myweb",
"app.oam.dev/name": "test",
},
},
"spec": map[string]interface{}{
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"app.oam.dev/component": "myweb"}},
"template": map[string]interface{}{
"metadata": map[string]interface{}{"labels": map[string]interface{}{"app.oam.dev/component": "myweb"}},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"command": []interface{}{"sleep", "1000"},
"image": "busybox",
"name": "myweb",
"env": []interface{}{
map[string]interface{}{"name": "c1", "value": "v1"},
map[string]interface{}{"name": "c2", "value": "v2"},
},
},
},
}}
expectWorkload := &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"workload.oam.dev/type": "worker",
"app.oam.dev/component": "myweb",
"app.oam.dev/name": "test",
},
},
"spec": map[string]interface{}{
"selector": map[string]interface{}{
"matchLabels": map[string]interface{}{
"app.oam.dev/component": "myweb"}},
"template": map[string]interface{}{
"metadata": map[string]interface{}{"labels": map[string]interface{}{"app.oam.dev/component": "myweb"}},
"spec": map[string]interface{}{
"containers": []interface{}{
map[string]interface{}{
"command": []interface{}{"sleep", "1000"},
"image": "busybox",
"name": "myweb",
"env": []interface{}{
map[string]interface{}{"name": "c1", "value": "v1"},
map[string]interface{}{"name": "c2", "value": "v2"},
},
},
},
@@ -465,12 +460,30 @@ var _ = Describe("Test appFile parser", func() {
},
},
}
// assertion util cannot compare slices embedded in map correctly while slice order is not required
// e.g., .containers[0].env in this case
// as a workaround, prepare two expected targets covering all possible slice order
// if any one is satisfied, the equal assertion pass
expectWorkloadOptional := expectWorkload.DeepCopy()
unstructured.SetNestedSlice(expectWorkloadOptional.Object, []interface{}{
map[string]interface{}{
"command": []interface{}{"sleep", "1000"},
"image": "busybox",
"name": "myweb",
"env": []interface{}{
map[string]interface{}{"name": "c2", "value": "v2"},
map[string]interface{}{"name": "c1", "value": "v1"},
},
},
}, "spec", "template", "spec", "containers")
By(" built components' length must be 1")
Expect(len(components)).To(BeEquivalentTo(1))
Expect(components[0].ObjectMeta).To(BeEquivalentTo(expectComponent.ObjectMeta))
Expect(components[0].TypeMeta).To(BeEquivalentTo(expectComponent.TypeMeta))
logf.Log.Info(cmp.Diff(components[0].Spec.Workload.Object, expectComponent.Spec.Workload.Object))
Expect(assert.ObjectsAreEqual(components[0].Spec.Workload.Object, expectComponent.Spec.Workload.Object)).To(BeTrue())
Expect(components[0].Spec.Workload.Object).Should(SatisfyAny(
BeEquivalentTo(expectWorkload),
BeEquivalentTo(expectWorkloadOptional)))
})
})

View File

@@ -8,7 +8,6 @@ import (
"os"
"time"
"github.com/openservicemesh/osm/pkg/cli"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/chart"
@@ -18,6 +17,7 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/apis/types"
"github.com/oam-dev/kubevela/hack/utils"
cmdutil "github.com/oam-dev/kubevela/pkg/commands/util"
"github.com/oam-dev/kubevela/pkg/plugins"
"github.com/oam-dev/kubevela/pkg/utils/helm"
@@ -247,7 +247,7 @@ func InstallOamRuntime(chartPath, chartSource string, vals map[string]interface{
ioStreams.Infof("Use customized chart at: %s", chartPath)
chartRequested, err = loader.Load(chartPath)
} else {
chartRequested, err = cli.LoadChart(chartSource)
chartRequested, err = utils.LoadChart(chartSource)
if chartRequested != nil {
m, l := chartRequested.Metadata, len(chartRequested.Raw)
ioStreams.Infof("install chart %s, version %s, desc : %s, contains %d file\n", m.Name, m.Version, m.Description, l)

View File

@@ -102,7 +102,7 @@ func Setup(mgr ctrl.Manager, args core.Args, l logging.Logger) error {
CustomRevisionHookURL: args.CustomRevisionHookURL,
}).
Complete(NewReconciler(mgr, dm,
WithLogger(l.WithValues("controller", name)),
l.WithValues("controller", name),
WithRecorder(event.NewAPIRecorder(mgr.GetEventRecorderFor(name))),
WithApplyOnceOnlyMode(args.ApplyMode)))
}
@@ -148,13 +148,6 @@ func WithGarbageCollector(gc GarbageCollector) ReconcilerOption {
}
}
// WithLogger specifies how the Reconciler should log messages.
func WithLogger(l logging.Logger) ReconcilerOption {
return func(r *OAMApplicationReconciler) {
r.log = l
}
}
// WithRecorder specifies how the Reconciler should record events.
func WithRecorder(er event.Recorder) ReconcilerOption {
return func(r *OAMApplicationReconciler) {
@@ -186,7 +179,7 @@ func WithApplyOnceOnlyMode(mode core.ApplyOnceOnlyMode) ReconcilerOption {
// NewReconciler returns an OAMApplicationReconciler that reconciles ApplicationConfigurations
// by rendering and instantiating their Components and Traits.
func NewReconciler(m ctrl.Manager, dm discoverymapper.DiscoveryMapper, o ...ReconcilerOption) *OAMApplicationReconciler {
func NewReconciler(m ctrl.Manager, dm discoverymapper.DiscoveryMapper, log logging.Logger, o ...ReconcilerOption) *OAMApplicationReconciler {
r := &OAMApplicationReconciler{
client: m.GetClient(),
scheme: m.GetScheme(),
@@ -198,12 +191,12 @@ func NewReconciler(m ctrl.Manager, dm discoverymapper.DiscoveryMapper, o ...Reco
trait: ResourceRenderFn(renderTrait),
},
workloads: &workloads{
applicator: apply.NewAPIApplicator(m.GetClient()),
applicator: apply.NewAPIApplicator(m.GetClient(), log),
rawClient: m.GetClient(),
dm: dm,
},
gc: GarbageCollectorFn(eligible),
log: logging.NewNopLogger(),
log: log,
record: event.NewNopRecorder(),
preHooks: make(map[string]ControllerHooks),
postHooks: make(map[string]ControllerHooks),
@@ -299,7 +292,7 @@ func (r *OAMApplicationReconciler) Reconcile(req reconcile.Request) (result reco
log.Debug("Successfully rendered components", "workloads", len(workloads))
r.record.Event(ac, event.Normal(reasonRenderComponents, "Successfully rendered components", "workloads", strconv.Itoa(len(workloads))))
applyOpts := []apply.ApplyOption{apply.MustBeControllableBy(ac.GetUID()), applyOnceOnly(ac, r.applyOnceOnlyMode)}
applyOpts := []apply.ApplyOption{apply.MustBeControllableBy(ac.GetUID()), applyOnceOnly(ac, r.applyOnceOnlyMode, log)}
if err := r.workloads.Apply(ctx, ac.Status.Workloads, workloads, applyOpts...); err != nil {
log.Debug("Cannot apply components", "error", err, "requeue-after", time.Now().Add(shortWait))
r.record.Event(ac, event.Warning(reasonCannotApplyComponents, err))
@@ -361,7 +354,6 @@ func (r *OAMApplicationReconciler) updateStatus(ctx context.Context, ac, acPatch
historyWorkloads := make([]v1alpha2.HistoryWorkload, 0)
for i, w := range workloads {
ac.Status.Workloads[i] = workloads[i].Status()
ac.Status.Workloads[i].ObservedGeneration = ac.GetGeneration()
if !w.RevisionEnabled {
continue
}
@@ -398,6 +390,17 @@ func updateObservedGeneration(ac *v1alpha2.ApplicationConfiguration) {
if ac.Status.ObservedGeneration != ac.Generation {
ac.Status.ObservedGeneration = ac.Generation
}
for i, w := range ac.Status.Workloads {
// only the workload meet all dependency can mean the generation applied successfully
if w.AppliedComponentRevision != w.ComponentRevisionName && !w.DependencyUnsatisfied {
ac.Status.Workloads[i].AppliedComponentRevision = w.ComponentRevisionName
}
for j, t := range w.Traits {
if t.AppliedGeneration != ac.Generation && !t.DependencyUnsatisfied {
ac.Status.Workloads[i].Traits[j].AppliedGeneration = ac.Generation
}
}
}
}
func patchExtraStatusField(acStatus *v1alpha2.ApplicationConfigurationStatus, acPatchStatus v1alpha2.ApplicationConfigurationStatus) {
@@ -485,6 +488,7 @@ func (w Workload) Status() v1alpha2.WorkloadStatus {
acw := v1alpha2.WorkloadStatus{
ComponentName: w.ComponentName,
ComponentRevisionName: w.ComponentRevisionName,
DependencyUnsatisfied: w.HasDep,
Reference: v1alpha1.TypedReference{
APIVersion: w.Workload.GetAPIVersion(),
Kind: w.Workload.GetKind(),
@@ -502,6 +506,7 @@ func (w Workload) Status() v1alpha2.WorkloadStatus {
Kind: w.Traits[i].Object.GetKind(),
Name: w.Traits[i].Object.GetName(),
}
acw.Traits[i].DependencyUnsatisfied = tr.HasDep
}
for i, s := range w.Scopes {
acw.Scopes[i].Reference = v1alpha1.TypedReference{
@@ -591,12 +596,11 @@ func (e *GenerationUnchanged) Error() string {
// applyOnceOnly is an ApplyOption that controls the applying mechanism for workload and trait.
// More detail refers to the ApplyOnceOnlyMode type annotation
func applyOnceOnly(ac *v1alpha2.ApplicationConfiguration, mode core.ApplyOnceOnlyMode) apply.ApplyOption {
func applyOnceOnly(ac *v1alpha2.ApplicationConfiguration, mode core.ApplyOnceOnlyMode, log logging.Logger) apply.ApplyOption {
return func(_ context.Context, existing, desired runtime.Object) error {
if mode == core.ApplyOnceOnlyOff {
return nil
}
d, _ := desired.(metav1.Object)
if d == nil {
return errors.Errorf("cannot access metadata of object being applied: %q",
@@ -608,6 +612,7 @@ func applyOnceOnly(ac *v1alpha2.ApplicationConfiguration, mode core.ApplyOnceOnl
dLabels[oam.LabelOAMResourceType] != oam.ResourceTypeTrait {
// this ApplyOption only works for workload and trait
// skip if the resource is not workload nor trait, e.g., scope
log.Info("ignore apply only once check, because resourceType is not workload or trait", oam.LabelOAMResourceType, dLabels[oam.LabelOAMResourceType])
return nil
}
@@ -615,41 +620,54 @@ func applyOnceOnly(ac *v1alpha2.ApplicationConfiguration, mode core.ApplyOnceOnl
if existing == nil {
if mode != core.ApplyOnceOnlyForce {
// non-force mode will always create the resource if not exist.
log.Info("apply only once with mode:" + string(mode) + ", but old resource not exist, will create a new one")
return nil
}
createdBefore := false
var appliedRevision, appliedGeneration string
for _, w := range ac.Status.Workloads {
// traverse recorded workloads to find the one matching applied resource
if w.Reference.GetObjectKind().GroupVersionKind() == desired.GetObjectKind().GroupVersionKind() &&
w.Reference.Name == d.GetName() {
// the workload matches applied resource
createdBefore = true
// for workload, when revision enabled, only when revision changed that can trigger to create a new one
if dLabels[oam.LabelOAMResourceType] == oam.ResourceTypeWorkload && w.AppliedComponentRevision == dLabels[oam.LabelAppComponentRevision] {
// the revision is not changed, so return an error to abort creating it
return &GenerationUnchanged{}
}
appliedRevision = w.AppliedComponentRevision
break
}
if !createdBefore {
// the workload is not matched, then traverse its traits to find matching one
for _, t := range w.Traits {
if t.Reference.GetObjectKind().GroupVersionKind() == desired.GetObjectKind().GroupVersionKind() &&
t.Reference.Name == d.GetName() {
// the trait matches applied resource
createdBefore = true
// the workload is not matched, then traverse its traits to find matching one
for _, t := range w.Traits {
if t.Reference.GetObjectKind().GroupVersionKind() == desired.GetObjectKind().GroupVersionKind() &&
t.Reference.Name == d.GetName() {
// the trait matches applied resource
createdBefore = true
// the resource was created before and appConfig status recorded the resource version applied
// if recorded AppliedGeneration and ComponentRevisionName both equal to the applied resource's,
// that means its spec is not changed
if dLabels[oam.LabelOAMResourceType] == oam.ResourceTypeTrait &&
w.ComponentRevisionName == dLabels[oam.LabelAppComponentRevision] &&
strconv.FormatInt(t.AppliedGeneration, 10) == dAnnots[oam.AnnotationAppGeneration] {
// the revision is not changed, so return an error to abort creating it
return &GenerationUnchanged{}
}
appliedGeneration = strconv.FormatInt(t.AppliedGeneration, 10)
break
}
}
// don't use if-else here because it will miss the case that the resource is a trait
if createdBefore {
// the resource was created before and appconfig status recorded the resource version applied
// if recored ObservedGeneration and ComponentRevisionName both equal to the applied resource's,
// that means its spec is not changed
if (strconv.Itoa(int(w.ObservedGeneration)) != dAnnots[oam.AnnotationAppGeneration]) ||
(w.ComponentRevisionName != dLabels[oam.LabelAppComponentRevision]) {
// its spec is changed, so re-create the resource
return nil
}
// its spec is not changed, so return an error to abort creating it
return &GenerationUnchanged{}
}
}
var message = "apply only once with mode: force, but resource not created before, will create new"
if createdBefore {
message = "apply only once with mode: force, but resource updated, will create new"
}
log.Info(message, "appConfig", ac.Name, "gvk", desired.GetObjectKind().GroupVersionKind(), "name", d.GetName(),
"resourceType", dLabels[oam.LabelOAMResourceType], "appliedCompRevision", appliedRevision, "labeledCompRevision", dLabels[oam.LabelAppComponentRevision],
"appliedGeneration", appliedGeneration, "labeledGeneration", dAnnots[oam.AnnotationAppGeneration])
// no recorded workloads nor traits matches the applied resource
// that means the resource is not created before, so create it
return nil
@@ -662,10 +680,13 @@ func applyOnceOnly(ac *v1alpha2.ApplicationConfiguration, mode core.ApplyOnceOnl
existing.GetObjectKind().GroupVersionKind())
}
eLabels := e.GetLabels()
// if existing reource's (observed)AppConfigGeneration and ComponentRevisionName both equal to the applied one's,
// if existing resource's (observed)AppConfigGeneration and ComponentRevisionName both equal to the applied one's,
// that means its spec is not changed
if (e.GetAnnotations()[oam.AnnotationAppGeneration] != dAnnots[oam.AnnotationAppGeneration]) ||
(eLabels[oam.LabelAppComponentRevision] != dLabels[oam.LabelAppComponentRevision]) {
log.Info("apply only once with mode: "+string(mode)+", but new generation or revision created, will create new",
oam.AnnotationAppGeneration, e.GetAnnotations()[oam.AnnotationAppGeneration]+"/"+dAnnots[oam.AnnotationAppGeneration],
oam.LabelAppComponentRevision, eLabels[oam.LabelAppComponentRevision]+"/"+dLabels[oam.LabelAppComponentRevision])
// its spec is changed, so apply new configuration to it
return nil
}

View File

@@ -661,7 +661,7 @@ func TestReconciler(t *testing.T) {
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
r := NewReconciler(tc.args.m, nil, tc.args.o...)
r := NewReconciler(tc.args.m, nil, logging.NewNopLogger(), tc.args.o...)
got, err := r.Reconcile(reconcile.Request{})
if diff := cmp.Diff(tc.want.err, err, test.EquateErrors()); diff != "" {
@@ -1628,7 +1628,7 @@ func TestUpdateStatus(t *testing.T) {
},
}
r := NewReconciler(m, nil)
r := NewReconciler(m, nil, logging.NewNopLogger())
ac := &v1alpha2.ApplicationConfiguration{}
err := r.client.Get(context.Background(), types.NamespacedName{Name: "example-appconfig"}, ac)

View File

@@ -136,13 +136,12 @@ spec:
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: appName}, ac)
}, 3*time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile")
reconcileRetry(reconciler, req)
By("Check workload created successfully")
Eventually(func() error {
By("Reconcile")
reconcileRetry(reconciler, req)
return k8sClient.Get(ctx, workloadKey, &workload)
}, 5*time.Second, 300*time.Millisecond).Should(BeNil())
}, 5*time.Second, time.Second).Should(BeNil())
By("Check reconcile again and no error will happen")
reconcileRetry(reconciler, req)
@@ -223,9 +222,14 @@ spec:
By("Check new trait CR is applied")
scale := v1alpha2.ManualScalerTrait{}
scaleKey := client.ObjectKey{Name: scaleName, Namespace: namespace}
err = k8sClient.Get(ctx, scaleKey, &scale)
Expect(err).Should(BeNil())
Expect(scale.Spec.ReplicaCount).Should(Equal(int32(3)))
Eventually(func() int32 {
By("Reconcile")
reconcileRetry(reconciler, req)
if err := k8sClient.Get(ctx, scaleKey, &scale); err != nil {
return 0
}
return scale.Spec.ReplicaCount
}, 5*time.Second, time.Second).Should(Equal(int32(3)))
})
AfterEach(func() {

View File

@@ -4,6 +4,11 @@ import (
"context"
"time"
"github.com/crossplane/crossplane-runtime/pkg/logging"
ctrl "sigs.k8s.io/controller-runtime"
"k8s.io/apimachinery/pkg/types"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -141,8 +146,7 @@ var _ = Describe("Test apply (workloads/traits) once only", func() {
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile")
Expect(func() error { _, err := reconciler.Reconcile(req); return err }()).Should(BeNil())
time.Sleep(3 * time.Second)
reconcileRetry(reconciler, req)
})
AfterEach(func() {
@@ -166,6 +170,8 @@ var _ = Describe("Test apply (workloads/traits) once only", func() {
By("Get workload instance & Check workload spec")
cwObj := v1alpha2.ContainerizedWorkload{}
Eventually(func() error {
By("Reconcile")
reconcileRetry(reconciler, req)
return k8sClient.Get(ctx, cwObjKey, &cwObj)
}, 5*time.Second, time.Second).Should(BeNil())
Expect(cwObj.Spec.Containers[0].Image).Should(Equal(image1))
@@ -267,6 +273,8 @@ var _ = Describe("Test apply (workloads/traits) once only", func() {
By("Get workload instance & Check workload spec")
cwObj := v1alpha2.ContainerizedWorkload{}
Eventually(func() error {
By("Reconcile")
reconcileRetry(reconciler, req)
return k8sClient.Get(ctx, cwObjKey, &cwObj)
}, 5*time.Second, time.Second).Should(BeNil())
@@ -285,6 +293,375 @@ var _ = Describe("Test apply (workloads/traits) once only", func() {
})
When("ApplyOnceOnlyForce is enabled", func() {
It("tests the situation where workload is not applied at the first because of unsatisfied dependency",
func() {
componentHandler := &ComponentHandler{Client: k8sClient, RevisionLimit: 100, Logger: logging.NewLogrLogger(ctrl.Log.WithName("component-handler"))}
By("Enable ApplyOnceOnlyForce")
reconciler.applyOnceOnlyMode = core.ApplyOnceOnlyForce
tempFoo := &unstructured.Unstructured{}
tempFoo.SetAPIVersion("example.com/v1")
tempFoo.SetKind("Foo")
tempFoo.SetNamespace(namespace)
inName := "data-input"
inputWorkload := &unstructured.Unstructured{}
inputWorkload.SetAPIVersion("example.com/v1")
inputWorkload.SetKind("Foo")
inputWorkload.SetNamespace(namespace)
inputWorkload.SetName(inName)
compInName := "comp-in"
compIn := v1alpha2.Component{
ObjectMeta: metav1.ObjectMeta{
Name: compInName,
Namespace: namespace,
},
Spec: v1alpha2.ComponentSpec{
Workload: runtime.RawExtension{
Object: inputWorkload,
},
},
}
outName := "data-output"
outputTrait := tempFoo.DeepCopy()
outputTrait.SetName(outName)
acWithDepName := "ac-dep"
acWithDep := v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: acWithDepName,
Namespace: namespace,
},
Spec: v1alpha2.ApplicationConfigurationSpec{
Components: []v1alpha2.ApplicationConfigurationComponent{
{
ComponentName: compInName,
DataInputs: []v1alpha2.DataInput{
{
ValueFrom: v1alpha2.DataInputValueFrom{
DataOutputName: "trait-output",
},
ToFieldPaths: []string{"spec.key"},
},
},
Traits: []v1alpha2.ComponentTrait{{
Trait: runtime.RawExtension{Object: outputTrait},
DataOutputs: []v1alpha2.DataOutput{{
Name: "trait-output",
FieldPath: "status.key",
}},
},
},
},
},
},
}
By("Create Component")
Expect(k8sClient.Create(ctx, &compIn)).Should(Succeed())
cmp := &v1alpha2.Component{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compInName}, cmp)).Should(Succeed())
cmpV1 := cmp.DeepCopy()
By("component handler will automatically create controller revision")
Expect(func() bool {
_, ok := componentHandler.createControllerRevision(cmpV1, cmpV1)
return ok
}()).Should(BeTrue())
By("Creat appConfig & check successfully")
Expect(k8sClient.Create(ctx, &acWithDep)).Should(Succeed())
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: acWithDepName}, &acWithDep)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile & check successfully")
reqDep := reconcile.Request{
NamespacedName: client.ObjectKey{Namespace: namespace, Name: acWithDepName},
}
Eventually(func() bool {
reconcileRetry(reconciler, reqDep)
acWithDep = v1alpha2.ApplicationConfiguration{}
if err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: acWithDepName}, &acWithDep); err != nil {
return false
}
return len(acWithDep.Status.Workloads) == 1
}, time.Second, 300*time.Millisecond).Should(BeTrue())
// because dependency is not satisfied so the workload should not be created
By("Check the workload is NOT created")
workloadIn := tempFoo.DeepCopy()
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: inName}, workloadIn)).Should(&util.NotFoundMatcher{})
// modify the trait to make it satisfy comp's dependency
outputTrait = tempFoo.DeepCopy()
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: outName}, outputTrait)).Should(Succeed())
err := unstructured.SetNestedField(outputTrait.Object, "test", "status", "key")
Expect(err).Should(BeNil())
Expect(k8sClient.Status().Update(ctx, outputTrait)).Should(Succeed())
Eventually(func() string {
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: outName}, outputTrait)
data, _, _ := unstructured.NestedString(outputTrait.Object, "status", "key")
return data
}, 3*time.Second, time.Second).Should(Equal("test"))
By("Reconcile & check ac is satisfied")
Eventually(func() []v1alpha2.UnstaifiedDependency {
reconcileRetry(reconciler, reqDep)
acWithDep = v1alpha2.ApplicationConfiguration{}
if err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: acWithDepName}, &acWithDep); err != nil {
return []v1alpha2.UnstaifiedDependency{{Reason: err.Error()}}
}
return acWithDep.Status.Dependency.Unsatisfied
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile & check workload is created")
Eventually(func() error {
reconcileRetry(reconciler, reqDep)
// the workload is created now because its dependency is satisfied
workloadIn := tempFoo.DeepCopy()
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: inName}, workloadIn)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Delete the workload")
recreatedWL := tempFoo.DeepCopy()
recreatedWL.SetName(inName)
Expect(k8sClient.Delete(ctx, recreatedWL)).Should(Succeed())
outputTrait = tempFoo.DeepCopy()
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: inName}, outputTrait)).Should(util.NotFoundMatcher{})
By("Reconcile")
Expect(func() error { _, err := reconciler.Reconcile(req); return err }()).Should(BeNil())
time.Sleep(3 * time.Second)
By("Check workload is not re-created by reconciliation")
inputWorkload = tempFoo.DeepCopy()
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: inName}, inputWorkload)).Should(util.NotFoundMatcher{})
})
It("tests the situation where workload is not applied at the first because of unsatisfied dependency and revision specified",
func() {
componentHandler := &ComponentHandler{Client: k8sClient, RevisionLimit: 100, Logger: logging.NewLogrLogger(ctrl.Log.WithName("component-handler"))}
By("Enable ApplyOnceOnlyForce")
reconciler.applyOnceOnlyMode = core.ApplyOnceOnlyForce
tempFoo := &unstructured.Unstructured{}
tempFoo.SetAPIVersion("example.com/v1")
tempFoo.SetKind("Foo")
tempFoo.SetNamespace(namespace)
inputWorkload := &unstructured.Unstructured{}
inputWorkload.SetAPIVersion("example.com/v1")
inputWorkload.SetKind("Foo")
inputWorkload.SetNamespace(namespace)
compInName := "comp-in-revision"
compIn := v1alpha2.Component{
ObjectMeta: metav1.ObjectMeta{
Name: compInName,
Namespace: namespace,
},
Spec: v1alpha2.ComponentSpec{
Workload: runtime.RawExtension{
Object: inputWorkload,
},
},
}
outName := "data-output"
outputTrait := tempFoo.DeepCopy()
outputTrait.SetName(outName)
acWithDepName := "ac-dep"
acWithDep := v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: acWithDepName,
Namespace: namespace,
},
Spec: v1alpha2.ApplicationConfigurationSpec{
Components: []v1alpha2.ApplicationConfigurationComponent{
{
RevisionName: compInName + "-v1",
DataInputs: []v1alpha2.DataInput{
{
ValueFrom: v1alpha2.DataInputValueFrom{
DataOutputName: "trait-output",
},
ToFieldPaths: []string{"spec.key"},
},
},
Traits: []v1alpha2.ComponentTrait{{
Trait: runtime.RawExtension{Object: outputTrait},
DataOutputs: []v1alpha2.DataOutput{{
Name: "trait-output",
FieldPath: "status.key",
}},
},
},
},
},
},
}
By("Create Component")
Expect(k8sClient.Create(ctx, &compIn)).Should(Succeed())
cmp := &v1alpha2.Component{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compInName}, cmp)).Should(Succeed())
cmpV1 := cmp.DeepCopy()
By("component handler will automatically create controller revision")
Expect(func() bool {
_, ok := componentHandler.createControllerRevision(cmpV1, cmpV1)
return ok
}()).Should(BeTrue())
By("Creat appConfig & check successfully")
Expect(k8sClient.Create(ctx, &acWithDep)).Should(Succeed())
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: acWithDepName}, &acWithDep)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile & check successfully")
reqDep := reconcile.Request{
NamespacedName: client.ObjectKey{Namespace: namespace, Name: acWithDepName},
}
Eventually(func() bool {
reconcileRetry(reconciler, reqDep)
acWithDep = v1alpha2.ApplicationConfiguration{}
if err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: acWithDepName}, &acWithDep); err != nil {
return false
}
return len(acWithDep.Status.Workloads) == 1
}, time.Second, 300*time.Millisecond).Should(BeTrue())
// because dependency is not satisfied so the workload should not be created
By("Check the workload is NOT created")
workloadIn := tempFoo.DeepCopy()
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compInName + "-v1"}, workloadIn)).Should(&util.NotFoundMatcher{})
// modify the trait to make it satisfy comp's dependency
outputTrait = tempFoo.DeepCopy()
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: outName}, outputTrait)).Should(Succeed())
err := unstructured.SetNestedField(outputTrait.Object, "test", "status", "key")
Expect(err).Should(BeNil())
Expect(k8sClient.Status().Update(ctx, outputTrait)).Should(Succeed())
Eventually(func() string {
k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: outName}, outputTrait)
data, _, _ := unstructured.NestedString(outputTrait.Object, "status", "key")
return data
}, 3*time.Second, time.Second).Should(Equal("test"))
By("Reconcile & check ac is satisfied")
Eventually(func() []v1alpha2.UnstaifiedDependency {
reconcileRetry(reconciler, reqDep)
acWithDep = v1alpha2.ApplicationConfiguration{}
if err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: acWithDepName}, &acWithDep); err != nil {
return []v1alpha2.UnstaifiedDependency{{Reason: err.Error()}}
}
return acWithDep.Status.Dependency.Unsatisfied
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile & check workload is created")
Eventually(func() error {
reconcileRetry(reconciler, reqDep)
// the workload should be created now because its dependency is satisfied
workloadIn := tempFoo.DeepCopy()
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compInName}, workloadIn)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Delete the workload")
recreatedWL := tempFoo.DeepCopy()
recreatedWL.SetName(compInName)
Expect(k8sClient.Delete(ctx, recreatedWL)).Should(Succeed())
inputWorkload2 := tempFoo.DeepCopy()
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compInName}, inputWorkload2)).Should(util.NotFoundMatcher{})
By("Reconcile")
Expect(func() error { _, err := reconciler.Reconcile(req); return err }()).Should(BeNil())
time.Sleep(3 * time.Second)
By("Check workload is not re-created by reconciliation")
inputWorkload = tempFoo.DeepCopy()
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compInName}, inputWorkload)).Should(util.NotFoundMatcher{})
})
It("should normally create workload/trait resources at fist time", func() {
By("Enable ApplyOnceOnlyForce")
reconciler.applyOnceOnlyMode = core.ApplyOnceOnlyForce
component2 := v1alpha2.Component{
TypeMeta: metav1.TypeMeta{
APIVersion: "core.oam.dev/v1alpha2",
Kind: "Component",
},
ObjectMeta: metav1.ObjectMeta{
Name: "mycomp2",
Namespace: namespace,
},
Spec: v1alpha2.ComponentSpec{
Workload: runtime.RawExtension{
Object: &cw,
},
},
}
newFakeTrait := fakeTrait.DeepCopy()
newFakeTrait.SetName("mytrait2")
appConfig2 := v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: "myac2",
Namespace: namespace,
},
Spec: v1alpha2.ApplicationConfigurationSpec{
Components: []v1alpha2.ApplicationConfigurationComponent{
{
ComponentName: "mycomp2",
Traits: []v1alpha2.ComponentTrait{
{Trait: runtime.RawExtension{Object: newFakeTrait}},
},
},
},
},
}
By("Create Component")
Expect(k8sClient.Create(ctx, &component2)).Should(Succeed())
time.Sleep(time.Second)
By("Creat appConfig & check successfully")
Expect(k8sClient.Create(ctx, &appConfig2)).Should(Succeed())
time.Sleep(time.Second)
By("Reconcile")
Expect(func() error {
_, err := reconciler.Reconcile(reconcile.Request{NamespacedName: types.NamespacedName{Name: "myac2", Namespace: namespace}})
return err
}()).Should(BeNil())
time.Sleep(2 * time.Second)
By("Get workload instance & Check workload spec")
cwObj := v1alpha2.ContainerizedWorkload{}
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: "mycomp2"}, &cwObj)
}, 5*time.Second, time.Second).Should(BeNil())
Expect(cwObj.Spec.Containers[0].Image).Should(Equal(image1))
By("Get trait instance & Check trait spec")
fooObj := &unstructured.Unstructured{}
fooObj.SetAPIVersion("example.com/v1")
fooObj.SetKind("Foo")
Eventually(func() error {
return k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: "mytrait2"}, fooObj)
}, 3*time.Second, time.Second).Should(BeNil())
fooObjV, _, _ := unstructured.NestedString(fooObj.Object, "spec", "key")
Expect(fooObjV).Should(Equal(traitSpecValue1))
})
It("should not revert changes of workload/trait made by others", func() {
By("Enable ApplyOnceOnlyForce")
reconciler.applyOnceOnlyMode = core.ApplyOnceOnlyForce
@@ -292,6 +669,8 @@ var _ = Describe("Test apply (workloads/traits) once only", func() {
By("Get workload instance & Check workload spec")
cwObj := v1alpha2.ContainerizedWorkload{}
Eventually(func() error {
By("Reconcile")
reconcileRetry(reconciler, req)
return k8sClient.Get(ctx, cwObjKey, &cwObj)
}, 5*time.Second, time.Second).Should(BeNil())
Expect(cwObj.Spec.Containers[0].Image).Should(Equal(image1))
@@ -393,8 +772,10 @@ var _ = Describe("Test apply (workloads/traits) once only", func() {
By("Get workload instance")
cwObj := v1alpha2.ContainerizedWorkload{}
Eventually(func() error {
By("Reconcile")
reconcileRetry(reconciler, req)
return k8sClient.Get(ctx, cwObjKey, &cwObj)
}, 3*time.Second, time.Second).Should(BeNil())
}, 5*time.Second, time.Second).Should(BeNil())
By("Get trait instance & Check trait spec")
fooObj := unstructured.Unstructured{}
@@ -426,7 +807,7 @@ var _ = Describe("Test apply (workloads/traits) once only", func() {
recreatedFooObj.SetKind("Foo")
Expect(k8sClient.Get(ctx, traitObjKey, &recreatedFooObj)).Should(util.NotFoundMatcher{})
By("Update Appconfig to trigger generation augment")
By("Update AppConfig to trigger generation updated")
unstructured.SetNestedField(fakeTrait.Object, "newvalue", "spec", "key")
appConfig = v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
@@ -445,14 +826,24 @@ var _ = Describe("Test apply (workloads/traits) once only", func() {
},
}
Expect(k8sClient.Patch(ctx, &appConfig, client.Merge)).Should(Succeed())
time.Sleep(1 * time.Second)
By("Reconcile")
reconcileRetry(reconciler, req)
time.Sleep(3 * time.Second)
By("Check AppConfig is updated successfully")
updateAC := v1alpha2.ApplicationConfiguration{}
Eventually(func() int64 {
if err := k8sClient.Get(ctx, appConfigKey, &updateAC); err != nil {
return 0
}
return updateAC.GetGeneration()
}, 3*time.Second, time.Second).Should(Equal(int64(2)))
By("Check workload is re-created by reconciliation")
recreatedCwObj = v1alpha2.ContainerizedWorkload{}
Expect(k8sClient.Get(ctx, cwObjKey, &recreatedCwObj)).Should(Succeed())
By("Check workload was not created by reconciliation")
Eventually(func() error {
By("Reconcile")
reconcileRetry(reconciler, req)
recreatedCwObj = v1alpha2.ContainerizedWorkload{}
return k8sClient.Get(ctx, cwObjKey, &recreatedCwObj)
}, 5*time.Second, time.Second).Should(SatisfyAll(util.NotFoundMatcher{}))
By("Check trait is re-created by reconciliation")
recreatedFooObj = unstructured.Unstructured{}

View File

@@ -236,31 +236,26 @@ spec:
return appConfig.GetGeneration()
}, time.Second, 300*time.Millisecond).Should(Equal(int64(2)))
By("Reconcile")
reconcileRetry(reconciler, req)
Eventually(func() string {
By("Reconcile & check updated trait")
var traitObj unstructured.Unstructured
Eventually(func() int64 {
reconcileRetry(reconciler, req)
if err := k8sClient.Get(ctx, appConfigKey, &appConfig); err != nil {
return ""
return 0
}
if appConfig.Status.Workloads == nil {
reconcileRetry(reconciler, req)
return ""
return 0
}
return appConfig.Status.Workloads[0].Traits[0].Reference.Name
}, 3*time.Second, time.Second).ShouldNot(BeEmpty())
By("Get changed trait object")
traitName := appConfig.Status.Workloads[0].Traits[0].Reference.Name
var traitObj unstructured.Unstructured
traitObj.SetAPIVersion("example.com/v1")
traitObj.SetKind("Bar")
Eventually(func() int64 {
traitName := appConfig.Status.Workloads[0].Traits[0].Reference.Name
traitObj.SetAPIVersion("example.com/v1")
traitObj.SetKind("Bar")
if err := k8sClient.Get(ctx,
client.ObjectKey{Namespace: namespace, Name: traitName}, &traitObj); err != nil {
return 0
}
return traitObj.GetGeneration()
}, 3*time.Second, time.Second).Should(Equal(int64(2)))
}, 5*time.Second, time.Second).Should(Equal(int64(2)))
By("Check labels are removed")
_, found, _ := unstructured.NestedString(traitObj.UnstructuredContent(), "metadata", "labels", "test.label")
@@ -355,13 +350,19 @@ spec:
}
return appConfig.GetGeneration()
}, time.Second, 300*time.Millisecond).Should(Equal(int64(2)))
By("Reconcile")
reconcileRetry(reconciler, req)
changedTrait = unstructured.Unstructured{}
changedTrait.SetAPIVersion("example.com/v1")
changedTrait.SetKind("Bar")
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: traitName}, &changedTrait)).Should(Succeed())
Eventually(func() int64 {
By("Reconcile")
reconcileRetry(reconciler, req)
changedTrait = unstructured.Unstructured{}
changedTrait.SetAPIVersion("example.com/v1")
changedTrait.SetKind("Bar")
if err := k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: traitName}, &changedTrait); err != nil {
return 0
}
return changedTrait.GetGeneration()
}, 5*time.Second, time.Second).Should(Equal(int64(3)))
By("Check AppConfig's change works")
// changed a field
v, _, _ = unstructured.NestedString(changedTrait.UnstructuredContent(), "spec", "valueChanged")

View File

@@ -81,7 +81,7 @@ func (c *ComponentHandler) Generic(_ event.GenericEvent, _ workqueue.RateLimitin
func isMatch(appConfigs *v1alpha2.ApplicationConfigurationList, compName string) (bool, types.NamespacedName) {
for _, app := range appConfigs.Items {
for _, comp := range app.Spec.Components {
if comp.ComponentName == compName {
if comp.ComponentName == compName || (strings.HasPrefix(comp.RevisionName, compName+"-")) {
return true, types.NamespacedName{Namespace: app.Namespace, Name: app.Name}
}
}
@@ -140,6 +140,10 @@ func newTrue() *bool {
func (c *ComponentHandler) createControllerRevision(mt metav1.Object, obj runtime.Object) ([]reconcile.Request, bool) {
curComp := obj.(*v1alpha2.Component)
comp := curComp.DeepCopy()
// No generation changed, will not create revision
if comp.Generation == comp.Status.ObservedGeneration {
return nil, false
}
diff, curRevision := c.IsRevisionDiff(mt, comp)
if !diff {
// No difference, no need to create new revision.

View File

@@ -18,50 +18,68 @@ package applicationconfiguration
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"github.com/oam-dev/kubevela/apis/core.oam.dev/v1alpha2"
)
func TestCustomRevisionHook(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var req RevisionHookRequest
data, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(400)
return
}
err = json.Unmarshal(data, &req)
if err != nil {
w.WriteHeader(401)
return
}
if len(req.RelatedApps) != 1 {
w.WriteHeader(400)
w.Write([]byte("we should have only one relatedApps"))
return
}
if req.Comp.Annotations == nil {
req.Comp.Annotations = make(map[string]string)
var RevisionHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var req RevisionHookRequest
data, err := ioutil.ReadAll(r.Body)
if err != nil {
w.WriteHeader(400)
return
}
err = json.Unmarshal(data, &req)
if err != nil {
w.WriteHeader(401)
return
}
fmt.Println("got request from", req.Comp.Name)
if len(req.RelatedApps) != 1 {
var abc []string
for _, v := range req.RelatedApps {
abc = append(abc, v.Name)
}
// we can add a check here for real world handler
fmt.Printf("we should have only one relatedApps, but now %d: %s\n", len(req.RelatedApps), strings.Join(abc, ", "))
}
if req.Comp.Annotations == nil {
req.Comp.Annotations = make(map[string]string)
}
if len(req.RelatedApps) > 0 {
req.Comp.Annotations["app-name"] = req.RelatedApps[0].Name
req.Comp.Annotations["app-namespace"] = req.RelatedApps[0].Namespace
}
a := &unstructured.Unstructured{}
err = json.Unmarshal(req.Comp.Spec.Workload.Raw, a)
fmt.Println("XX:", err)
a.SetAnnotations(map[string]string{"time": time.Now().Format(time.RFC3339Nano)})
data, _ = json.Marshal(a)
req.Comp.Spec.Workload.Raw = data
newdata, err := json.Marshal(req.Comp)
if err != nil {
w.WriteHeader(500)
return
}
w.WriteHeader(200)
w.Write(newdata)
})
newdata, err := json.Marshal(req.Comp)
if err != nil {
w.WriteHeader(500)
return
}
w.WriteHeader(200)
w.Write(newdata)
}))
func TestCustomRevisionHook(t *testing.T) {
srv := httptest.NewServer(RevisionHandler)
defer srv.Close()
compHandler := ComponentHandler{
CustomRevisionHookURL: srv.URL,
@@ -71,7 +89,4 @@ func TestCustomRevisionHook(t *testing.T) {
assert.NoError(t, err)
assert.Equal(t, "app1", comp.Annotations["app-name"])
assert.Equal(t, "default1", comp.Annotations["app-namespace"])
err = compHandler.customComponentRevisionHook([]reconcile.Request{{NamespacedName: types.NamespacedName{Name: "app1", Namespace: "default1"}}, {NamespacedName: types.NamespacedName{Name: "app2", Namespace: "default2"}}}, comp)
assert.Equal(t, err.Error(), "httpcode(400) err: we should have only one relatedApps")
}

View File

@@ -138,7 +138,7 @@ func TestComponentHandler(t *testing.T) {
// check component's status saved in corresponding controllerRevision
assert.Equal(t, gotComp.Status.LatestRevision.Name, revisions.Items[0].Name)
assert.Equal(t, gotComp.Status.LatestRevision.Revision, revisions.Items[0].Revision)
// check component's status ObservedGeneration
// check component's status AppliedGeneration
assert.Equal(t, gotComp.Status.ObservedGeneration, comp.Generation)
q.Done(item)
// ============ Test Create Event End ===================

View File

@@ -80,8 +80,23 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
AfterEach(func() {
logf.Log.Info("Clean up resources")
// delete the namespace with all its resources
Expect(k8sClient.Delete(ctx, in)).Should(SatisfyAny(BeNil(), &util.NotFoundMatcher{}))
Expect(k8sClient.Delete(ctx, out)).Should(BeNil())
ac := &v1alpha2.ApplicationConfiguration{}
Expect(k8sClient.DeleteAllOf(ctx, ac, client.InNamespace(namespace))).Should(Succeed())
cm := &corev1.ConfigMap{}
Expect(k8sClient.DeleteAllOf(ctx, cm, client.InNamespace(namespace))).Should(Succeed())
foo := &unstructured.Unstructured{}
foo.SetAPIVersion("example.com/v1")
foo.SetKind("Foo")
Expect(k8sClient.DeleteAllOf(ctx, foo, client.InNamespace(namespace))).Should(Succeed())
Eventually(func() bool {
l := &unstructured.UnstructuredList{}
l.SetAPIVersion("example.com/v1")
l.SetKind("Foo")
if err := k8sClient.List(ctx, l, client.InNamespace(namespace)); err != nil {
return false
}
return len(l.Items) == 0
}, 3*time.Second, time.Second).Should(BeTrue())
})
// common function for verification
@@ -114,11 +129,11 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
Eventually(func() error {
err := k8sClient.Get(ctx, outFooKey, outFoo)
if err != nil {
// Try 3 (= 1s/300ms) times
// Try 3 (= 3s/1s) times
reconciler.Reconcile(req)
}
return err
}, time.Second, 300*time.Millisecond).Should(BeNil())
}, 3*time.Second, time.Second).Should(BeNil())
By("Reconcile")
reconcileRetry(reconciler, req)
@@ -159,7 +174,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
k8sClient.Get(ctx, outFooKey, outFoo)
data, _, _ := unstructured.NestedString(outFoo.Object, "status", "key")
return data
}, time.Second, 300*time.Millisecond).Should(Equal("test"))
}, 3*time.Second, time.Second).Should(Equal("test"))
By("Reconcile")
reconcileRetry(reconciler, req)
@@ -175,7 +190,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
reconciler.Reconcile(req)
k8sClient.Get(ctx, appconfigKey, appconfig)
return appconfig.Status.Dependency.Unsatisfied
}, 2*time.Second, 300*time.Millisecond).Should(BeNil())
}, 3*time.Second, time.Second).Should(BeNil())
}
It("trait depends on another trait", func() {
@@ -372,7 +387,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
Expect(k8sClient.Create(ctx, &appConfig)).Should(Succeed())
Eventually(func() error {
return k8sClient.Get(ctx, appconfigKey, &appConfig)
}, time.Second, 300*time.Millisecond).Should(BeNil())
}, 3*time.Second, time.Second).Should(BeNil())
By("Reconcile")
reconcileRetry(reconciler, req)
@@ -399,11 +414,11 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
Eventually(func() error {
err := k8sClient.Get(ctx, outFooKey, outFoo)
if err != nil {
// Try 3 (= 1s/300ms) times
// Try 3 (= 3s/1s) times
reconciler.Reconcile(req)
}
return err
}, time.Second, 300*time.Millisecond).Should(BeNil())
}, 3*time.Second, time.Second).Should(BeNil())
err := unstructured.SetNestedField(outFoo.Object, "test", "status", "key")
Expect(err).Should(BeNil())
@@ -423,11 +438,11 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
err = k8sClient.Get(ctx, appconfigKey, tempApp)
tempApp.DeepCopyInto(newAppConfig)
if err != nil || tempApp.Status.Dependency.Unsatisfied != nil {
// Try 3 (= 1s/300ms) times
// Try 3 (= 3s/1s) times
reconciler.Reconcile(req)
}
return tempApp.Status.Dependency.Unsatisfied
}(), time.Second, 300*time.Millisecond).Should(BeNil())
}(), 3*time.Second, time.Second).Should(BeNil())
By("Checking that resource which accepts data is created now")
logf.Log.Info("Checking on resource that inputs data", "Key", inFooKey)
@@ -436,11 +451,11 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
Eventually(func() error {
err := k8sClient.Get(ctx, outFooKey, outFoo)
if err != nil {
// Try 3 (= 1s/300ms) times
// Try 3 (= 3s/1s) times
reconciler.Reconcile(req)
}
return err
}, time.Second, 300*time.Millisecond).Should(BeNil())
}, 3*time.Second, time.Second).Should(BeNil())
err = unstructured.SetNestedField(outFoo.Object, "test", "status", "key")
Expect(err).Should(BeNil())
err = unstructured.SetNestedField(outFoo.Object, "hash-v1", "status", "app-hash")
@@ -453,7 +468,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
}
s, _, _ := unstructured.NestedString(outFoo.Object, "status", "key")
return s == "test"
}, time.Second, 300*time.Millisecond).Should(BeTrue())
}, 3*time.Second, time.Second).Should(BeTrue())
newAppConfig.Labels["app-hash"] = "hash-v2"
By("Update newAppConfig & check successfully")
@@ -464,10 +479,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
return false
}
return newAppConfig.Labels["app-hash"] == "hash-v2"
}, time.Second, 300*time.Millisecond).Should(BeTrue())
By("Reconcile")
reconcileRetry(reconciler, req)
}, 3*time.Second, time.Second).Should(BeTrue())
By("Verify the appconfig's dependency should be unsatisfied, because requirementCondition valueFrom not match")
depStatus := v1alpha2.DependencyStatus{
@@ -492,9 +504,11 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
}}}},
}
Eventually(func() v1alpha2.DependencyStatus {
By("Reconcile")
reconcileRetry(reconciler, req)
k8sClient.Get(ctx, appconfigKey, newAppConfig)
return newAppConfig.Status.Dependency
}, time.Second, 300*time.Millisecond).Should(Equal(depStatus))
}, 3*time.Second, time.Second).Should(Equal(depStatus))
By("Update trait resource to meet the requirement")
Expect(k8sClient.Get(ctx, outFooKey, outFoo)).Should(BeNil()) // Get the latest before update
@@ -508,7 +522,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
}
s, _, _ := unstructured.NestedString(outFoo.Object, "status", "key")
return s == "test-new"
}, time.Second, 300*time.Millisecond).Should(BeTrue())
}, 3*time.Second, time.Second).Should(BeTrue())
By("Reconcile")
reconcileRetry(reconciler, req)
@@ -519,11 +533,11 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
tempAppConfig := &v1alpha2.ApplicationConfiguration{}
err := k8sClient.Get(ctx, appconfigKey, tempAppConfig)
if err != nil || tempAppConfig.Status.Dependency.Unsatisfied != nil {
// Try 3 (= 1s/300ms) times
// Try 3 (= 3s/1s) times
reconciler.Reconcile(req)
}
return tempAppConfig.Status.Dependency.Unsatisfied
}(), time.Second, 300*time.Millisecond).Should(BeNil())
}(), 3*time.Second, time.Second).Should(BeNil())
By("Checking that resource which accepts data is updated")
Expect(func() string {
@@ -625,6 +639,9 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
Name: appConfigName,
Namespace: namespace,
}
Eventually(func() error {
return k8sClient.Get(ctx, appconfigKey, &v1alpha2.ApplicationConfiguration{})
}, 3*time.Second, time.Second).Should(Succeed())
By("Reconcile")
req := reconcile.Request{NamespacedName: appconfigKey}
reconcileRetry(reconciler, req)
@@ -641,7 +658,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
reconciler.Reconcile(req)
}
return err
}, time.Second, 300*time.Millisecond).Should(BeNil())
}, 3*time.Second, time.Second).Should(BeNil())
By("Get reconciled AppConfig the first time")
appconfig := &v1alpha2.ApplicationConfiguration{}
@@ -669,7 +686,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
k8sClient.Get(ctx, outFooKey, outFoo)
data, _, _ := unstructured.NestedSlice(outFoo.Object, "status", "complex2")
return data
}, time.Second, 300*time.Millisecond).Should(BeEquivalentTo(complex2))
}, 3*time.Second, time.Second).Should(BeEquivalentTo(complex2))
By("Reconcile")
reconcileRetry(reconciler, req)
@@ -680,7 +697,7 @@ var _ = Describe("Resource Dependency in an ApplicationConfiguration", func() {
reconciler.Reconcile(req)
k8sClient.Get(ctx, appconfigKey, appconfig)
return appconfig.Status.Dependency.Unsatisfied
}, 2*time.Second, 300*time.Millisecond).Should(BeNil())
}, 2*3*time.Second, time.Second).Should(BeNil())
// Verification after satisfying dependency
By("Checking that resource which accepts data is created now")
inFooKey := client.ObjectKey{

View File

@@ -19,18 +19,20 @@ package applicationconfiguration
import (
"context"
"fmt"
"net/http/httptest"
"strconv"
"time"
v1 "k8s.io/api/apps/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/crossplane/crossplane-runtime/pkg/logging"
v1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
@@ -200,11 +202,10 @@ var _ = Describe("Test ApplicationConfiguration Component Revision Enabled trait
return k8sClient.Get(ctx, appConfigKey, &appConfig)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile")
reconcileRetry(reconciler, req)
By("Check workload created successfully")
Eventually(func() error {
By("Reconcile")
reconcileRetry(reconciler, req)
var workloadKey = client.ObjectKey{Namespace: namespace, Name: compName + "-v1"}
return k8sClient.Get(ctx, workloadKey, &wr)
}, 3*time.Second, 300*time.Millisecond).Should(BeNil())
@@ -295,11 +296,11 @@ var _ = Describe("Test ApplicationConfiguration Component Revision Enabled trait
Eventually(func() error {
return k8sClient.Get(ctx, appConfigKey, &appConfig)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile for new revision")
reconcileRetry(reconciler, req)
By("Check new revision workload created successfully")
Eventually(func() error {
By("Reconcile for new revision")
reconcileRetry(reconciler, req)
var workloadKey = client.ObjectKey{Namespace: namespace, Name: compName + "-v2"}
return k8sClient.Get(ctx, workloadKey, &wr)
}, time.Second, 300*time.Millisecond).Should(BeNil())
@@ -341,3 +342,485 @@ var _ = Describe("Test ApplicationConfiguration Component Revision Enabled trait
})
})
var _ = Describe("Test Component Revision Enabled with custom component revision hook", func() {
const (
namespace = "revision-enable-test2"
compName = "revision-test-comp2"
)
var (
ctx = context.Background()
component v1alpha2.Component
ns = corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
)
BeforeEach(func() {})
AfterEach(func() {
// delete the namespace with all its resources
Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).
Should(SatisfyAny(BeNil(), &util.NotFoundMatcher{}))
})
It("custom component change revision lead to revision difference, it should not loop infinitely create", func() {
srv := httptest.NewServer(RevisionHandler)
defer srv.Close()
customComponentHandler := &ComponentHandler{Client: k8sClient, RevisionLimit: 100, Logger: logging.NewLogrLogger(ctrl.Log.WithName("component-handler")), CustomRevisionHookURL: srv.URL}
getDeploy := func(image string) *v1.Deployment {
return &v1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
},
Spec: v1.DeploymentSpec{
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{
"app": compName,
}},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{
"app": compName,
}},
Spec: corev1.PodSpec{Containers: []corev1.Container{{
Name: "wordpress",
Image: image,
Ports: []corev1.ContainerPort{
{
Name: "wordpress",
ContainerPort: 80,
},
},
},
}}},
},
}
}
component = v1alpha2.Component{
TypeMeta: metav1.TypeMeta{
APIVersion: "core.oam.dev/v1alpha2",
Kind: "Component",
},
ObjectMeta: metav1.ObjectMeta{
Name: compName,
Namespace: namespace,
},
Spec: v1alpha2.ComponentSpec{
Workload: runtime.RawExtension{
Object: getDeploy("wordpress:4.6.1-apache"),
},
},
}
By("Create namespace")
Eventually(
func() error {
return k8sClient.Create(ctx, &ns)
},
time.Second*3, time.Millisecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
By("Create Component")
Expect(k8sClient.Create(ctx, &component)).Should(Succeed())
By("component handler will automatically create controller revision")
Expect(func() bool {
_, ok := customComponentHandler.createControllerRevision(component.DeepCopy(), component.DeepCopy())
return ok
}()).Should(BeTrue())
By("it should not create again for the same generation component")
cmpV1 := &v1alpha2.Component{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compName}, cmpV1)).Should(Succeed())
Expect(func() bool {
_, ok := customComponentHandler.createControllerRevision(cmpV1, cmpV1)
return ok
}()).Should(BeFalse())
var crList v1.ControllerRevisionList
By("Check controller revision created successfully")
Eventually(func() error {
labels := &metav1.LabelSelector{
MatchLabels: map[string]string{
ControllerRevisionComponentLabel: compName,
},
}
selector, err := metav1.LabelSelectorAsSelector(labels)
if err != nil {
return err
}
err = k8sClient.List(ctx, &crList, &client.ListOptions{
LabelSelector: selector,
})
if err != nil {
return err
}
if len(crList.Items) != 1 {
return fmt.Errorf("want only 1 revision created but got %d", len(crList.Items))
}
return nil
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("===================================== Start to Update =========================================")
cmpV2 := &v1alpha2.Component{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compName}, cmpV2)).Should(Succeed())
cmpV2.Spec.Workload = runtime.RawExtension{
Object: getDeploy("wordpress:v2"),
}
By("Update Component")
Expect(k8sClient.Update(ctx, cmpV2)).Should(Succeed())
By("component handler will automatically create a ne controller revision")
Expect(func() bool { _, ok := componentHandler.createControllerRevision(cmpV2, cmpV2); return ok }()).Should(BeTrue())
cmpV3 := &v1alpha2.Component{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compName}, cmpV3)).Should(Succeed())
Expect(func() bool { _, ok := componentHandler.createControllerRevision(cmpV3, cmpV3); return ok }()).Should(BeFalse())
By("Check controller revision created successfully")
Eventually(func() error {
labels := &metav1.LabelSelector{
MatchLabels: map[string]string{
ControllerRevisionComponentLabel: compName,
},
}
selector, err := metav1.LabelSelectorAsSelector(labels)
if err != nil {
return err
}
err = k8sClient.List(ctx, &crList, &client.ListOptions{
LabelSelector: selector,
})
if err != nil {
return err
}
if len(crList.Items) != 2 {
return fmt.Errorf("there should be exactly 2 revision created but got %d", len(crList.Items))
}
return nil
}, time.Second, 300*time.Millisecond).Should(BeNil())
})
})
var _ = Describe("Component Revision Enabled with apply once only force", func() {
const (
namespace = "revision-and-apply-once-force"
appName = "revision-apply-once"
compName = "revision-apply-once-comp"
)
var (
ctx = context.Background()
wr v1.Deployment
component v1alpha2.Component
appConfig v1alpha2.ApplicationConfiguration
appConfigKey = client.ObjectKey{
Name: appName,
Namespace: namespace,
}
req = reconcile.Request{NamespacedName: appConfigKey}
ns = corev1.Namespace{
ObjectMeta: metav1.ObjectMeta{
Name: namespace,
},
}
)
BeforeEach(func() {})
AfterEach(func() {
// delete the namespace with all its resources
Expect(k8sClient.Delete(ctx, &ns, client.PropagationPolicy(metav1.DeletePropagationForeground))).
Should(SatisfyAny(BeNil(), &util.NotFoundMatcher{}))
})
It("revision enabled should create workload with revisionName and work upgrade with new revision successfully", func() {
getDeploy := func(image string) *v1.Deployment {
return &v1.Deployment{
TypeMeta: metav1.TypeMeta{
Kind: "Deployment",
APIVersion: "apps/v1",
},
ObjectMeta: metav1.ObjectMeta{
Namespace: namespace,
},
Spec: v1.DeploymentSpec{
Selector: &metav1.LabelSelector{MatchLabels: map[string]string{
"app": compName,
}},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{
"app": compName,
}},
Spec: corev1.PodSpec{Containers: []corev1.Container{{
Name: "wordpress",
Image: image,
Ports: []corev1.ContainerPort{
{
Name: "wordpress",
ContainerPort: 80,
},
},
},
}}},
},
}
}
component = v1alpha2.Component{
TypeMeta: metav1.TypeMeta{
APIVersion: "core.oam.dev/v1alpha2",
Kind: "Component",
},
ObjectMeta: metav1.ObjectMeta{
Name: compName,
Namespace: namespace,
},
Spec: v1alpha2.ComponentSpec{
Workload: runtime.RawExtension{
Object: getDeploy("wordpress:4.6.1-apache"),
},
},
}
appConfig = v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
}
By("Create namespace")
Eventually(
func() error {
return k8sClient.Create(ctx, &ns)
},
time.Second*3, time.Millisecond*300).Should(SatisfyAny(BeNil(), &util.AlreadyExistMatcher{}))
By("Create Component")
Expect(k8sClient.Create(ctx, &component)).Should(Succeed())
cmpV1 := &v1alpha2.Component{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compName}, cmpV1)).Should(Succeed())
By("component handler will automatically create controller revision")
Expect(func() bool {
_, ok := componentHandler.createControllerRevision(cmpV1, cmpV1)
return ok
}()).Should(BeTrue())
var crList v1.ControllerRevisionList
By("Check controller revision created successfully")
Eventually(func() error {
labels := &metav1.LabelSelector{
MatchLabels: map[string]string{
ControllerRevisionComponentLabel: compName,
},
}
selector, err := metav1.LabelSelectorAsSelector(labels)
if err != nil {
return err
}
err = k8sClient.List(ctx, &crList, &client.ListOptions{
LabelSelector: selector,
})
if err != nil {
return err
}
if len(crList.Items) != 1 {
return fmt.Errorf("want only 1 revision created but got %d", len(crList.Items))
}
return nil
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Create an ApplicationConfiguration")
appConfig = v1alpha2.ApplicationConfiguration{
ObjectMeta: metav1.ObjectMeta{
Name: appName,
Namespace: namespace,
},
Spec: v1alpha2.ApplicationConfigurationSpec{Components: []v1alpha2.ApplicationConfigurationComponent{
{
RevisionName: compName + "-v1",
Traits: []v1alpha2.ComponentTrait{
{
Trait: runtime.RawExtension{Object: &unstructured.Unstructured{Object: map[string]interface{}{
"apiVersion": "example.com/v1",
"kind": "Foo",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"trait.oam.dev/type": "rollout-revision",
},
},
"spec": map[string]interface{}{
"key": "test1",
},
}}},
},
},
},
}},
}
By("Creat appConfig & check successfully")
Expect(k8sClient.Create(ctx, &appConfig)).Should(Succeed())
Eventually(func() error {
return k8sClient.Get(ctx, appConfigKey, &appConfig)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile")
reconciler.applyOnceOnlyMode = "force"
reconcileRetry(reconciler, req)
By("Check workload created successfully")
var workloadKey1 = client.ObjectKey{Namespace: namespace, Name: compName + "-v1"}
Eventually(func() error {
reconcileRetry(reconciler, req)
return k8sClient.Get(ctx, workloadKey1, &wr)
}, 3*time.Second, 300*time.Millisecond).Should(BeNil())
By("Check workload should only have 1 generation")
Expect(wr.GetGeneration()).Should(BeEquivalentTo(1))
By("Delete the workload")
Expect(k8sClient.Delete(ctx, &wr)).Should(BeNil())
By("Check reconcile again and no error will happen")
reconcileRetry(reconciler, req)
By("Check workload will not created after reconcile because apply once force enabled")
Expect(k8sClient.Get(ctx, workloadKey1, &wr)).Should(SatisfyAll(util.NotFoundMatcher{}))
Expect(k8sClient.Get(ctx, appConfigKey, &appConfig)).Should(BeNil())
By("update the trait of ac")
appConfig.Spec.Components[0].Traits[0].Trait = runtime.RawExtension{Object: &unstructured.Unstructured{Object: map[string]interface{}{
"apiVersion": "example.com/v1",
"kind": "Foo",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"trait.oam.dev/type": "rollout-revision",
},
},
"spec": map[string]interface{}{
"key": "test2",
},
}}}
Expect(k8sClient.Update(ctx, &appConfig)).Should(Succeed())
By("Reconcile and Check appconfig condition should not have error")
reconcileRetry(reconciler, req)
Eventually(func() string {
By("Reconcile again and should not have error")
reconcileRetry(reconciler, req)
err := k8sClient.Get(ctx, appConfigKey, &appConfig)
if err != nil {
return err.Error()
}
if len(appConfig.Status.Conditions) != 1 {
return "condition len should be 1 but now is " + strconv.Itoa(len(appConfig.Status.Conditions))
}
return string(appConfig.Status.Conditions[0].Reason)
}, 3*time.Second, 300*time.Millisecond).Should(BeEquivalentTo("ReconcileSuccess"))
time.Sleep(time.Second)
By("Check workload will not created even AC changed because apply once force working")
Expect(k8sClient.Get(ctx, workloadKey1, &wr)).Should(SatisfyAll(util.NotFoundMatcher{}))
By("Check the trait was updated as expected")
var tr unstructured.Unstructured
Eventually(func() error {
tr.SetAPIVersion("example.com/v1")
tr.SetKind("Foo")
var traitKey = client.ObjectKey{Namespace: namespace, Name: appConfig.Status.Workloads[0].Traits[0].Reference.Name}
return k8sClient.Get(ctx, traitKey, &tr)
}, time.Second, 300*time.Millisecond).Should(BeNil())
Expect(tr.Object["spec"]).Should(BeEquivalentTo(map[string]interface{}{"key": "test2"}))
By("===================================== Start to Upgrade revision of component =========================================")
cmpV2 := &v1alpha2.Component{}
Expect(k8sClient.Get(ctx, client.ObjectKey{Namespace: namespace, Name: compName}, cmpV2)).Should(Succeed())
cmpV2.Spec.Workload = runtime.RawExtension{
Object: getDeploy("wordpress:v2"),
}
By("Update Component")
Expect(k8sClient.Update(ctx, cmpV2)).Should(Succeed())
By("component handler will automatically create a ne controller revision")
Expect(func() bool { _, ok := componentHandler.createControllerRevision(cmpV2, cmpV2); return ok }()).Should(BeTrue())
By("Check controller revision created successfully")
Eventually(func() error {
labels := &metav1.LabelSelector{
MatchLabels: map[string]string{
ControllerRevisionComponentLabel: compName,
},
}
selector, err := metav1.LabelSelectorAsSelector(labels)
if err != nil {
return err
}
err = k8sClient.List(ctx, &crList, &client.ListOptions{
LabelSelector: selector,
})
if err != nil {
return err
}
if len(crList.Items) != 2 {
return fmt.Errorf("there should be exactly 2 revision created but got %d", len(crList.Items))
}
return nil
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Update appConfig & check successfully")
appConfig.Spec.Components[0].RevisionName = compName + "-v2"
appConfig.Spec.Components[0].Traits[0].Trait = runtime.RawExtension{Object: &unstructured.Unstructured{Object: map[string]interface{}{
"apiVersion": "example.com/v1",
"kind": "Foo",
"metadata": map[string]interface{}{
"labels": map[string]interface{}{
"trait.oam.dev/type": "rollout-revision",
},
},
"spec": map[string]interface{}{
"key": "test3",
},
}}}
Expect(k8sClient.Update(ctx, &appConfig)).Should(Succeed())
Eventually(func() error {
return k8sClient.Get(ctx, appConfigKey, &appConfig)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Reconcile for new revision")
reconcileRetry(reconciler, req)
By("Check new revision workload created successfully")
Eventually(func() error {
reconcileRetry(reconciler, req)
var workloadKey = client.ObjectKey{Namespace: namespace, Name: compName + "-v2"}
return k8sClient.Get(ctx, workloadKey, &wr)
}, time.Second, 300*time.Millisecond).Should(BeNil())
By("Check the new workload should only have 1 generation")
Expect(wr.GetGeneration()).Should(BeEquivalentTo(1))
Expect(wr.Spec.Template.Spec.Containers[0].Image).Should(BeEquivalentTo("wordpress:v2"))
By("Check the new workload should only have 1 generation")
Expect(wr.GetGeneration()).Should(BeEquivalentTo(1))
By("Check reconcile again and no error will happen")
reconcileRetry(reconciler, req)
By("Check appconfig condition should not have error")
Eventually(func() string {
By("Once more Reconcile and should not have error")
reconcileRetry(reconciler, req)
err := k8sClient.Get(ctx, appConfigKey, &appConfig)
if err != nil {
return err.Error()
}
if len(appConfig.Status.Conditions) != 1 {
return "condition len should be 1 but now is " + strconv.Itoa(len(appConfig.Status.Conditions))
}
return string(appConfig.Status.Conditions[0].Reason)
}, 3*time.Second, 300*time.Millisecond).Should(BeEquivalentTo("ReconcileSuccess"))
By("Check trait was updated as expected")
Eventually(func() error {
tr.SetAPIVersion("example.com/v1")
tr.SetKind("Foo")
var traitKey = client.ObjectKey{Namespace: namespace, Name: appConfig.Status.Workloads[0].Traits[0].Reference.Name}
return k8sClient.Get(ctx, traitKey, &tr)
}, time.Second, 300*time.Millisecond).Should(BeNil())
Expect(tr.Object["spec"]).Should(BeEquivalentTo(map[string]interface{}{"key": "test3"}))
reconciler.applyOnceOnlyMode = "off"
})
})

View File

@@ -44,7 +44,7 @@ var k8sClient client.Client
var scheme = runtime.NewScheme()
var crd crdv1.CustomResourceDefinition
func TestReconcilder(t *testing.T) {
func TestReconcilerSuit(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecsWithDefaultAndCustomReporters(t,
@@ -150,7 +150,7 @@ var _ = BeforeSuite(func(done Done) {
}, time.Second*30, time.Millisecond*500).Should(BeNil())
Expect(mapping.Resource.Resource).Should(Equal("foo"))
reconciler = NewReconciler(mgr, dm, WithLogger(logging.NewLogrLogger(ctrl.Log.WithName("suit-test-appconfig"))))
reconciler = NewReconciler(mgr, dm, logging.NewLogrLogger(ctrl.Log.WithName("suit-test-appconfig")))
componentHandler = &ComponentHandler{Client: k8sClient, RevisionLimit: 100, Logger: logging.NewLogrLogger(ctrl.Log.WithName("component-handler"))}
By("Creating workload definition and trait definition")

View File

@@ -301,12 +301,13 @@ func PassLabel(parentObj oam.Object, childObj labelAnnotationObject) {
childObj.SetLabels(MergeMapOverrideWithDst(parentObj.GetLabels(), childObj.GetLabels()))
}
// PassLabelAndAnnotation passes through labels and annotation objectMeta from the parent to the child object
// PassLabelAndAnnotation passes through labels and annotation objectMeta from the parent to the child object,
// when annotation or labels has conflicts, the parentObj will override the childObj.
func PassLabelAndAnnotation(parentObj oam.Object, childObj labelAnnotationObject) {
// pass app-config labels
childObj.SetLabels(MergeMapOverrideWithDst(parentObj.GetLabels(), childObj.GetLabels()))
childObj.SetLabels(MergeMapOverrideWithDst(childObj.GetLabels(), parentObj.GetLabels()))
// pass app-config annotation
childObj.SetAnnotations(MergeMapOverrideWithDst(parentObj.GetAnnotations(), childObj.GetAnnotations()))
childObj.SetAnnotations(MergeMapOverrideWithDst(childObj.GetAnnotations(), parentObj.GetAnnotations()))
}
// GetDefinitionName return the Definition name of any resources

View File

@@ -1192,7 +1192,7 @@ func TestPassThroughObjMeta(t *testing.T) {
gotAnnotation = u.GetAnnotations()
wantAnnotation = map[string]string{
"key1": "exist value1",
"key1": "value1",
"key2": "value2",
"key3": "value3",
}
@@ -1200,7 +1200,7 @@ func TestPassThroughObjMeta(t *testing.T) {
gotLabels := u.GetLabels()
wantLabels := map[string]string{
"core.oam.dev/ns": "kube-system",
"core.oam.dev/ns": "oam-system",
"core.oam.dev/kube-native": "deployment",
"core.oam.dev/controller": "oam-kubernetes-runtime",
}

View File

@@ -3,22 +3,23 @@ package apply
import (
"context"
"github.com/crossplane/crossplane-runtime/pkg/logging"
"github.com/pkg/errors"
kerrors "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/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
"github.com/oam-dev/kubevela/pkg/oam"
)
// Applicator applies new state to an object or create it if not exist.
// It employes the same mechanism as `kubectl apply`, that is, for each resource being applied,
// It uses the same mechanism as `kubectl apply`, that is, for each resource being applied,
// computing a three-way diff merge in client side based on its current state, modified stated,
// and last-applied-state which is tracked through an specific annotaion.
// and last-applied-state which is tracked through an specific annotation.
// If the resource doesn't exist before, Apply will create it.
type Applicator interface {
Apply(context.Context, runtime.Object, ...ApplyOption) error
@@ -32,20 +33,23 @@ type ApplyOption func(ctx context.Context, existing, desired runtime.Object) err
// NewAPIApplicator creates an Applicator that applies state to an
// object or creates the object if not exist.
func NewAPIApplicator(c client.Client) *APIApplicator {
func NewAPIApplicator(c client.Client, log logging.Logger) *APIApplicator {
return &APIApplicator{
creatorFn(createOrGetExisting),
patcherFn(threeWayMergePatch), c}
creator: creatorFn(createOrGetExisting),
patcher: patcherFn(threeWayMergePatch),
c: c,
log: log,
}
}
type creator interface {
createOrGetExisting(context.Context, client.Client, runtime.Object, ...ApplyOption) (runtime.Object, error)
createOrGetExisting(context.Context, logging.Logger, client.Client, runtime.Object, ...ApplyOption) (runtime.Object, error)
}
type creatorFn func(context.Context, client.Client, runtime.Object, ...ApplyOption) (runtime.Object, error)
type creatorFn func(context.Context, logging.Logger, client.Client, runtime.Object, ...ApplyOption) (runtime.Object, error)
func (fn creatorFn) createOrGetExisting(ctx context.Context, c client.Client, o runtime.Object, ao ...ApplyOption) (runtime.Object, error) {
return fn(ctx, c, o, ao...)
func (fn creatorFn) createOrGetExisting(ctx context.Context, log logging.Logger, c client.Client, o runtime.Object, ao ...ApplyOption) (runtime.Object, error) {
return fn(ctx, log, c, o, ao...)
}
type patcher interface {
@@ -62,12 +66,23 @@ func (fn patcherFn) patch(c, m runtime.Object) (client.Patch, error) {
type APIApplicator struct {
creator
patcher
c client.Client
c client.Client
log logging.Logger
}
// loggingApply will record a log with desired object applied
func loggingApply(log logging.Logger, msg string, desired runtime.Object) {
d, ok := desired.(metav1.Object)
if !ok {
log.Debug(msg, "resource", desired.GetObjectKind().GroupVersionKind().String())
return
}
log.Debug(msg, "name", d.GetName(), "resource", desired.GetObjectKind().GroupVersionKind().String())
}
// Apply applies new state to an object or create it if not exist
func (a *APIApplicator) Apply(ctx context.Context, desired runtime.Object, ao ...ApplyOption) error {
existing, err := a.createOrGetExisting(ctx, a.c, desired, ao...)
existing, err := a.createOrGetExisting(ctx, a.log, a.c, desired, ao...)
if err != nil {
return err
}
@@ -79,6 +94,7 @@ func (a *APIApplicator) Apply(ctx context.Context, desired runtime.Object, ao ..
if err := executeApplyOptions(ctx, existing, desired, ao); err != nil {
return err
}
loggingApply(a.log, "patching object", desired)
patch, err := a.patcher.patch(existing, desired)
if err != nil {
return errors.Wrap(err, "cannot calculate patch by computing a three way diff")
@@ -88,7 +104,7 @@ func (a *APIApplicator) Apply(ctx context.Context, desired runtime.Object, ao ..
// createOrGetExisting will create the object if it does not exist
// or get and return the existing object
func createOrGetExisting(ctx context.Context, c client.Client, desired runtime.Object, ao ...ApplyOption) (runtime.Object, error) {
func createOrGetExisting(ctx context.Context, log logging.Logger, c client.Client, desired runtime.Object, ao ...ApplyOption) (runtime.Object, error) {
m, ok := desired.(oam.Object)
if !ok {
return nil, errors.New("cannot access object metadata")
@@ -102,6 +118,7 @@ func createOrGetExisting(ctx context.Context, c client.Client, desired runtime.O
if err := addLastAppliedConfigAnnotation(desired); err != nil {
return nil, err
}
loggingApply(log, "creating object", desired)
return nil, errors.Wrap(c.Create(ctx, desired), "cannot create object")
}

View File

@@ -11,6 +11,7 @@ import (
oamcore "github.com/oam-dev/kubevela/apis/core.oam.dev"
oamstd "github.com/oam-dev/kubevela/apis/standard.oam.dev/v1alpha1"
"github.com/crossplane/crossplane-runtime/pkg/logging"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
@@ -56,7 +57,7 @@ var _ = BeforeSuite(func(done Done) {
rawClient, err = client.New(cfg, client.Options{Scheme: testScheme})
Expect(err).ShouldNot(HaveOccurred())
Expect(rawClient).ShouldNot(BeNil())
k8sApplicator = NewAPIApplicator(rawClient)
k8sApplicator = NewAPIApplicator(rawClient, logging.NewNopLogger())
By("Create test namespace")
applyNS = corev1.Namespace{

View File

@@ -4,6 +4,7 @@ import (
"context"
"testing"
"github.com/crossplane/crossplane-runtime/pkg/logging"
"github.com/crossplane/crossplane-runtime/pkg/test"
"github.com/google/go-cmp/cmp"
"github.com/pkg/errors"
@@ -117,13 +118,14 @@ func TestAPIApplicator(t *testing.T) {
for caseName, tc := range cases {
t.Run(caseName, func(t *testing.T) {
a := &APIApplicator{
creator: creatorFn(func(_ context.Context, _ client.Client, _ runtime.Object, _ ...ApplyOption) (runtime.Object, error) {
creator: creatorFn(func(_ context.Context, _ logging.Logger, _ client.Client, _ runtime.Object, _ ...ApplyOption) (runtime.Object, error) {
return tc.args.existing, tc.args.creatorErr
}),
patcher: patcherFn(func(c, m runtime.Object) (client.Patch, error) {
return nil, tc.args.patcherErr
}),
c: tc.c,
c: tc.c,
log: logging.NewNopLogger(),
}
result := a.Apply(ctx, tc.args.desired, tc.args.ao...)
if diff := cmp.Diff(tc.want, result, test.EquateErrors()); diff != "" {
@@ -284,7 +286,7 @@ func TestCreator(t *testing.T) {
for caseName, tc := range cases {
t.Run(caseName, func(t *testing.T) {
result, err := createOrGetExisting(ctx, tc.c, tc.args.desired, tc.args.ao...)
result, err := createOrGetExisting(ctx, logging.NewNopLogger(), tc.c, tc.args.desired, tc.args.ao...)
if diff := cmp.Diff(tc.want.existing, result); diff != "" {
t.Errorf("\n%s\ncreateOrGetExisting(...): -want , +got \n%s\n", tc.reason, diff)
}