From 71a02b434b3e85c56c43d761b8db46bef94ec63e Mon Sep 17 00:00:00 2001 From: Jianbo Sun Date: Mon, 20 Jun 2022 16:15:06 +0800 Subject: [PATCH] Feat: support dry run for policy (#4201) * Feat: support dry run for policy Signed-off-by: Jianbo Sun * Fix: upgrade runc package Signed-off-by: Jianbo Sun --- go.mod | 4 +- go.sum | 19 ++- pkg/apiserver/domain/service/application.go | 32 ++--- pkg/appfile/dryrun/diff.go | 8 +- pkg/appfile/dryrun/dryrun.go | 55 ++++++++- pkg/appfile/dryrun/dryrun_test.go | 2 +- references/cli/debug.go | 2 +- references/cli/def.go | 3 +- references/cli/dryrun.go | 26 +--- references/cli/dryrun_test.go | 127 ++++++++++++++++++++ 10 files changed, 212 insertions(+), 66 deletions(-) create mode 100644 references/cli/dryrun_test.go diff --git a/go.mod b/go.mod index da47881a2..0949f4979 100644 --- a/go.mod +++ b/go.mod @@ -56,7 +56,7 @@ require ( github.com/olekukonko/tablewriter v0.0.5 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.19.0 - github.com/opencontainers/runc v1.0.3 // indirect + github.com/opencontainers/runc v1.1.3 // indirect github.com/openkruise/kruise-api v1.1.0 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.11.0 @@ -146,7 +146,7 @@ require ( github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/creack/pty v1.1.11 // indirect - github.com/cyphar/filepath-securejoin v0.2.2 // indirect + github.com/cyphar/filepath-securejoin v0.2.3 // indirect github.com/docker/cli v20.10.16+incompatible // indirect github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker v20.10.16+incompatible // indirect diff --git a/go.sum b/go.sum index d5d45c6a3..a9f6ef7b3 100644 --- a/go.sum +++ b/go.sum @@ -369,6 +369,7 @@ github.com/charithe/durationcheck v0.0.9/go.mod h1:SSbRIBVfMjCi/kEB6K65XEA83D6pr github.com/chavacava/garif v0.0.0-20210405164556-e8a0a408d6af/go.mod h1:Qjyv4H3//PWVzTeCezG2b9IRn6myJxJSr4TD/xo6ojU= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= +github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= @@ -378,6 +379,7 @@ github.com/cilium/ebpf v0.0.0-20200702112145-1c8d4c9ef775/go.mod h1:7cR51M8ViRLI github.com/cilium/ebpf v0.2.0/go.mod h1:To2CFviqOWL/M0gIMsvSMlqe7em/l1ALkX1PyjrX2Qs= github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs= +github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= @@ -420,6 +422,7 @@ github.com/containerd/console v0.0.0-20181022165439-0650fd9eeb50/go.mod h1:Tj/on github.com/containerd/console v0.0.0-20191206165004-02ecf6a7291e/go.mod h1:8Pf4gM6VEbTNRIT26AyyU7hxdQU3MvAvxVI0sc00XBE= github.com/containerd/console v1.0.1/go.mod h1:XUsP6YE/mKtz6bxc+I8UiKKTP04qjQL4qcS3XoQ5xkw= github.com/containerd/console v1.0.2/go.mod h1:ytZPjGgY2oeTkAONYafi2kSj0aYggsf8acV1PGKCbzQ= +github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U= github.com/containerd/containerd v1.2.10/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0-beta.2.0.20190828155532-0293cbd26c69/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA= @@ -531,8 +534,9 @@ github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd h1:2ZdR/HyjXFIo6KxmM08jBLeiJs7GRdGmb6qPKQANGvI= github.com/crossplane/crossplane-runtime v0.14.1-0.20210722005935-0b469fcc77cd/go.mod h1:0sB8XOV2zy1GdZvSMY0/5QzKQJUiNSek08wbAYHJbws= -github.com/cyphar/filepath-securejoin v0.2.2 h1:jCwT2GTP+PY5nBz3c/YL5PAIbusElVrPujOBSCj8xRg= github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4= +github.com/cyphar/filepath-securejoin v0.2.3 h1:YX6ebbZCZP7VkM3scTTokDgBL2TY741X51MTk3ycuNI= +github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1SMSibvLzxjeJLnrYEVLULFNiHY9YfQ= github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s= github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8= @@ -897,6 +901,7 @@ github.com/godbus/dbus v0.0.0-20180201030542-885f9cc04c9c/go.mod h1:/YcGZj5zSblf github.com/godbus/dbus v0.0.0-20190422162347-ade71ed3457e/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godror/godror v0.24.2/go.mod h1:wZv/9vPiUib6tkoDl+AZ/QLf5YZgMravZ7jxH2eQWAE= github.com/gofrs/flock v0.8.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= @@ -1506,8 +1511,9 @@ github.com/moby/moby v17.12.0-ce-rc1.0.20200618181300-9dc6525e6118+incompatible/ github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/sys/mountinfo v0.4.0/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= -github.com/moby/sys/mountinfo v0.4.1 h1:1O+1cHA1aujwEwwVMa2Xm2l+gIpUHyd3+D+d7LZh1kM= github.com/moby/sys/mountinfo v0.4.1/go.mod h1:rEr8tzG/lsIZHBtN/JjGG+LMYx9eXgW2JI+6q0qou+A= +github.com/moby/sys/mountinfo v0.5.0 h1:2Ks8/r6lopsxWi9m58nlwjaeSzUX9iiL1vj5qB/9ObI= +github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU= github.com/moby/sys/symlink v0.1.0/go.mod h1:GGDODQmbFOjFsXvfLVn3+ZRxkch54RkSiGqsZeMYowQ= github.com/moby/term v0.0.0-20200312100748-672ec06f55cd/go.mod h1:DdlQx2hp0Ss5/fLikoLlEeIYiATotOjgB//nb973jeo= github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc= @@ -1643,8 +1649,8 @@ github.com/opencontainers/runc v1.0.0-rc8.0.20190926000215-3e425f80a8c9/go.mod h github.com/opencontainers/runc v1.0.0-rc9/go.mod h1:qT5XzbpPznkRYVz/mWwUaVBUv2rmF59PVA73FjuZG0U= github.com/opencontainers/runc v1.0.0-rc93/go.mod h1:3NOsor4w32B2tC0Zbl8Knk4Wg84SM2ImC1fxBuqJ/H0= github.com/opencontainers/runc v1.0.2/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= -github.com/opencontainers/runc v1.0.3 h1:1hbqejyQWCJBvtKAfdO0b1FmaEf2z/bxnjqbARass5k= -github.com/opencontainers/runc v1.0.3/go.mod h1:aTaHFFwQXuA71CiyxOdFFIorAoemI04suvGRQFzWTD0= +github.com/opencontainers/runc v1.1.3 h1:vIXrkId+0/J2Ymu2m7VjGvbSlAId9XNRPhn2p4b+d8w= +github.com/opencontainers/runc v1.1.3/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg= github.com/opencontainers/runtime-spec v0.1.2-0.20190507144316-5b71a03e2700/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.0.2-0.20190207185410-29686dbc5559/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= @@ -1655,6 +1661,7 @@ github.com/opencontainers/runtime-tools v0.0.0-20181011054405-1d69bd0f9c39/go.mo github.com/opencontainers/selinux v1.6.0/go.mod h1:VVGKuOLlE7v4PJyT6h7mNWvq1rzqiriPsEqVhc+svHE= github.com/opencontainers/selinux v1.8.0/go.mod h1:RScLhm78qiWa2gbVCcGkC7tCGdgk3ogry1nUQF8Evvo= github.com/opencontainers/selinux v1.8.2/go.mod h1:MUIHuUEvKB1wtJjQdOyYRgOnLD2xAPP8dBsCoU0KuF8= +github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/openkruise/kruise-api v1.1.0 h1:ZRhV0FnxUp4XHc60YPkUqj2LJD4GRFB92qhtdgU6Zhc= github.com/openkruise/kruise-api v1.1.0/go.mod h1:kxV/UA/vrf/hz3z+kL21c0NOawC6K1ZjaKcJFgiOwsE= github.com/openshift/api v0.0.0-20210915110300-3cd8091317c4/go.mod h1:RsQCVJu4qhUawxxDP7pGlwU3IA4F01wYm3qKEu29Su8= @@ -1849,6 +1856,7 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= +github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg= github.com/securego/gosec/v2 v2.8.0/go.mod h1:hJZ6NT5TqoY+jmOsaxAV4cXoEdrMRLVaNPnSpUCvCZs= github.com/securego/gosec/v2 v2.9.1/go.mod h1:oDcDLcatOJxkCGaCaq8lua1jTnYf6Sou4wdiJ1n4iHc= github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= @@ -2541,14 +2549,17 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211029165221-6e7872819dc8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211110154304-99a53858aa08/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/apiserver/domain/service/application.go b/pkg/apiserver/domain/service/application.go index f1b29eb1c..a21229687 100644 --- a/pkg/apiserver/domain/service/application.go +++ b/pkg/apiserver/domain/service/application.go @@ -29,7 +29,6 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/selection" "k8s.io/apimachinery/pkg/types" @@ -1584,38 +1583,21 @@ func dryRunApplication(ctx context.Context, c common2.Args, app *v1beta1.Applica return buff, err } dryRunOpt := dryrun.NewDryRunOption(newClient, config, dm, pd, objects) - comps, err := dryRunOpt.ExecuteDryRun(ctx, app) + comps, policies, err := dryRunOpt.ExecuteDryRun(ctx, app) if err != nil { return buff, fmt.Errorf("generate OAM objects %w", err) } - var components = make(map[string]*unstructured.Unstructured) - for _, comp := range comps { - components[comp.Name] = comp.StandardWorkload + if _, err = fmt.Fprintf(&buff, "---\n# Application(%s) \n---\n\n", app.Name); err != nil { + return buff, fmt.Errorf("fail to write to buff %w", err) } - buff.Write([]byte(fmt.Sprintf("---\n# Application(%s) \n---\n\n", app.Name))) result, err := yaml.Marshal(app) if err != nil { - return buff, errors.New("marshal app error") + return buff, fmt.Errorf("marshal app: %w", err) } buff.Write(result) - buff.Write([]byte("\n---\n")) - for _, c := range comps { - buff.Write([]byte(fmt.Sprintf("---\n# Application(%s) -- Component(%s) \n---\n\n", app.Name, c.Name))) - result, err := yaml.Marshal(components[c.Name]) - if err != nil { - return buff, errors.New("marshal result for component " + c.Name + " object in yaml format") - } - buff.Write(result) - buff.Write([]byte("\n---\n")) - for _, t := range c.Traits { - result, err := yaml.Marshal(t) - if err != nil { - return buff, errors.New("marshal result for component " + c.Name + " object in yaml format") - } - buff.Write(result) - buff.Write([]byte("\n---\n")) - } - buff.Write([]byte("\n")) + buff.WriteString("\n---\n") + if err = dryRunOpt.PrintDryRun(&buff, app.Name, comps, policies); err != nil { + return buff, err } return buff, nil } diff --git a/pkg/appfile/dryrun/diff.go b/pkg/appfile/dryrun/diff.go index cab39e8f1..8e4daff54 100644 --- a/pkg/appfile/dryrun/diff.go +++ b/pkg/appfile/dryrun/diff.go @@ -232,8 +232,9 @@ func (l *LiveDiffOption) diffManifest(base, comparor *manifest) *DiffEntry { // Diff does three phases, dry-run on input app, preparing manifest for diff, and // calculating diff on manifests. +// TODO(wonderflow): vela live-diff don't diff for policies now. func (l *LiveDiffOption) Diff(ctx context.Context, app *v1beta1.Application, appRevision *v1beta1.ApplicationRevision) (*DiffEntry, error) { - comps, err := l.ExecuteDryRun(ctx, app) + comps, _, err := l.ExecuteDryRun(ctx, app) if err != nil { return nil, errors.WithMessagef(err, "cannot dry-run for app %q", app.Name) } @@ -254,8 +255,9 @@ func (l *LiveDiffOption) Diff(ctx context.Context, app *v1beta1.Application, app // DiffApps does three phases, dry-run on input app, preparing manifest for diff, and // calculating diff on manifests. +// TODO(wonderflow): vela live-diff don't diff for policies now. func (l *LiveDiffOption) DiffApps(ctx context.Context, app *v1beta1.Application, oldApp *v1beta1.Application) (*DiffEntry, error) { - comps, err := l.ExecuteDryRun(ctx, app) + comps, _, err := l.ExecuteDryRun(ctx, app) if err != nil { return nil, errors.WithMessagef(err, "cannot dry-run for app %q", app.Name) } @@ -265,7 +267,7 @@ func (l *LiveDiffOption) DiffApps(ctx context.Context, app *v1beta1.Application, return nil, errors.WithMessagef(err, "cannot generate diff manifest for app %q", app.Name) } - oldComps, err := l.ExecuteDryRun(ctx, oldApp) + oldComps, _, err := l.ExecuteDryRun(ctx, oldApp) if err != nil { return nil, errors.WithMessagef(err, "cannot dry-run for app %q", oldApp.Name) } diff --git a/pkg/appfile/dryrun/dryrun.go b/pkg/appfile/dryrun/dryrun.go index 6dc351034..e97048812 100644 --- a/pkg/appfile/dryrun/dryrun.go +++ b/pkg/appfile/dryrun/dryrun.go @@ -17,8 +17,10 @@ limitations under the License. package dryrun import ( + "bytes" "context" "encoding/json" + "fmt" "os" "path/filepath" @@ -44,7 +46,7 @@ import ( // DryRun executes dry-run on an application type DryRun interface { - ExecuteDryRun(ctx context.Context, app *v1beta1.Application) ([]*types.ComponentManifest, error) + ExecuteDryRun(ctx context.Context, app *v1beta1.Application) ([]*types.ComponentManifest, []*unstructured.Unstructured, error) } // NewDryRunOption creates a dry-run option @@ -120,22 +122,65 @@ func (d *Option) ValidateApp(ctx context.Context, filename string) error { // ExecuteDryRun simulates applying an application into cluster and returns rendered // resources but not persist them into cluster. -func (d *Option) ExecuteDryRun(ctx context.Context, app *v1beta1.Application) ([]*types.ComponentManifest, error) { +func (d *Option) ExecuteDryRun(ctx context.Context, app *v1beta1.Application) ([]*types.ComponentManifest, []*unstructured.Unstructured, error) { parser := appfile.NewDryRunApplicationParser(d.Client, d.DiscoveryMapper, d.PackageDiscover, d.Auxiliaries) if app.Namespace != "" { ctx = oamutil.SetNamespaceInCtx(ctx, app.Namespace) } appFile, err := parser.GenerateAppFileFromApp(ctx, app) if err != nil { - return nil, errors.WithMessage(err, "cannot generate appFile from application") + return nil, nil, errors.WithMessage(err, "cannot generate appFile from application") } if appFile.Namespace == "" { appFile.Namespace = corev1.NamespaceDefault } comps, err := appFile.GenerateComponentManifests() if err != nil { - return nil, errors.WithMessage(err, "cannot generate AppConfig and Components") + return nil, nil, errors.WithMessage(err, "cannot generate manifests from components and traits") } + objs, err := appFile.GeneratePolicyManifests(ctx) + if err != nil { + return nil, nil, errors.WithMessage(err, "cannot generate manifests from policies") + } + return comps, objs, nil +} - return comps, nil +// PrintDryRun will print the result of dry-run +func (d *Option) PrintDryRun(buff *bytes.Buffer, appName string, comps []*types.ComponentManifest, policies []*unstructured.Unstructured) error { + var components = make(map[string]*unstructured.Unstructured) + for _, comp := range comps { + components[comp.Name] = comp.StandardWorkload + } + for _, c := range comps { + if _, err := fmt.Fprintf(buff, "---\n# Application(%s) -- Component(%s) \n---\n\n", appName, c.Name); err != nil { + return errors.Wrap(err, "fail to write buff") + } + result, err := yaml.Marshal(components[c.Name]) + if err != nil { + return errors.New("marshal result for component " + c.Name + " object in yaml format") + } + buff.Write(result) + buff.WriteString("\n---\n") + for _, t := range c.Traits { + result, err := yaml.Marshal(t) + if err != nil { + return errors.New("marshal result for Component " + c.Name + " trait " + t.GetName() + " object in yaml format") + } + buff.Write(result) + buff.WriteString("\n---\n") + } + buff.WriteString("\n") + } + for _, plc := range policies { + if _, err := fmt.Fprintf(buff, "---\n# Application(%s) -- Policy(%s) \n---\n\n", appName, plc.GetName()); err != nil { + return errors.Wrap(err, "fail to write buff") + } + result, err := yaml.Marshal(plc) + if err != nil { + return errors.New("marshal result for policy " + plc.GetName() + " object in yaml format") + } + buff.Write(result) + buff.WriteString("\n---\n") + } + return nil } diff --git a/pkg/appfile/dryrun/dryrun_test.go b/pkg/appfile/dryrun/dryrun_test.go index 929767648..791fe844c 100644 --- a/pkg/appfile/dryrun/dryrun_test.go +++ b/pkg/appfile/dryrun/dryrun_test.go @@ -42,7 +42,7 @@ var _ = Describe("Test DryRun", func() { Expect(err).Should(BeNil()) By("Execute DryRun") - comps, err := dryrunOpt.ExecuteDryRun(context.Background(), app) + comps, _, err := dryrunOpt.ExecuteDryRun(context.Background(), app) Expect(err).Should(BeNil()) expectCompYAML := readDataFromFile("./testdata/dryrun-exp-comp.yaml") diff --git a/references/cli/debug.go b/references/cli/debug.go index 80a2c40d2..0813f59e5 100644 --- a/references/cli/debug.go +++ b/references/cli/debug.go @@ -133,7 +133,7 @@ func (d *debugOpts) debugApplication(ctx context.Context, c common.Args, app *v1 return err } dryRunOpt := dryrun.NewDryRunOption(cli, config, dm, pd, []oam.Object{}) - comps, err := dryRunOpt.ExecuteDryRun(ctx, app) + comps, _, err := dryRunOpt.ExecuteDryRun(ctx, app) if err != nil { ioStreams.Info(color.RedString("%s%s", emojiFail, err.Error())) return nil diff --git a/references/cli/def.go b/references/cli/def.go index fefecc2de..21a911361 100644 --- a/references/cli/def.go +++ b/references/cli/def.go @@ -30,8 +30,6 @@ import ( "strings" "time" - "github.com/oam-dev/kubevela/pkg/cue/packages" - "cuelang.org/go/cue" "cuelang.org/go/encoding/gocode/gocodec" crossplane "github.com/oam-dev/terraform-controller/api/types/crossplane-runtime" @@ -50,6 +48,7 @@ import ( "github.com/oam-dev/kubevela/apis/types" "github.com/oam-dev/kubevela/pkg/cue/model" "github.com/oam-dev/kubevela/pkg/cue/model/sets" + "github.com/oam-dev/kubevela/pkg/cue/packages" pkgdef "github.com/oam-dev/kubevela/pkg/definition" "github.com/oam-dev/kubevela/pkg/utils/common" "github.com/oam-dev/kubevela/references/plugins" diff --git a/references/cli/dryrun.go b/references/cli/dryrun.go index fa387b9fd..262550cc1 100644 --- a/references/cli/dryrun.go +++ b/references/cli/dryrun.go @@ -20,7 +20,6 @@ import ( "bytes" "context" "encoding/json" - "fmt" "os" "path/filepath" @@ -144,32 +143,13 @@ func DryRunApplication(cmdOption *DryRunCmdOptions, c common.Args, namespace str return buff, errors.WithMessagef(err, "read application file: %s", cmdOption.ApplicationFile) } - comps, err := dryRunOpt.ExecuteDryRun(ctx, app) + comps, policies, err := dryRunOpt.ExecuteDryRun(ctx, app) if err != nil { return buff, errors.WithMessage(err, "generate OAM objects") } - var components = make(map[string]*unstructured.Unstructured) - for _, comp := range comps { - components[comp.Name] = comp.StandardWorkload - } - for _, c := range comps { - buff.Write([]byte(fmt.Sprintf("---\n# Application(%s) -- Component(%s) \n---\n\n", app.Name, c.Name))) - result, err := yaml.Marshal(components[c.Name]) - if err != nil { - return buff, errors.WithMessage(err, "marshal result for component "+c.Name+" object in yaml format") - } - buff.Write(result) - buff.Write([]byte("\n---\n")) - for _, t := range c.Traits { - result, err := yaml.Marshal(t) - if err != nil { - return buff, errors.WithMessage(err, "marshal result for component "+c.Name+" object in yaml format") - } - buff.Write(result) - buff.Write([]byte("\n---\n")) - } - buff.Write([]byte("\n")) + if err = dryRunOpt.PrintDryRun(&buff, app.Name, comps, policies); err != nil { + return buff, err } return buff, nil } diff --git a/references/cli/dryrun_test.go b/references/cli/dryrun_test.go new file mode 100644 index 000000000..a1be93030 --- /dev/null +++ b/references/cli/dryrun_test.go @@ -0,0 +1,127 @@ +/* + Copyright 2022 The KubeVela Authors. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cli + +import ( + "bytes" + "context" + "io/ioutil" + "strings" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "sigs.k8s.io/yaml" + + "github.com/oam-dev/kubevela/apis/core.oam.dev/v1beta1" + "github.com/oam-dev/kubevela/apis/types" + "github.com/oam-dev/kubevela/pkg/appfile/dryrun" + "github.com/oam-dev/kubevela/pkg/oam/discoverymapper" + common2 "github.com/oam-dev/kubevela/pkg/utils/common" +) + +var _ = Describe("Test dry run with policy", func() { + It("Test dry run with normal policy", func() { + webservice, err := ioutil.ReadFile("../../charts/vela-core/templates/defwithtemplate/webservice.yaml") + Expect(err).Should(BeNil()) + webserviceYAML := strings.Replace(string(webservice), "{{ include \"systemDefinitionNamespace\" . }}", types.DefaultKubeVelaNS, 1) + wwd := v1beta1.ComponentDefinition{} + Expect(yaml.Unmarshal([]byte(webserviceYAML), &wwd)).Should(BeNil()) + Expect(k8sClient.Create(context.TODO(), &wwd)).Should(BeNil()) + + plcd := v1beta1.PolicyDefinition{} + Expect(yaml.Unmarshal([]byte(plcdef), &plcd)).Should(BeNil()) + plcd.Namespace = types.DefaultKubeVelaNS + Expect(k8sClient.Create(context.TODO(), &plcd)).Should(BeNil()) + app := v1beta1.Application{} + Expect(yaml.Unmarshal([]byte(plcapp), &app)).Should(BeNil()) + c := common2.Args{} + c.SetConfig(cfg) + c.SetClient(k8sClient) + pd, err := c.GetPackageDiscover() + Expect(err).Should(BeNil()) + dm, err := discoverymapper.New(cfg) + Expect(err).Should(BeNil()) + + dryRunOpt := dryrun.NewDryRunOption(k8sClient, cfg, dm, pd, nil) + + comps, plcs, err := dryRunOpt.ExecuteDryRun(context.TODO(), &app) + Expect(err).Should(BeNil()) + speci := plcs[0].Object["spec"].(map[string]interface{}) + Expect(speci["service"].(string)).Should(BeEquivalentTo("unified")) + buff := bytes.NewBufferString("") + Expect(dryRunOpt.PrintDryRun(buff, app.Name, comps, plcs)).Should(BeNil()) + Expect(buff.String()).Should(ContainSubstring(`backends: + - service: server-v1 + weight: 80 + - service: server-v2 + weight: 20 + service: unified`)) + Expect(buff.String()).Should(ContainSubstring("- image: oamdev/hello-world:v1\n name: server-v1")) + Expect(buff.String()).Should(ContainSubstring("- image: oamdev/hello-world:v2\n name: server-v2")) + }) + +}) + +var plcapp = `apiVersion: core.oam.dev/v1beta1 +kind: Application +metadata: + name: my-test-2 +spec: + components: + - name: server-v1 + type: webservice + properties: + image: oamdev/hello-world:v1 + - name: server-v2 + type: webservice + properties: + image: oamdev/hello-world:v2 + policies: + - type: my-plc + name: unified + properties: + weights: + - service: server-v1 + weight: 80 + - service: server-v2 + weight: 20 +` + +var plcdef = `apiVersion: core.oam.dev/v1beta1 +kind: PolicyDefinition +metadata: + annotations: + definition.oam.dev/description: My ingress route policy. + name: my-plc +spec: + schematic: + cue: + template: | + #ServerWeight: { + service: string + weight: int + } + parameter: weights: [...#ServerWeight] + output: { + apiVersion: "split.smi-spec.io/v1alpha3" + kind: "TrafficSplit" + metadata: name: context.name + spec: { + service: context.name + backends: parameter.weights + } + }`