diff --git a/go.mod b/go.mod index 2ae9b176f..ddbaaa38e 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/k14s/kbld v0.32.0 github.com/lithammer/dedent v1.1.0 github.com/logrusorgru/aurora v2.0.3+incompatible + github.com/mattn/go-sqlite3 v1.14.16 github.com/onsi/ginkgo v1.16.5 github.com/onsi/gomega v1.20.1 github.com/otiai10/copy v1.4.2 @@ -29,11 +30,11 @@ require ( github.com/stretchr/testify v1.8.1 github.com/tj/assert v0.0.3 github.com/vmware-tanzu/carvel-ytt v0.40.0 - github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20221202212418-359f504ed815 + github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20230121092944-3710280bf92a github.com/vmware-tanzu/tanzu-plugin-runtime v0.0.0-20230125222721-2af61852d9fb go.uber.org/multierr v1.8.0 golang.org/x/mod v0.6.0 - golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 + golang.org/x/oauth2 v0.3.0 google.golang.org/grpc v1.48.0 gopkg.in/yaml.v2 v2.4.0 gopkg.in/yaml.v3 v3.0.1 @@ -63,7 +64,7 @@ require ( github.com/docker/distribution v2.8.1+incompatible // indirect github.com/docker/docker v20.10.16+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect - github.com/emicklei/go-restful/v3 v3.8.0 // indirect + github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch/v5 v5.6.0 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect @@ -115,13 +116,13 @@ require ( github.com/vmware-tanzu/carvel-vendir v0.26.0 // indirect github.com/vmware-tanzu/tanzu-framework/apis/run v0.0.0-20221207131309-7323ca04b86c // indirect go.uber.org/atomic v1.9.0 // indirect - golang.org/x/crypto v0.1.0 // indirect - golang.org/x/net v0.2.0 // indirect + golang.org/x/crypto v0.3.0 // indirect + golang.org/x/net v0.4.0 // indirect golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect - golang.org/x/sys v0.2.0 // indirect - golang.org/x/term v0.2.0 // indirect - golang.org/x/text v0.4.0 // indirect - golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect + golang.org/x/sys v0.3.0 // indirect + golang.org/x/term v0.3.0 // indirect + golang.org/x/text v0.5.0 // indirect + golang.org/x/time v0.3.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect google.golang.org/appengine v1.6.7 // indirect google.golang.org/genproto v0.0.0-20220810155839-1856144b1d9c // indirect @@ -131,10 +132,10 @@ require ( k8s.io/apiextensions-apiserver v0.25.0 // indirect k8s.io/component-base v0.25.0 // indirect k8s.io/klog/v2 v2.70.1 // indirect - k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect + k8s.io/kube-openapi v0.0.0-20221207184640-f3cff1453715 // indirect k8s.io/kubectl v0.24.0 // indirect k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect - sigs.k8s.io/cluster-api v1.2.7 // indirect + sigs.k8s.io/cluster-api v1.2.8 // indirect sigs.k8s.io/json v0.0.0-20220713155537-f223a00ba0e2 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect diff --git a/go.sum b/go.sum index ea4a1e9e6..baaf971b0 100644 --- a/go.sum +++ b/go.sum @@ -303,8 +303,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= -github.com/emicklei/go-restful/v3 v3.8.0 h1:eCZ8ulSerjdAiaNpF7GxXIE7ZCMo1moN1qX+S609eVw= -github.com/emicklei/go-restful/v3 v3.8.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= +github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= 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= @@ -620,6 +620,8 @@ github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRC github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= +github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= +github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 h1:I0XW9+e1XWDxdcEniV4rQAIOPUGDq67JSCiRCgGCZLI= github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= @@ -896,8 +898,8 @@ github.com/vmware-tanzu/carvel-ytt v0.40.0 h1:WUWTtwvfqV9CN9v207oDt2xfhmuWHGwc4M github.com/vmware-tanzu/carvel-ytt v0.40.0/go.mod h1:crDcKbS1GM4Q34puoVxdrajWOXrxjOxvUCwtsNV5Etc= github.com/vmware-tanzu/tanzu-framework/apis/run v0.0.0-20221207131309-7323ca04b86c h1:w1b5UNbfqUetv4f32qqkbh2ESV+0iZCpMlq72zfyDqs= github.com/vmware-tanzu/tanzu-framework/apis/run v0.0.0-20221207131309-7323ca04b86c/go.mod h1:ukZpKQ0hf5bjWdJLjn2M6qXP+9giZWQPxt8nOfrCR+o= -github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20221202212418-359f504ed815 h1:uuwq0KWncphYB4LA+OAi/XYfUgJP+Q9PnWzYgtudNoY= -github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20221202212418-359f504ed815/go.mod h1:dBxtBhdSqmHHHKGq0WwllQVuklNzDsAeP130lVOvqsc= +github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20230121092944-3710280bf92a h1:4eFwBDBd3zDxUzPxewLMJx3evqKsqrRAYjFrQNOQvqE= +github.com/vmware-tanzu/tanzu-framework/capabilities/client v0.0.0-20230121092944-3710280bf92a/go.mod h1:rcIfoGpdav3evsyEMMzYH0xhGZOkIy+Ra3koypM8Aco= github.com/vmware-tanzu/tanzu-plugin-runtime v0.0.0-20230125222721-2af61852d9fb h1:TtSEKblKfoD5Omzue3AcZpmXlMSgVSsh6so6U/szLsQ= github.com/vmware-tanzu/tanzu-plugin-runtime v0.0.0-20230125222721-2af61852d9fb/go.mod h1:CZNPe3l0Y2SgvKP1XcgKwAzio4KJRoKNFSIdRnbK9Ro= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= @@ -976,8 +978,8 @@ golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= +golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= @@ -1051,8 +1053,8 @@ golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.4.0 h1:Q5QPcMlvfxFTAPV0+07Xz/MpK9NTXu2VDUuy0FeMfaU= +golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1068,8 +1070,8 @@ golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1 h1:lxqLZaMad/dJHMFZH0NiNpiEZI/nhgWhe4wgzpE+MuA= -golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= +golang.org/x/oauth2 v0.3.0 h1:6l90koy8/LaBLmLu8jpHeHexzMwEita0zFfYlggy2F8= +golang.org/x/oauth2 v0.3.0/go.mod h1:rQrIauxkUhJ6CuwEXwymO2/eh4xz2ZWF1nBkcxS+tGk= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1179,13 +1181,13 @@ golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.3.0 h1:w8ZOecv6NaNa/zC8944JTU3vz4u6Lagfk4RPQxv92NQ= +golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.3.0 h1:qoo4akIqOcDME5bhc/NgxUdovd6BSS2uMsVjB56q1xI= +golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1193,15 +1195,15 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.5.0 h1:OLmvp0KP+FVG99Ct/qFiL/Fhk4zp4QQnZ7b2U+5piUM= +golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200416051211-89c76fbcd5d1/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20200630173020-3af7569d3a1e/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U= -golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -1464,8 +1466,8 @@ k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H k8s.io/kube-openapi v0.0.0-20201113171705-d219536bb9fd/go.mod h1:WOJ3KddDSol4tAGcJo0Tvi+dK12EcqSLqcWsryKMpfM= k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw= k8s.io/kube-openapi v0.0.0-20220328201542-3ee0da9b0b42/go.mod h1:Z/45zLw8lUo4wdiUkI+v/ImEGAvu3WatcZl3lPMR4Rk= -k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 h1:MQ8BAZPZlWk3S9K4a9NCkIFQtZShWqoha7snGixVgEA= -k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1/go.mod h1:C/N6wCaBHeBHkHUesQOQy2/MZqGgMAFPqGsGQLdbZBU= +k8s.io/kube-openapi v0.0.0-20221207184640-f3cff1453715 h1:tBEbstoM+K0FiBV5KGAKQ0kuvf54v/hwpldiJt69w1s= +k8s.io/kube-openapi v0.0.0-20221207184640-f3cff1453715/go.mod h1:+Axhij7bCpeqhklhUTe3xmOn6bWxolyZEeyaFpjGtl4= k8s.io/kubectl v0.24.0 h1:nA+WtMLVdXUs4wLogGd1mPTAesnLdBpCVgCmz3I7dXo= k8s.io/kubectl v0.24.0/go.mod h1:pdXkmCyHiRTqjYfyUJiXtbVNURhv0/Q1TyRhy2d5ic0= k8s.io/kubernetes v1.13.0/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk= @@ -1477,8 +1479,8 @@ k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/l k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.14/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg= -sigs.k8s.io/cluster-api v1.2.7 h1:LjdToomKcAaOh71b2TSKbOucZgkw6NQhwiVaGuidI6E= -sigs.k8s.io/cluster-api v1.2.7/go.mod h1:qLMSP/QUb0zwBXoXo2MmzV+YLyNQBkK7OwYEUDOQyQA= +sigs.k8s.io/cluster-api v1.2.8 h1:O0ZGyxGBeJaSWVptM7U0vTArAVlxCE5OtQItZ4OS2Y4= +sigs.k8s.io/cluster-api v1.2.8/go.mod h1:HmxYwjLGHia5yjFoMY8I03Ha4kXAB+VTJnHFhAmPVig= sigs.k8s.io/controller-runtime v0.13.1 h1:tUsRCSJVM1QQOOeViGeX3GMT3dQF1eePPw6sEE3xSlg= sigs.k8s.io/controller-runtime v0.13.1/go.mod h1:Zbz+el8Yg31jubvAEyglRZGdLAjplZl+PgtYNI6WNTI= sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY= diff --git a/pkg/carvelhelpers/fetcher.go b/pkg/carvelhelpers/fetcher.go index 1039e5886..bac155978 100644 --- a/pkg/carvelhelpers/fetcher.go +++ b/pkg/carvelhelpers/fetcher.go @@ -47,6 +47,22 @@ func DownloadImageBundleAndSaveFilesToTempDir(imageWithTag string) (string, erro return tmpDir, nil } +// DownloadDBImage reads a plain OCI image and saves its +// files to the specified location. +func DownloadDBImage(imageWithTag, destinationDir string) error { + reg, err := newRegistry() + if err != nil { + return errors.Wrapf(err, "unable to initialize registry") + } + + err = reg.DownloadImage(imageWithTag, destinationDir) + if err != nil { + return errors.Wrap(err, "error downloading image") + } + + return nil +} + // newRegistry returns a new registry object by also // taking into account for any custom registry or proxy // environment variable provided by the user diff --git a/pkg/discovery/discoverybackend.go b/pkg/discovery/discoverybackend.go new file mode 100644 index 000000000..03179f064 --- /dev/null +++ b/pkg/discovery/discoverybackend.go @@ -0,0 +1,10 @@ +// Copyright 2023 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package discovery + +// DiscoveryBackend is the interface to extract plugin information from +// a backend used for plugin discovery. +type DiscoveryBackend interface { + GetAllPlugins() ([]*Discovered, error) +} diff --git a/pkg/discovery/oci.go b/pkg/discovery/oci.go index ffa56a020..560c90742 100644 --- a/pkg/discovery/oci.go +++ b/pkg/discovery/oci.go @@ -12,6 +12,8 @@ import ( cliv1alpha1 "github.com/vmware-tanzu/tanzu-cli/apis/cli/v1alpha1" "github.com/vmware-tanzu/tanzu-cli/pkg/carvelhelpers" "github.com/vmware-tanzu/tanzu-cli/pkg/common" + "github.com/vmware-tanzu/tanzu-cli/pkg/constants" + "github.com/vmware-tanzu/tanzu-plugin-runtime/config" ) // OCIDiscovery is an artifact discovery endpoint utilizing OCI image @@ -26,8 +28,15 @@ type OCIDiscovery struct { image string } -// NewOCIDiscovery returns a new local repository. +// NewOCIDiscovery returns a new Discovery using the specified OCI image. func NewOCIDiscovery(name, image string) Discovery { + if config.IsFeatureActivated(constants.FeatureCentralRepository) { + return &DBBackedOCIDiscovery{ + name: name, + image: image, + } + } + return &OCIDiscovery{ name: name, image: image, diff --git a/pkg/discovery/oci_dbbacked.go b/pkg/discovery/oci_dbbacked.go new file mode 100644 index 000000000..81c3df403 --- /dev/null +++ b/pkg/discovery/oci_dbbacked.go @@ -0,0 +1,82 @@ +// Copyright 2023 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package discovery + +import ( + "path" + "path/filepath" + + "github.com/pkg/errors" + + "github.com/vmware-tanzu/tanzu-cli/pkg/carvelhelpers" + "github.com/vmware-tanzu/tanzu-cli/pkg/common" +) + +// inventoryDirName is the name of the directory where the file(s) describing +// the inventory of the discovery will be downloaded and stored. +// It should be a sub-directory of the cache directory. +const inventoryDirName = "plugin_inventory" + +// DBBackedOCIDiscovery is an artifact discovery utilizing an OCI image +// which contains an SQLite database describing the content of the plugin +// discovery. +type DBBackedOCIDiscovery struct { + // name is the name given to the discovery + name string + // image is an OCI compliant image. Which include DNS-compatible registry name, + // a valid URI path (MAY contain zero or more ‘/’) and a valid tag + // E.g., harbor.my-domain.local/tanzu-cli/plugins/plugins-inventory:latest + // This image contains a single SQLite database file. + image string +} + +// Name of the discovery. +func (od *DBBackedOCIDiscovery) Name() string { + return od.name +} + +// Type of the discovery. +func (od *DBBackedOCIDiscovery) Type() string { + return common.DiscoveryTypeOCI +} + +// List available plugins. +func (od *DBBackedOCIDiscovery) List() (plugins []Discovered, err error) { + pluginInventoryDir, err := od.fetchInventoryImage() + if err != nil { + return nil, errors.Wrapf(err, "unable to fetch the inventory of discovery '%s'", od.Name()) + } + + // The plugin inventory uses relative image URIs to be future-proof. + // Determine the image prefix from the main image. + // E.g., if the main image is at project.registry.vmware.com/tanzu-cli/plugins/plugin-inventory:latest + // then the image prefix should be project.registry.vmware.com/tanzu-cli/plugins/ + imagePrefix := path.Dir(od.image) + backend := NewSQLiteBackend(od.Name(), pluginInventoryDir, imagePrefix) + + allPluginPtrs, err := backend.GetAllPlugins() + if err != nil { + return nil, err + } + + // Convert from plugin pointers to plugins + // TODO(khouzam): continue optimizing by converting every call to using pointers + var allPlugins []Discovered + for _, pluginPtr := range allPluginPtrs { + allPlugins = append(allPlugins, *pluginPtr) + } + return allPlugins, nil +} + +// fetchInventoryImage downloads the OCI image containing the information about the +// inventory of this discovery and stores it in the cache directory. +// It returns the path to the exact directory used. +func (od *DBBackedOCIDiscovery) fetchInventoryImage() (string, error) { + // TODO(khouzam): Improve by checking if we really need to download again or if we can use the cache + pluginDataDir := filepath.Join(common.DefaultCacheDir, inventoryDirName) + if err := carvelhelpers.DownloadDBImage(od.image, pluginDataDir); err != nil { + return "", errors.Wrapf(err, "failed to download OCI image from discovery '%s'", od.Name()) + } + return pluginDataDir, nil +} diff --git a/pkg/discovery/sqlite_backend.go b/pkg/discovery/sqlite_backend.go new file mode 100644 index 000000000..df2fe84f8 --- /dev/null +++ b/pkg/discovery/sqlite_backend.go @@ -0,0 +1,221 @@ +// Copyright 2023 VMware, Inc. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package discovery + +import ( + "database/sql" + "fmt" + "os" + "path/filepath" + "strings" + + // Import the sqlite3 driver + _ "github.com/mattn/go-sqlite3" + + "github.com/pkg/errors" + + "github.com/vmware-tanzu/tanzu-cli/pkg/catalog" + "github.com/vmware-tanzu/tanzu-cli/pkg/common" + "github.com/vmware-tanzu/tanzu-cli/pkg/distribution" + configtypes "github.com/vmware-tanzu/tanzu-plugin-runtime/config/types" +) + +// SQLiteBackend is a backend using SQLite for managing the data for the +// inventory of plugins. +type SQLiteBackend struct { + // discoveryName is the name of the discovery powered by this backend + discoveryName string + // inventoryFile represents the full path to the SQLite DB file + inventoryFile string + // uriPrefix is the prefix that must be added to the extracted URIs. + // To be future-proof the DB stores image URIs that are relative to + // the inventory location. + uriPrefix string +} + +const ( + // sqliteDBFileName is the name of the DB file that is stored in + // the OCI image describing the inventory of plugins. + sqliteDBFileName = "plugin_inventory.db" +) + +// Structure of each row of the SQLite database +type inventoryDBRow struct { + name string + target string + recommendedVersion string + version string + hidden string + description string + publisher string + vendor string + os string + arch string + digest string + uri string +} + +// NewSQLiteBackend returns a new DiscoveryBackend using the data found at 'inventoryDir'. +func NewSQLiteBackend(discoveryName, inventoryDir, prefix string) DiscoveryBackend { + return &SQLiteBackend{ + discoveryName: discoveryName, + inventoryFile: filepath.Join(inventoryDir, sqliteDBFileName), + uriPrefix: prefix, + } +} + +// GetAllPlugins returns all plugins discovered in this backend. +func (b *SQLiteBackend) GetAllPlugins() ([]*Discovered, error) { + return b.getPluginsFromDB() +} + +// getPluginsFromDB returns all plugins found in the DB 'inventoryFile' +func (b *SQLiteBackend) getPluginsFromDB() ([]*Discovered, error) { + db, err := sql.Open("sqlite3", b.inventoryFile) + if err != nil { + return nil, errors.Wrapf(err, "failed to open the DB for discovery '%s'", b.discoveryName) + } + defer db.Close() + + // We need to order the results properly because the logic of extractPluginsFromRows() + // expects an ordering of PluginName, then Target, then Version. + // The column order must also match the order used in getNextRow(). + dbQuery := "SELECT PluginName,Target,RecommendedVersion,Version,Hidden,Description,Publisher,Vendor,OS,Architecture,Digest,URI FROM PluginBinaries ORDER BY PluginName,Target,Version;" + rows, err := db.Query(dbQuery) + if err != nil { + return nil, errors.Wrapf(err, "unable to setup DB query for discovery '%s'", b.discoveryName) + } + defer rows.Close() + + return b.extractPluginsFromRows(rows) +} + +// extractPluginsFromRows loops through all DB rows and builds an array +// of Discovered plugins based on the data extracted. +func (b *SQLiteBackend) extractPluginsFromRows(rows *sql.Rows) ([]*Discovered, error) { + currentPluginID := "" + currentVersion := "" + var currentPlugin *Discovered + allPlugins := make([]*Discovered, 0) + var artifactList distribution.ArtifactList + var artifacts distribution.Artifacts + + for rows.Next() { + row, err := getNextRow(rows) + if err != nil { + return allPlugins, err + } + + target := convertTargetFromDB(row.target) + pluginIDFromRow := catalog.PluginNameTarget(row.name, target) + if currentPluginID != pluginIDFromRow { + // Found a new plugin. + // Store the current one in the array and prepare the new one. + if currentPlugin != nil { + artifacts[currentVersion] = artifactList + artifactList = distribution.ArtifactList{} + currentPlugin.Distribution = artifacts + allPlugins = appendPlugin(allPlugins, currentPlugin) + } + currentPluginID = pluginIDFromRow + + currentPlugin = &Discovered{ + Name: row.name, + Description: row.description, + RecommendedVersion: row.recommendedVersion, + InstalledVersion: "", // Not set when discovered, but later. + SupportedVersions: []string{}, // Will be filled gradually below. + Optional: false, + Scope: common.PluginScopeStandalone, + Source: b.discoveryName, + ContextName: "", // Not set when discovered by this backend. + DiscoveryType: common.DiscoveryTypeOCI, + Target: target, + Status: common.PluginStatusNotInstalled, + } + currentVersion = "" + artifacts = distribution.Artifacts{} + } + + // Check if we have a new version + if currentVersion != row.version { + // This is a new version of our current plugin. Add it to the array of versions. + // We can do this without verifying if the version is already there because + // we have requested the list of plugins from the database ordered by version. + currentPlugin.SupportedVersions = append(currentPlugin.SupportedVersions, row.version) + + // Store the list of artifacts for the previous version then start building + // the artifact list for the new version. + if currentVersion != "" { + artifacts[currentVersion] = artifactList + artifactList = distribution.ArtifactList{} + } + currentVersion = row.version + } + + // The DB uses relative URIs to be future-proof. + // Build the full URI before creating the artifact. + fullImagePath := fmt.Sprintf("%s/%s", b.uriPrefix, row.uri) + // Create the artifact for this row. + artifact := distribution.Artifact{ + Image: fullImagePath, + URI: "", + Digest: row.digest, + OS: row.os, + Arch: row.arch, + } + artifactList = append(artifactList, artifact) + } + // Don't forget to store the very last plugin we were building + artifacts[currentVersion] = artifactList + currentPlugin.Distribution = artifacts + allPlugins = appendPlugin(allPlugins, currentPlugin) + return allPlugins, rows.Err() +} + +// getNextRow simply extracts the next row of data from the DB. +func getNextRow(rows *sql.Rows) (*inventoryDBRow, error) { + var row inventoryDBRow + // The order of the fields MUST match the order specified in the + // SELECT query that generated the rows. + err := rows.Scan( + &row.name, + &row.target, + &row.recommendedVersion, + &row.version, + &row.hidden, + &row.description, + &row.publisher, + &row.vendor, + &row.os, + &row.arch, + &row.digest, + &row.uri, + ) + return &row, err +} + +func convertTargetFromDB(target string) configtypes.Target { + target = strings.ToLower(target) + if target == "global" { + target = "" + } + return configtypes.StringToTarget(target) +} + +// appendPlugin appends a Discovered plugins to the specified array. +// This function needs to be used to do post-processing on the new plugin before storing it. +func appendPlugin(allPlugins []*Discovered, plugin *Discovered) []*Discovered { + // Now that we are done gathering the information for the plugin + // we need to compute the recommendedVersion if it wasn't provided + // by the database + if err := SortVersions(plugin.SupportedVersions); err != nil { + fmt.Fprintf(os.Stderr, "error parsing supported versions for plugin %s: %v", plugin.Name, err) + } + if plugin.RecommendedVersion == "" { + plugin.RecommendedVersion = plugin.SupportedVersions[len(plugin.SupportedVersions)-1] + } + allPlugins = append(allPlugins, plugin) + return allPlugins +} diff --git a/pkg/fakes/registy.go b/pkg/fakes/registy.go index be9189428..43b9c00f5 100644 --- a/pkg/fakes/registy.go +++ b/pkg/fakes/registy.go @@ -20,6 +20,18 @@ type Registry struct { downloadBundleReturnsOnCall map[int]struct { result1 error } + DownloadImageStub func(string, string) error + downloadImageMutex sync.RWMutex + downloadImageArgsForCall []struct { + arg1 string + arg2 string + } + downloadImageReturns struct { + result1 error + } + downloadImageReturnsOnCall map[int]struct { + result1 error + } GetFileStub func(string, string) ([]byte, error) getFileMutex sync.RWMutex getFileArgsForCall []struct { @@ -126,6 +138,68 @@ func (fake *Registry) DownloadBundleReturnsOnCall(i int, result1 error) { }{result1} } +func (fake *Registry) DownloadImage(arg1 string, arg2 string) error { + fake.downloadImageMutex.Lock() + ret, specificReturn := fake.downloadImageReturnsOnCall[len(fake.downloadImageArgsForCall)] + fake.downloadImageArgsForCall = append(fake.downloadImageArgsForCall, struct { + arg1 string + arg2 string + }{arg1, arg2}) + stub := fake.DownloadImageStub + fakeReturns := fake.downloadImageReturns + fake.recordInvocation("DownloadImage", []interface{}{arg1, arg2}) + fake.downloadImageMutex.Unlock() + if stub != nil { + return stub(arg1, arg2) + } + if specificReturn { + return ret.result1 + } + return fakeReturns.result1 +} + +func (fake *Registry) DownloadImageCallCount() int { + fake.downloadImageMutex.RLock() + defer fake.downloadImageMutex.RUnlock() + return len(fake.downloadImageArgsForCall) +} + +func (fake *Registry) DownloadImageCalls(stub func(string, string) error) { + fake.downloadImageMutex.Lock() + defer fake.downloadImageMutex.Unlock() + fake.DownloadImageStub = stub +} + +func (fake *Registry) DownloadImageArgsForCall(i int) (string, string) { + fake.downloadImageMutex.RLock() + defer fake.downloadImageMutex.RUnlock() + argsForCall := fake.downloadImageArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2 +} + +func (fake *Registry) DownloadImageReturns(result1 error) { + fake.downloadImageMutex.Lock() + defer fake.downloadImageMutex.Unlock() + fake.DownloadImageStub = nil + fake.downloadImageReturns = struct { + result1 error + }{result1} +} + +func (fake *Registry) DownloadImageReturnsOnCall(i int, result1 error) { + fake.downloadImageMutex.Lock() + defer fake.downloadImageMutex.Unlock() + fake.DownloadImageStub = nil + if fake.downloadImageReturnsOnCall == nil { + fake.downloadImageReturnsOnCall = make(map[int]struct { + result1 error + }) + } + fake.downloadImageReturnsOnCall[i] = struct { + result1 error + }{result1} +} + func (fake *Registry) GetFile(arg1 string, arg2 string) ([]byte, error) { fake.getFileMutex.Lock() ret, specificReturn := fake.getFileReturnsOnCall[len(fake.getFileArgsForCall)] @@ -324,6 +398,8 @@ func (fake *Registry) Invocations() map[string][][]interface{} { defer fake.invocationsMutex.RUnlock() fake.downloadBundleMutex.RLock() defer fake.downloadBundleMutex.RUnlock() + fake.downloadImageMutex.RLock() + defer fake.downloadImageMutex.RUnlock() fake.getFileMutex.RLock() defer fake.getFileMutex.RUnlock() fake.getFilesMutex.RLock() diff --git a/pkg/pluginmanager/manager.go b/pkg/pluginmanager/manager.go index 5ded0d2b7..7db600b96 100644 --- a/pkg/pluginmanager/manager.go +++ b/pkg/pluginmanager/manager.go @@ -447,9 +447,19 @@ func InitializePlugin(plugin *cli.PluginInfo) error { return nil } -// InstallPlugin installs a plugin from the given repository. +// InstallPlugin installs a plugin by name, version and target. func InstallPlugin(pluginName, version string, target configtypes.Target) error { - availablePlugins, err := AvailablePlugins() + var availablePlugins []discovery.Discovered + var err error + if configlib.IsFeatureActivated(constants.FeatureCentralRepository) { + availablePlugins, err = DiscoverStandalonePlugins() + if installedPlugins, err := pluginsupplier.GetInstalledPlugins(); err == nil { + setAvailablePluginsStatus(availablePlugins, installedPlugins) + } + } else { + availablePlugins, err = AvailablePlugins() + } + if err != nil { return err } @@ -681,10 +691,28 @@ func DeletePlugin(options DeletePluginOptions) error { return nil } -// SyncPlugins automatically downloads all available plugins to users machine +// SyncPlugins automatically installs the plugins required by the current contexts. func SyncPlugins() error { log.Info("Checking for required plugins...") - plugins, err := AvailablePlugins() + var plugins []discovery.Discovered + var err error + if configlib.IsFeatureActivated(constants.FeatureCentralRepository) { + // We no longer sync standalone plugins. + // With a centralized approach to discovering plugins, synchronizing + // standalone plugins would install ALL plugins available for ALL + // products. + // Instead, we only synchronize any plugins that are specifically specified + // by the contexts. + // + // Note: to install all plugins for a specific product, plugin groups will + // need to be used. + plugins, err = DiscoverServerPlugins() + if installedPlugins, err := pluginsupplier.GetInstalledServerPlugins(); err == nil { + setAvailablePluginsStatus(plugins, installedPlugins) + } + } else { + plugins, err = AvailablePlugins() + } if err != nil { return err } diff --git a/pkg/registry/client.go b/pkg/registry/client.go index 5ac814d0c..32f877a0c 100644 --- a/pkg/registry/client.go +++ b/pkg/registry/client.go @@ -153,15 +153,23 @@ func getAllFilesContentFromImage(image regv1.Image) (map[string][]byte, error) { // DownloadBundle downloads OCI bundle similar to `imgpkg pull -b` command // It is recommended to use this function when downloading imgpkg bundle because -// - During the air-gapped script, these plugin discovery packages are copied to a -// private registry with the `imgpkg copy` command -// - Downloading files directly from OCI image similar to `GetFiles` doesn't work -// because it doesn't update the `ImageLock` file when we download the package from -// different registry. And returns original ImageLock file. and as ImageLock file -// is pointing to original registry instead of private registry, image references -// does not point to the correct location - +// - During the air-gapped script, these plugin discovery packages are copied to a +// private registry with the `imgpkg copy` command +// - Downloading files directly from OCI image similar to `GetFiles` doesn't work +// because it doesn't update the `ImageLock` file when we download the package from +// different registry. And returns original ImageLock file. and as ImageLock file +// is pointing to original registry instead of private registry, image references +// does not point to the correct location func (r *registry) DownloadBundle(imageName, outputDir string) error { + return r.downloadBundleOrImage(imageName, outputDir, true) +} + +// DownloadImage downloads an OCI image similarly to the `imgpkg pull -i` command +func (r *registry) DownloadImage(imageName, outputDir string) error { + return r.downloadBundleOrImage(imageName, outputDir, false) +} + +func (r *registry) downloadBundleOrImage(imageName, outputDir string, isBundle bool) error { // Creating a dummy writer to capture the logs // currently this logs are not displayed or used directly var outputBuf, errorBuf bytes.Buffer @@ -169,8 +177,11 @@ func (r *registry) DownloadBundle(imageName, outputDir string) error { pullOptions := cmd.NewPullOptions(writerUI) pullOptions.OutputPath = outputDir - pullOptions.BundleFlags = cmd.BundleFlags{Bundle: imageName} - + if isBundle { + pullOptions.BundleFlags = cmd.BundleFlags{Bundle: imageName} + } else { + pullOptions.ImageFlags = cmd.ImageFlags{Image: imageName} + } if r.opts != nil { pullOptions.RegistryFlags = cmd.RegistryFlags{ CACertPaths: r.opts.CACertPaths, diff --git a/pkg/registry/interface.go b/pkg/registry/interface.go index 122e59600..ecef47a87 100644 --- a/pkg/registry/interface.go +++ b/pkg/registry/interface.go @@ -17,4 +17,6 @@ type Registry interface { // DownloadBundle downloads OCI bundle similar to `imgpkg pull -b` command // It is recommended to use this function when downloading imgpkg bundle DownloadBundle(imageName, outputDir string) error + // DownloadImage downloads an OCI image similarly to the `imgpkg pull -i` command + DownloadImage(imageName, outputDir string) error }